मैं किसी विशेष सूचकांक का उपयोग करने के लिए Postgres को कैसे मजबूर करूं?


112

जब मैं किसी अनुक्रमणिका स्कैन को करने पर जोर देता हूं तो मैं अनुक्रमणिका का उपयोग करने के लिए कैसे बाध्य करता हूं?



1
+1 यह सुविधा देखना मुझे अच्छा लगेगा। यह केवल सीक स्कैन को अक्षम करने का मामला नहीं है, क्योंकि अन्य उत्तर कहते हैं: हमें पीजी को एक विशिष्ट सूचकांक का उपयोग करने के लिए मजबूर करने की क्षमता की आवश्यकता है । ऐसा इसलिए है क्योंकि वास्तविक शब्द आँकड़े पूरी तरह से गलत हो सकते हैं और उस बिंदु पर आपको अविश्वसनीय / आंशिक वर्कअराउंड का उपयोग करने की आवश्यकता होती है। मैं मानता हूं कि साधारण मामलों में आपको सबसे पहले इंडेक्स और अन्य सेटिंग्स की जांच करनी चाहिए, लेकिन बड़े डेटा पर विश्वसनीयता और उन्नत उपयोग के लिए हमें इसकी आवश्यकता है।
Collimarco

MySQL और Oracle दोनों में यह है ... निश्चित नहीं कि Postgres 'योजनाकार इतना अविश्वसनीय क्यों है।
केविन पार्कर

जवाबों:


103

यह मानते हुए कि आप कई डेटाबेस में पाए जाने वाले सामान्य "इंडेक्स हिंटिंग" फीचर के बारे में पूछ रहे हैं, PostgreSQL इस तरह की सुविधा प्रदान नहीं करता है। यह PostgreSQL टीम द्वारा किया गया एक सचेत निर्णय था। इसके बजाय आप क्यों और क्या कर सकते हैं, का एक अच्छा अवलोकन यहां पाया जा सकता है । मूल रूप से कारण यह है कि यह एक प्रदर्शन हैक है जो बाद में आपके डेटा में परिवर्तन के रूप में लाइन के नीचे और अधिक समस्याएं पैदा करता है, जबकि पोस्टग्रेजक्यूएल के आशावादी आंकड़ों के आधार पर योजना का पुनर्मूल्यांकन कर सकते हैं। दूसरे शब्दों में, आज एक अच्छी क्वेरी योजना क्या हो सकती है, शायद सभी समय के लिए एक अच्छी क्वेरी योजना नहीं होगी, और सूचकांक संकेत किसी विशेष क्वेरी योजना को हर समय के लिए मजबूर करते हैं।

एक बहुत ही कुंद हथौड़ा के रूप में, परीक्षण के लिए उपयोगी, आप enable_seqscanऔर enable_indexscanमापदंडों का उपयोग कर सकते हैं । देख:

ये चल रहे उत्पादन उपयोग के लिए उपयुक्त नहीं हैं । यदि आपके पास क्वेरी योजना पसंद के साथ समस्याएँ हैं, तो आपको क्वेरी प्रदर्शन समस्याओं को ट्रैक करने के लिए दस्तावेज़ देखना चाहिए । सिर्फ enable_परम सेट न करें और दूर चलें।

जब तक आपके पास सूचकांक का उपयोग करने का एक बहुत अच्छा कारण नहीं है, तब तक Postgres सही विकल्प बना सकता है। क्यों?

  • छोटी तालिकाओं के लिए, यह अनुक्रमिक स्कैन करने के लिए तेज़ है।
  • जब डेटाटाइप ठीक से मेल नहीं खाता है, तो पोस्टग्रेसेज इंडेक्स का उपयोग नहीं करते हैं, आपको उपयुक्त कास्ट को शामिल करने की आवश्यकता हो सकती है।
  • आपकी योजनाकार सेटिंग्स समस्याएँ पैदा कर सकती हैं।

इस पुरानी न्यूज़ग्रुप पोस्ट को भी देखें ।


4
सहमत, मजबूरन इसे अपने तरीके से करने के लिए आमतौर पर इसका मतलब है कि आपने इसे गलत किया है। 9/10 टाइम्स योजनाकार आपके साथ आ सकने वाली किसी भी चीज़ को हरा देगा। अन्य 1 बार इसकी वजह से आपने इसे गलत बनाया।
केंट फ्रेड्रिक

मुझे लगता है कि यह वास्तव में आपके इंडेक्स होल्ड के ऑपरेटर वर्गों की जांच करने के लिए एक अच्छा विचार है।
मेट्सोस

