क्या उस खंड को उस क्रम में लागू किया जाता है जिस क्रम में वे लिखे गए हैं?


36

मैं एक क्वेरी को अनुकूलित करने की कोशिश कर रहा हूं जो एक बड़ी तालिका (37 मिलियन पंक्तियों) में दिखता है और एक प्रश्न है कि किसी क्वेरी में संचालन को किस क्रम में निष्पादित किया जाता है।

select 1 
from workdays day
where day.date_day >= '2014-10-01' 
    and day.date_day <= '2015-09-30' 
    and day.offer_id in (
        select offer.offer_day 
        from offer  
        inner join province on offer.id_province = province.id_province  
        inner join center cr on cr.id_cr = province.id_cr 
        where upper(offer.code_status) <> 'A' 
            and province.id_region in ('10' ,'15' ,'21' ,'26' ,'31' , ...,'557') 
            and province.id_cr in ('9' ,'14' ,'20' ,'25' ,'30' ,'35' ,'37')
    )

क्या WHEREउप-सीमा से पहले निष्पादित की गई तिथि सीमा के खंड हैं? क्या यह एक सबसे अच्छा तरीका है कि सबसे अधिक प्रतिबंधात्मक धाराएं लगाई जाए ताकि अन्य धाराओं के लिए बड़े छोरों से बचा जा सके, ताकि तेजी से निष्पादन हो सके?

अब प्रश्नों को निष्पादित होने में इतना समय लगता है।

जवाबों:


68

@ Alci के उत्तर पर विस्तृत करने के लिए:

PostgreSQL परवाह नहीं करता है कि आप किस क्रम में चीजें लिखते हैं

  • PostgreSQL WHEREक्लाज में प्रविष्टियों के क्रम के बारे में बिल्कुल भी परवाह नहीं करता है , और लागत और अकेले चयन के आधार पर अनुक्रमित और निष्पादन आदेश चुनता है।

  • जिस क्रम में ज्वाइनिंग लिखी जाती है उसे भी कॉन्फ़िगर किए जाने तक अनदेखा किया जाता है join_collapse_limit; अगर वहाँ से अधिक जोड़ रहे हैं, यह उन्हें आदेश में लिखा है कि वे निष्पादित करेंगे।

  • सबक्वेरी को उस क्वेरी से पहले या बाद में निष्पादित किया जा सकता है, जिसमें सबसे तेज़, इतनी देर तक सबकुछ निर्भर करता है, क्योंकि बाहरी क्वेरी वास्तव में जानकारी की आवश्यकता से पहले सबक्वेरी निष्पादित होती है। अक्सर वास्तविकता में उपसमुच्चय को बीच में ही निष्पादित किया जाता है, या बाहरी क्वेरी के साथ इंटरलेय किया जाता है।

  • कोई गारंटी नहीं है कि PostgreSQL वास्तव में क्वेरी के कुछ हिस्सों को निष्पादित करेगा। उन्हें पूरी तरह से अनुकूलित किया जा सकता है। यह महत्वपूर्ण है यदि आप साइड-इफेक्ट्स वाले कार्यों को कहते हैं।

PostgreSQL आपकी क्वेरी को बदल देगा

PostgreSQL परिणामों को परिवर्तित नहीं करते हुए उन्हें तेज गति से चलाने के लिए सटीक समान प्रभावों को बनाए रखते हुए पोस्टग्रेज को भारी रूप से परिवर्तित कर देगा।

  • एक उपमहाद्वीप के बाहर की शर्तों को उपश्रेणी में नीचे धकेला जा सकता है , इसलिए वे उप-भाग के भाग के रूप में निष्पादित होते हैं न कि जहां आपने उन्हें बाहरी प्रश्न में लिखा था

  • उपनगर की शर्तें बाहरी क्वेरी तक खींची जा सकती हैं, इसलिए उनका निष्पादन बाहरी क्वेरी के हिस्से के रूप में किया जाता है, न कि आपने उन्हें उप-केंद्र में लिखा था

  • उपमहाद्वीप, और अक्सर, बाहरी तालिका में शामिल होने के लिए चपटा होता है । जैसा है वैसा ही सच है EXISTSऔरNOT EXISTS जिज्ञासाएं होती ।

  • दृश्य दृश्य का उपयोग करने वाली क्वेरी में चपटा हो जाता है

  • SQL फ़ंक्शन अक्सर कॉलिंग क्वेरी में इनबिल्ड हो जाते हैं

  • ... और प्रश्नों के लिए कई अन्य परिवर्तन किए गए हैं, जैसे निरंतर अभिव्यक्ति पूर्व मूल्यांकन, कुछ उपश्रेणियों का डी-सहसंबंध, और अन्य योजनाकार / अनुकूलक चाल के सभी प्रकार।

