क्वेरी को ऑप्टिमाइज़ करते समय हमेशा 2 बातों का ध्यान रखना चाहिए:
- किस इंडेक्स का उपयोग किया जा सकता है (आपको इंडेक्स बनाने की आवश्यकता हो सकती है)
- क्वेरी कैसे लिखी जाती है (क्वेरी ऑप्टिमाइज़र को उपयुक्त इंडेक्स खोजने में सक्षम होने और डेटा को अनावश्यक रूप से दोबारा न पढ़ने के लिए आपको क्वेरी को बदलने की आवश्यकता हो सकती है)
कुछ अवलोकन:
-
आप अपनी तिथियों में शामिल होने से पहले तारीख में हेरफेर कर रहे हैं। एक सामान्य नियम के रूप में यह एक क्वेरी ऑप्टिमाइज़र को इंडेक्स का उपयोग करने से रोकेगा, भले ही वह मौजूद हो। आपको अपने भावों को इस प्रकार लिखने का प्रयास करना चाहिए कि अनुक्रमित स्तंभ व्यंजक के एक तरफ अपरिवर्तित रहें।
-
आपकी उपश्रेणियाँ उसी दिनांक सीमा तक फ़िल्टर कर रही हैं जैसे
generate_series
. यह एक दोहराव है, और यह सबसे कुशल अनुकूलन चुनने के लिए ऑप्टिमाइज़र की क्षमता को सीमित करता है। मुझे संदेह है कि प्रदर्शन में सुधार के लिए लिखा गया हो सकता है क्योंकि ऑप्टिमाइज़र दिनांक कॉलम (body_time
पर एक इंडेक्स का उपयोग करने में असमर्थ था। )? -
नोट :हम वास्तव में
Body.body_time
. पर एक इंडेक्स का उपयोग करना पसंद करेंगे -
ORDER BY
उपश्रेणियों के भीतर सबसे अच्छा बेमानी है। कम से कम यह क्वेरी ऑप्टिमाइज़र को शामिल होने से पहले परिणाम सेट को सॉर्ट करने के लिए मजबूर कर सकता है; और यह आवश्यक रूप से क्वेरी योजना के लिए अच्छा नहीं है। इसके बजाय केवल अंतिम प्रदर्शन के लिए अंत में ऑर्डरिंग लागू करें। -
LEFT JOIN
. का उपयोग आपके उपश्रेणियों में अनुचित है। मान लें कि आपNULL
. के लिए ANSI कन्वेंशन का उपयोग कर रहे हैं व्यवहार (और आपको होना चाहिए), कोई भी बाहरीenvelope
. से जुड़ता है वापस आ जाएगाenvelope_command=NULL
, और इसके परिणामस्वरूपenvelope_command=?
. शर्त से इन्हें बाहर रखा जाएगा । -
सबक्वेरी
o
औरi
envelope_command
. के लिए लगभग एक जैसे सेव हैं मूल्य। यह ऑप्टिमाइज़र को समान अंतर्निहित तालिकाओं को दो बार स्कैन करने के लिए बाध्य करता है। आप एक पिवट टेबल का उपयोग कर सकते हैं एक बार डेटा से जुड़ने और मानों को 2 कॉलम में विभाजित करने की तकनीक।
निम्नलिखित का प्रयास करें जो पिवट तकनीक का उपयोग करता है:
SELECT p.period,
/*The pivot technique in action...*/
SUM(
CASE WHEN envelope_command = 1 THEN body_size
ELSE 0
END) AS Outbound,
SUM(
CASE WHEN envelope_command = 2 THEN body_size
ELSE 0
END) AS Inbound
FROM (
SELECT date '2009-10-01' + s.day AS period
FROM generate_series(0, date '2009-10-31' - date '2009-10-01') AS s(day)
) AS p
/*The left JOIN is justified to ensure ALL generated dates are returned
Also: it joins to a subquery, else the JOIN to envelope _could_ exclude some generated dates*/
LEFT OUTER JOIN (
SELECT b.body_size,
b.body_time,
e.envelope_command
FROM body AS b
INNER JOIN envelope e
ON e.message_id = b.message_id
WHERE envelope_command IN (1, 2)
) d
/*The expressions below allow the optimser to use an index on body_time if
the statistics indicate it would be beneficial*/
ON d.body_time >= p.period
AND d.body_time < p.period + INTERVAL '1 DAY'
GROUP BY p.Period
ORDER BY p.Period
संपादित करें :टॉम एच द्वारा सुझाया गया जोड़ा गया फ़िल्टर।