2
मैं एक पुराने प्रश्न को पुनर्जीवित करने से नफरत करता हूं, लेकिन मैं अक्सर पोस्टग्रेज डॉक्यूमेंटेशन, चर्चाओं और यहां देखता हूं, लेकिन क्या एक सामान्यीकृत अवधारणा है कि एक छोटी मेज के लिए क्या योग्यता है ? क्या यह कुछ 5000 पंक्तियों, या 50000 आदि की तरह है?
वाफेल

1
@waffl क्या आपने बेंचमार्किंग पर विचार किया है? एक रैंडम के साथ एक साधारण टेबल बनाएं और रैंडम जंक की n पंक्तियों के साथ इसे भरने के लिए एक साथ काम करें । फिर n के विभिन्न मूल्यों के लिए क्वेरी योजना को देखना शुरू करें । जब आप देखते हैं कि यह सूचकांक का उपयोग करना शुरू कर देता है, तो आपके पास एक बॉलपार्क उत्तर होना चाहिए। यदि आप PostgreSQL का निर्धारण (आँकड़ों के आधार पर) करते हैं तो आप अनुक्रमिक स्कैन भी प्राप्त कर सकते हैं, जो एक इंडेक्स स्कैन बहुत अधिक पंक्तियों को भी समाप्त करने वाला नहीं है। जब आप वास्तविक प्रदर्शन की चिंता करते हैं तो बेंचमार्किंग हमेशा एक अच्छा विचार है। एक ऑफ-हैंड, वास्तविक अनुमान के रूप में, मैं कहूंगा कि एक जोड़े को आमतौर पर "छोटा" होता है।
jpmc26

11
ओरेकल, टेराडाटा और MSSQL जैसे प्लेटफार्मों पर 30 से अधिक वर्षों के अनुभव के साथ, मुझे विशेष रूप से स्मार्ट पोस्टग्रेक्यूएल 10 के ऑप्टिमाइज़र मिलते हैं। अप-टू-डेट आंकड़ों के साथ भी यह एक विशेष दिशा में मजबूर करने की तुलना में कम कुशल निष्पादन योजनाएं बनाता है। इन मुद्दों की भरपाई के लिए संरचनात्मक संकेत प्रदान करने से पोस्टग्रेसीक्यू को अधिक बाजार क्षेत्रों में बढ़ने की अनुमति देने के लिए एक समाधान मिलेगा। IMHO।
गुइडो लेन्डर्स

75

संभवतः उपयोग करने का एकमात्र मान्य कारण है

set enable_seqscan=false

जब आप प्रश्न लिख रहे हैं और जल्दी से देखना चाहते हैं कि क्वेरी प्लान वास्तव में क्या होगा तो तालिका में बड़ी मात्रा में डेटा थे। या निश्चित रूप से अगर आपको यह जल्दी से पुष्टि करने की आवश्यकता है कि आपकी क्वेरी केवल एक इंडेक्स का उपयोग नहीं कर रही है क्योंकि डेटासेट बहुत छोटा है।


41
यह संक्षिप्त उत्तर वास्तव में परीक्षण के उद्देश्यों के लिए एक अच्छा संकेत देता है
dwery

3
कोई भी सवाल का जवाब नहीं दे रहा है!
इवैलो बार्डारोव

@IvailoBardarov इन सभी अन्य सुझावों का कारण यहाँ है क्योंकि PostgreSQL में यह सुविधा नहीं है; यह डेवलपर्स द्वारा किया गया एक सचेत निर्णय था जो आमतौर पर इसका उपयोग करने और इसके कारण दीर्घकालिक समस्याओं के आधार पर किया जाता था।
jpmc26

परीक्षण करने के लिए एक अच्छी चाल: दौड़ें set enable_seqscan=false, अपनी क्वेरी चलाएँ, और फिर जल्दी set enable_seqscan=trueसे अपने उचित व्यवहार के लिए पोस्टग्रैस्कल वापस करने के लिए दौड़ें (और स्पष्ट रूप से उत्पादन में ऐसा नहीं करते हैं, केवल विकास में!)
ब्रायन हेल्लेकिन

2
@BrianHellekin बेहतर, SET SESSION enable_seqscan=falseकेवल अपने आप को प्रभावित करने के लिए
इज़्काता

20

कभी-कभी PostgreSQL किसी विशेष स्थिति के लिए अनुक्रमित का सबसे अच्छा विकल्प बनाने में विफल रहता है। एक उदाहरण के रूप में, मान लें कि कई मिलियन पंक्तियों के साथ एक लेन-देन तालिका है, जिनमें से किसी भी दिन के लिए कई सौ हैं, और तालिका में चार अनुक्रमणिकाएँ हैं: transaction_id, client_id, date और विवरण। आप निम्नलिखित क्वेरी चलाना चाहते हैं:

SELECT client_id, SUM(amount)
FROM transactions
WHERE date >= 'yesterday'::timestamp AND date < 'today'::timestamp AND
      description = 'Refund'