सामान्य तौर पर PostgreSQL बड़े पैमाने पर आपकी क्वेरी को बदल सकता है और फिर से लिख सकता है, इस बिंदु पर जहाँ इनमें से प्रत्येक प्रश्न:

select my_table.*
from my_table
left join other_table on (my_table.id = other_table.my_table_id)
where other_table.id is null;

select *
from my_table
where not exists (
  select 1
  from other_table
  where other_table.my_table_id = my_table.id
);

select *
from my_table
where my_table.id not in (
  select my_table_id
  from other_table
  where my_table_id is not null
);

आमतौर पर सभी बिल्कुल एक ही क्वेरी योजना का उत्पादन करेंगे। (यह मानते हुए कि मैंने उपरोक्त किसी भी तरह की गूंगी गलतियों को नहीं किया है)।

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

सीमाएं

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

  • प्लानर द्वारा रखे गए आँकड़ों पर निर्भर करता है ANALYZE(आमतौर पर ऑटोवैक्युम के माध्यम से)। यदि ये पुराने हैं, तो योजना का विकल्प खराब हो सकता है।

  • आंकड़े केवल एक नमूना हैं, इसलिए वे नमूने के प्रभाव के कारण भ्रामक हो सकते हैं, खासकर यदि बहुत छोटा नमूना लिया जाता है। खराब योजना विकल्पों का परिणाम हो सकता है।

  • आंकड़े तालिका के बारे में कुछ प्रकार के डेटा का ट्रैक नहीं रखते हैं, जैसे स्तंभों के बीच संबंध। यह खराब निर्णय लेने के लिए योजनाकार का नेतृत्व कर सकता है जब यह मानता है कि चीजें स्वतंत्र हैं जब वे नहीं हैं।

  • प्लानर लागत मापदंडों पर निर्भर करता है, जैसे random_page_costकि यह उस विशेष सिस्टम पर विभिन्न ऑपरेशनों की सापेक्ष गति बताता है, जिस पर यह स्थापित है। ये केवल मार्गदर्शक हैं। यदि वे बुरी तरह से गलत हैं तो वे खराब योजना विकल्पों को जन्म दे सकते हैं।

  • LIMITया के साथ किसी भी उपश्रेणी को OFFSETचपटा नहीं किया जा सकता है या पुलअप / पुशडाउन के अधीन नहीं किया जा सकता है। इसका मतलब यह नहीं है कि यह बाहरी क्वेरी के सभी भागों से पहले निष्पादित होगा, हालांकि, या यहां तक ​​कि यह बिल्कुल भी निष्पादित करेगा ।

  • सीटीई की शर्तें (एक WITHप्रश्न में खंड ) हमेशा अपनी संपूर्णता में निष्पादित होती हैं, अगर वे बिल्कुल निष्पादित होती हैं। उन्हें चपटा नहीं किया जा सकता है, और शर्तों को सीटीई अवधि की बाधा के पार नहीं धकेला जा सकता है या नीचे नहीं खींचा जा सकता है। CTE की शर्तों को हमेशा अंतिम क्वेरी से पहले निष्पादित किया जाता है। यह गैर SQL मानक है व्यवहार है, लेकिन यह दस्तावेज के रूप में है कि पोस्टग्रेक्यूएल चीजों को कैसे करता है।

  • PostgreSQL में विदेशी तालिकाओं, security_barrierविचारों और कुछ अन्य विशेष प्रकार के संबंधों पर प्रश्नों को अनुकूलित करने की एक सीमित क्षमता है

  • PostgreSQL सादे SQL को छोड़कर किसी भी चीज़ में लिखे फ़ंक्शन को इनलाइन नहीं करेगा, और न ही इसके और बाहरी क्वेरी के बीच पुलअप / पुशडाउन।

  • योजनाकार / अनुकूलक वास्तव में अभिव्यक्ति सूचकांक का चयन करने के बारे में गूंगा है, और सूचकांक और अभिव्यक्ति के बीच तुच्छ डेटा प्रकार के अंतर के बारे में।