GROUP BY client_id

PostgreSQL लेनदेन के बजाय index_description_idx का उपयोग करने का विकल्प चुन सकता है_date_idx, जो क्वेरी को एक मिनट से कम के बजाय कई मिनट ले सकता है। यदि यह मामला है, तो आप इस तरह की स्थिति को ध्यान में रखते हुए सूचकांक पर तारीख का उपयोग करने के लिए मजबूर कर सकते हैं:

SELECT client_id, SUM(amount)
FROM transactions
WHERE date >= 'yesterday'::timestamp AND date < 'today'::timestamp AND
      description||'' = 'Refund'
GROUP BY client_id

3
अछा सुझाव। हालाँकि, जब हम इस विधि के साथ वर्तमान अनुक्रमणिका उपयोग को अक्षम करते हैं - अगले उपयुक्त अनुक्रमणिका के लिए क्वेरी ऑप्टिमाइज़र कमियां पोस्टग्रेजेकल। इस प्रकार, कोई गारंटी नहीं है कि ऑप्टिमाइज़र चुन लेगा your_wanted_index, यह इतना हो सकता है कि पोस्टग्रैक्कल इंजन सिर्फ एक अनुक्रम / प्राथमिक कुंजी स्कैन के बजाय प्रदर्शन करेगा। निष्कर्ष - PostgreSql सर्वर के लिए कुछ इंडेक्स उपयोग को बाध्य करने के लिए कोई 100% विश्वसनीय तरीका नहीं है।
अग्निस वसीलियास्कस

क्या होगा अगर कोई whereस्थिति नहीं है, लेकिन दो टेबल या शामिल हो गए हैं और पोस्टग्रैज इंडेक्स लेने में विफल हैं।
लूना लवगूड

@ सूर्या ऊपर और जोइन दोनों पर लागू होता है ... शर्तों पर
जिग्गी क्रुएल्टीफ्री ज़ेतिगेस्टर

18

संक्षिप्त जवाब

यह समस्या आमतौर पर तब होती है जब एक सूचकांक स्कैन की अनुमानित लागत बहुत अधिक होती है और वास्तविकता को सही ढंग से प्रतिबिंबित नहीं करती है। random_page_costइसे ठीक करने के लिए आपको कॉन्फ़िगरेशन पैरामीटर को कम करना पड़ सकता है । से Postgres प्रलेखन :

इस मान को कम करना [...] इस प्रणाली के कारण सूचकांक स्कैन को प्राथमिकता देगा; इसे बढ़ाने से इंडेक्स स्कैन अपेक्षाकृत अधिक महंगे लगेंगे।

आप जांच सकते हैं कि क्या कम मूल्य वास्तव में Postgres सूचकांक का उपयोग करेगा (लेकिन केवल परीक्षण के लिए इसका उपयोग करें ):

EXPLAIN <query>;              # Uses sequential scan
SET random_page_cost = 1;
EXPLAIN <query>;              # May use index scan now

आप SET random_page_cost = DEFAULT;फिर से डिफ़ॉल्ट मान को पुनर्स्थापित कर सकते हैं ।

पृष्ठभूमि

सूचकांक स्कैन के लिए गैर-अनुक्रमिक डिस्क पेज लाने की आवश्यकता होती है। random_page_costअनुक्रमिक भ्रूणों के संबंध में ऐसे गैर-अनुक्रमिक भ्रूणों की लागत का अनुमान लगाने के लिए पोस्टग्रेज का उपयोग करता है। डिफ़ॉल्ट मूल्य है 4.0, इस प्रकार अनुक्रमिक भ्रूण (खाते में कैशिंग प्रभाव को ध्यान में रखते हुए) की तुलना में 4 का औसत लागत कारक माना जाता है ।

समस्या यह है कि यह डिफ़ॉल्ट मान निम्न महत्वपूर्ण वास्तविक जीवन परिदृश्यों में अनुपयुक्त है:

1) सॉलिड-स्टेट ड्राइव

जैसा कि प्रलेखन स्वीकार करता है:

भंडारण जो अनुक्रमिक, जैसे ठोस-राज्य ड्राइव के सापेक्ष कम यादृच्छिक रीड कॉस्ट है, के लिए कम मूल्य के साथ बेहतर मॉडलिंग की जा सकती है random_page_cost

PostgresConf 2018 में एक भाषण से इस स्लाइड के अंतिम बिंदु के अनुसार , ठोस राज्य ड्राइव के random_page_costबीच 1.0और कुछ के लिए सेट किया जाना चाहिए 2.0

2) कैश्ड डेटा