टन अधिक, भी।

तुम्हारे सवाल

आपकी क्वेरी के मामले में:

select 1 
from workdays day
where day.date_day >= '2014-10-01' 
    and day.date_day <= '2015-09-30' 
    and day.offer_id in (
        select offer.offer_day 
        from offer  
        inner join province on offer.id_province = province.id_province  
        inner join center cr on cr.id_cr = province.id_cr 
        where upper(offer.code_status) <> 'A' 
            and province.id_region in ('10' ,'15' ,'21' ,'26' ,'31' , ...,'557') 
            and province.id_cr in ('9' ,'14' ,'20' ,'25' ,'30' ,'35' ,'37')
    )

कुछ भी नहीं एक अतिरिक्त सेट के साथ एक सरल क्वेरी में चपटा होने से रोकता है, और यह बहुत संभावना होगी।

यह संभवत: कुछ ऐसा करेगा (अप्रकाशित, स्पष्ट रूप से):

select 1 
from workdays day
inner join offer on day.offer_id = offer.offer_day
inner join province on offer.id_province = province.id_province  
inner join center cr on cr.id_cr = province.id_cr 
where upper(offer.code_status) <> 'A' 
   and province.id_region in ('10' ,'15' ,'21' ,'26' ,'31' , ...,'557') 
   and province.id_cr in ('9' ,'14' ,'20' ,'25' ,'30' ,'35' ,'37')
   and day.date_day >= '2014-10-01' 
   and day.date_day <= '2015-09-30';

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

कैसे देखें कि ऑप्टिमाइज़र ने क्या किया

आप उस SQL ​​को नहीं देख सकते हैं जो PostgreSQL आपकी क्वेरी का अनुकूलन करता है, क्योंकि यह SQL को आंतरिक क्वेरी ट्री प्रतिनिधित्व में परिवर्तित करता है और फिर उसे संशोधित करता है। आप कर सकते हैं क्वेरी योजना डंप और इसकी तुलना अन्य प्रश्नों से कर सकते हैं।

उस क्वेरी योजना या आंतरिक योजना ट्री को SQL में वापस लाने का कोई तरीका नहीं है।

http://explain.depesz.com/ में एक अच्छा क्वेरी प्लान हेल्पर है। यदि आप क्वेरी योजनाओं आदि के लिए पूरी तरह से नए हैं (जिस स्थिति में मैं अचंभित हूं तो आपने इसे इस पोस्ट के माध्यम से दूर कर दिया है) तो PgAdmin में एक ग्राफिकल क्वेरी प्लान व्यूअर है जो बहुत कम जानकारी प्रदान करता है लेकिन सरल है।

संबंधित पढ़ना:

पुशडाउन / पुलअप और चपटा करने की क्षमताओं में सुधार जारी है । PostgreSQL आमतौर पर पुल-अप / पुश-डाउन / सपाट निर्णय लेने के बारे में सही है, लेकिन हमेशा नहीं, इसलिए कभी-कभी आपको (ab) CTE या OFFSET 0हैक का उपयोग करना पड़ता है । यदि आपको ऐसा कोई मामला मिलता है, तो क्वेरी प्लानर बग की रिपोर्ट करें।


यदि आप वास्तव में हैं, तो वास्तव में उत्सुक हैं आप debug_print_plansकच्चे क्वेरी प्लान को देखने के लिए विकल्प का उपयोग कर सकते हैं , लेकिन मैं वादा करता हूं कि आप इसे पढ़ना नहीं चाहते हैं। वास्तव में।