यदि आवश्यक इंडेक्स डेटा पहले से ही रैम में कैश्ड है, तो एक इंडेक्स स्कैन हमेशा अनुक्रमिक स्कैन की तुलना में काफी तेज होगा। प्रलेखन कहता है:

इसके विपरीत, यदि आपका डेटा पूरी तरह से कैश में होने की संभावना है, [...] घटाना random_page_costउचित हो सकता है।

समस्या यह है कि आप निश्चित रूप से आसानी से नहीं जान सकते कि संबंधित डेटा पहले से कैश है या नहीं। हालांकि, यदि कोई विशिष्ट इंडेक्स अक्सर क्वेर होता है, और यदि सिस्टम में पर्याप्त रैम है, तो डेटा कैश्ड होने की संभावना है, और random_page_costइसे कम मूल्य पर सेट किया जाना चाहिए। आपको विभिन्न मूल्यों के साथ प्रयोग करना होगा और देखना होगा कि आपके लिए क्या काम करता है।

आप स्पष्ट डेटा कैशिंग के लिए pg_prewarm एक्सटेंशन का उपयोग करना चाह सकते हैं ।



2
यहां तक ​​कि मुझे Ubuntu पर पृष्ठ 10.1 में बड़े (~ 600M पंक्तियों की तालिका) पर सूचकांक स्कैन का काम करने के लिए random_page_cost = 0.1 सेट करना पड़ा। ट्वीक के बिना, seq स्कैन (समानांतर होने के बावजूद) 12 मिनट ले रहा था (ध्यान दें कि एनालिसिस टेबल का प्रदर्शन किया गया था!)। ड्राइव एसएसडी है। ट्विक के बाद, निष्पादन समय 1 सेकंड हो गया।
अनातोली अलेक्सेव

आपने मेरा दिन बचाया। मैं यह जानने की कोशिश कर रहा था कि एक ही डेटाबेस पर सटीक एक ही क्वेरी एक मशीन पर 30 सेकंड और दूसरे पर 1 से कम कैसे ले रही है, दोनों सिरों पर विश्लेषण चलाने के बाद भी ... किसके लिए यह चिंता का विषय हो सकता है: कमांड ' ALTER SYSTEM SET random_page_cost = x 'वैश्विक रूप से नया डिफ़ॉल्ट मान सेट करता है।
जूलियन

10

स्वयं पर प्रश्न बहुत अमान्य है। मजबूर करना (उदाहरण के लिए enable_seqscan = off करना) बहुत बुरा विचार है। यह जांचने के लिए उपयोगी हो सकता है कि क्या यह तेज होगा, लेकिन उत्पादन कोड को कभी भी ऐसी चाल का उपयोग नहीं करना चाहिए।

इसके बजाय - अपनी क्वेरी का विश्लेषण करें, इसे पढ़ें, और पता करें कि PostgreSQL खराब (आपकी राय में) योजना क्यों चुनता है।

वेब पर ऐसे उपकरण हैं जो पढ़ने में मदद करने के लिए आउटपुट का विश्लेषण करने में मदद करते हैं - उनमें से एक व्याख्या है ।epesz.com - मेरे द्वारा लिखित।

एक अन्य विकल्प #postgresql चैनल पर जुड़ना है freenode irc नेटवर्क , और वहां के लोगों से बात करके आपकी मदद करना है - जैसा कि क्वेरी को अनुकूलित करना "एक सवाल पूछना, जवाब खुश होना" का मामला नहीं है। यह बातचीत की तरह है, कई चीजों को जांचने के लिए, कई चीजों को सीखने के लिए।


2

वहाँ एक चाल postgres पुश करने के लिए एक seqscan एक जोड़ने पसंद करते हैं करने के लिए है OFFSET 0सबक्वेरी में

यह बड़े / विशाल तालिकाओं को जोड़ने के अनुरोधों के अनुकूलन के लिए आसान है जब आपको केवल आवश्यक पहले / अंतिम तत्वों की आवश्यकता होती है।

कहते हैं कि आप पहले / अंतिम 20 तत्वों की तलाश कर रहे हैं जिसमें 100k (या अधिक) प्रविष्टियां होने वाली कई तालिकाएँ शामिल हैं, कोई बिंदु निर्माण / सभी डेटा पर सभी क्वेरी को जोड़ना जब आप जो देख रहे हैं वह पहले 100 या 1000 में होगा प्रविष्टियों। इस परिदृश्य में उदाहरण के लिए, यह क्रमिक स्कैन करने के लिए 10x से अधिक तेजी से निकलता है।

देखें कि मैं पोस्टग्रेज को एक उपनगरीय इलाके में घुसने से कैसे रोक सकता हूं?


अच्छी चाल। हालांकि एक अच्छा आशावादी को निश्चित रूप से ऑफसेट को दूर करना चाहिए 0 :-)
गुइडो लेन्डर्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.