वाह ... काफी पूरा जवाब :-) उन मामलों में से एक जहां मैंने पोस्टग्रैस्कल (साथ ही अन्य प्रसिद्ध डीबी इंजन, जैसे ओरेकल) के साथ योजना धीमी की थी, स्तंभों या कई सहसंबद्ध जोड़ के बीच संबंध के साथ है। यह अक्सर नेस्टेड छोरों को खत्म कर देगा, यह सोचकर कि योजना के इस बिंदु पर केवल कुछ पंक्तियाँ हैं, जब वास्तव में कई हजारों होते हैं। इस तरह के प्रश्नों को अनुकूलित करने का एक तरीका 'enable_nestloop = off;' सेट करना है; क्वेरी की अवधि के लिए।
alci

मैं एक ऐसी स्थिति में भाग गया, जहाँ v9.5.5 चेक से पहले TO_DATE को लागू करने की कोशिश कर रहा था, यदि इसे लागू किया जा सकता है, तो एक साधारण 7 में जहां खंड क्वेरी है। आदेश दिया गया।
user1133275

@ user1133275 उस स्थिति में यह केवल संयोग से आपके लिए काम करता है, क्योंकि गणना लागत अनुमान समान थे। PostgreSQL अभी भी to_dateकुछ बाद के संस्करण में चेक से पहले चलने का निर्णय ले सकता है या कुछ ऑप्टिमाइज़र आँकड़ों में बदलाव के कारण हो सकता है। किसी फ़ंक्शन से पहले मज़बूती से एक चेक चलाने के लिए जो केवल चेक के बाद चलना चाहिए, एक CASEबयान का उपयोग करें ।
क्रेग रिंगर

सबसे बड़ा जवाब मैं कभी SO पर देखा है! अंगूठे ऊपर, यार!
62mkv

मैंने उन स्थितियों का अनुभव किया जहां साधारण क्वेरी जोड़ने के order byलिए क्वेरी निष्पादन को बहुत तेजी से किया गया था अगर कोई नहीं था order by। यही कारण है कि मैं अपने प्रश्नों को इस तरह से जोड़कर लिखता हूं जैसे कि मैं उन्हें निष्पादित करना चाहता था - यह महान अनुकूलक के लिए अच्छा है, लेकिन मुझे लगता है कि पूरी तरह से इसके परिणाम के लिए अपनी किस्मत पर भरोसा करना बुद्धिमानी नहीं है और बिना सोचे समझे प्रश्न लिखें। यह may beनिष्पादित ... महान जवाब !!
ग्रेग्री

17

एसक्यूएल एक घोषणात्मक भाषा है: आप बताएं कि आप क्या चाहते हैं, कैसे नहीं। RDBMS उस तरीके का चयन करेगा, जो क्वेरी को निष्पादित करेगा, जिसे निष्पादन योजना कहा जाता है।

एक बार (5-10 साल पहले), जिस तरह से एक क्वेरी लिखी गई थी, उसका निष्पादन योजना पर सीधा प्रभाव पड़ा, लेकिन आजकल, अधिकांश SQL डेटाबेस इंजन प्लानिंग के लिए लागत आधारित ऑप्टिमाइज़र का उपयोग करते हैं। यही है, यह डेटाबेस ऑब्जेक्ट्स पर अपने आंकड़ों के आधार पर क्वेरी को निष्पादित करने के लिए विभिन्न रणनीतियों का मूल्यांकन करेगा, और सबसे अच्छा एक का चयन करेगा।

ज्यादातर समय, यह वास्तव में सबसे अच्छा एक है, लेकिन कभी-कभी डीबी इंजन खराब विकल्प बना देगा, जिसके परिणामस्वरूप बहुत धीमी गति से प्रश्न होंगे।


यह ध्यान दिया जाना चाहिए कि कुछ RDBMSs पर क्वेरी ऑर्डर अभी भी महत्वपूर्ण है, लेकिन अधिक उन्नत लोगों के लिए जो कुछ भी आप कहते हैं वह व्यवहार में और साथ ही सिद्धांत में सच है। जब क्वेरी प्लानर निष्पादन आदेश के खराब विकल्पों को चुन रहा होता है, तो आमतौर पर क्वेरी के संकेत इसे और अधिक कुशल दिशा में धकेलने के लिए उपलब्ध होते हैं (जैसे कि WITH(INDEX(<index>))MSSQL में किसी विशेष जॉइन के लिए इंडेक्स की पसंद को बाध्य करने के लिए)।
डेविड स्पिललेट

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