इंडेक्स (केवल) स्कैन -> बिटमैप इंडेक्स स्कैन -> अनुक्रमिक स्कैन
कुछ पंक्तियों के लिए यह एक इंडेक्स स्कैन चलाने के लिए भुगतान करता है। यदि पर्याप्त डेटा पृष्ठ सभी के लिए दृश्यमान हैं (=पर्याप्त वैक्यूम किया गया है, और बहुत अधिक समवर्ती लेखन भार नहीं है) और अनुक्रमणिका सभी आवश्यक स्तंभ मान प्रदान कर सकती है, तो एक तेज़ अनुक्रमणिका केवल स्कैन का उपयोग किया जाता है। अधिक पंक्तियों के वापस आने की उम्मीद के साथ (तालिका का उच्च प्रतिशत और डेटा वितरण, मूल्य आवृत्तियों और पंक्ति की चौड़ाई के आधार पर) एक डेटा पृष्ठ पर कई पंक्तियों को खोजने की अधिक संभावना हो जाती है। फिर यह बिटमैप इंडेक्स स्कैन पर स्विच करने के लिए भुगतान करता है। (या कई अलग-अलग इंडेक्स को संयोजित करने के लिए।) एक बार डेटा पेजों के एक बड़े प्रतिशत को किसी भी तरह से देखा जाना है, अनुक्रमिक स्कैन चलाना, अधिशेष पंक्तियों को फ़िल्टर करना और इंडेक्स के लिए ओवरहेड को पूरी तरह से छोड़ना सस्ता है।
अनुक्रमिक क्रम में डेटा पृष्ठों तक पहुँचने पर इंडेक्स का उपयोग (बहुत) सस्ता और अधिक होने की संभावना (अधिक) हो जाती है। ऐसा तब होता है जब स्पिनिंग डिस्क के बजाय SSD का उपयोग किया जाता है, या इससे भी अधिक RAM में कैश किया जाता है - और संबंधित कॉन्फ़िगरेशन पैरामीटर random_page_cost
और effective_cache_size
तदनुसार सेट कर रहे हैं।
आपके मामले में, Postgres एक अनुक्रमिक स्कैन पर स्विच करता है, जो rows=263962
खोजने की अपेक्षा करता है , यह पहले से ही संपूर्ण तालिका का 3% है। (जबकि केवल rows=47935
वास्तव में पाए जाते हैं, नीचे देखें।)
इस संबंधित उत्तर में और अधिक:
- इंडेक्स या बिटमैप इंडेक्स स्कैन का उपयोग करके टाइमस्टैम्प पर कुशल PostgreSQL क्वेरी?
जबरदस्ती क्वेरी योजनाओं से सावधान रहें
आप किसी निश्चित योजनाकार पद्धति को सीधे Postgres में बाध्य नहीं कर सकते, लेकिन आप अन्य . बना सकते हैं डीबगिंग उद्देश्यों के लिए विधियां बेहद महंगी लगती हैं। मैनुअल में प्लानर मेथड कॉन्फिगरेशन देखें।
SET enable_seqscan = off
(जैसा कि किसी अन्य उत्तर में सुझाया गया है) अनुक्रमिक स्कैन के लिए करता है। लेकिन यह केवल आपके सत्र में डिबगिंग उद्देश्यों के लिए है। नहीं करें इसे उत्पादन में एक सामान्य सेटिंग के रूप में उपयोग करें जब तक कि आप ठीक से नहीं जानते कि आप क्या कर रहे हैं। यह हास्यास्पद क्वेरी योजनाओं को बाध्य कर सकता है। मैनुअल:
ये कॉन्फ़िगरेशन पैरामीटर क्वेरी ऑप्टिमाइज़र द्वारा चुनी गई क्वेरी योजनाओं को प्रभावित करने की एक अपरिष्कृत विधि प्रदान करते हैं। यदि किसी विशेष क्वेरी के लिए अनुकूलक द्वारा चुना गया डिफ़ॉल्ट प्लान इष्टतम नहीं है, तो एकअस्थायी समाधान इन कॉन्फ़िगरेशन मापदंडों में से एक का उपयोग करना है ताकि अनुकूलक को एक अलग योजना चुनने के लिए मजबूर किया जा सके। अनुकूलक द्वारा चुनी गई योजनाओं की गुणवत्ता में सुधार करने के बेहतर तरीकों में शामिल हैं, ANALYZE
चलाना, योजनाकार लागत स्थिरांक को समायोजित करना (देखें खंड 19.7.2), मैन्युअल रूप से, default_statistics_target
. का मान बढ़ाना कॉन्फ़िगरेशन पैरामीटर, और ALTER TABLE SET STATISTICS
का उपयोग करके विशिष्ट कॉलम के लिए एकत्रित आंकड़ों की मात्रा में वृद्धि करना ।
आपको पहले से ही अधिकांश सलाह की आवश्यकता है।
- पोस्टग्रेएसक्यूएल को कभी-कभी खराब क्वेरी प्लान चुनने से रोकें
इस विशेष मामले में, Postgres को email_activities.email_recipient_id
पर 5-6 गुना अधिक हिट की उम्मीद है की तुलना में वास्तव में पाए जाते हैं:
अनुमानित rows=227007
बनाम actual ... rows=40789
अनुमानित rows=263962
बनाम actual ... rows=47935
यदि आप इस क्वेरी को अक्सर चलाते हैं तो इसके लिए ANALYZE
का भुगतान करना होगा विशेष कॉलम पर अधिक सटीक आंकड़ों के लिए एक बड़ा नमूना देखें। आपकी तालिका बड़ी है (~ 10M पंक्तियाँ), इसलिए इसे बनाएं:
ALTER TABLE email_activities ALTER COLUMN email_recipient_id
SET STATISTICS 3000; -- max 10000, default 100
फिर ANALYZE email_activities;
अंतिम उपाय का उपाय
बहुत दुर्लभ . में जिन मामलों में आप SET LOCAL enable_seqscan = off
के साथ एक इंडेक्स को बाध्य करने का सहारा ले सकते हैं एक अलग लेनदेन में या अपने स्वयं के वातावरण के साथ एक समारोह में। पसंद:
CREATE OR REPLACE FUNCTION f_count_dist_recipients(_email_campaign_id int, _limit int)
RETURNS bigint AS
$func$
SELECT COUNT(DISTINCT a.email_recipient_id)
FROM email_activities a
WHERE a.email_recipient_id IN (
SELECT id
FROM email_recipients
WHERE email_campaign_id = $1
LIMIT $2) -- or consider query below
$func$ LANGUAGE sql VOLATILE COST 100000 SET enable_seqscan = off;
सेटिंग केवल फ़ंक्शन के स्थानीय दायरे पर लागू होती है।
चेतावनी: यह सिर्फ अवधारणा का प्रमाण है। यहां तक कि यह बहुत कम कट्टरपंथी मैनुअल हस्तक्षेप आपको लंबे समय में काट सकता है। कार्डिनैलिटीज, वैल्यू फ़्रीक्वेंसी, आपका स्कीमा, ग्लोबल पोस्टग्रेज़ सेटिंग्स, समय के साथ सब कुछ बदल जाता है। आप एक नए पोस्टग्रेज संस्करण में अपग्रेड करने जा रहे हैं। अभी आप जिस क्वेरी प्लान को थोपते हैं, वह बाद में बहुत बुरा विचार बन सकता है।
और आमतौर पर यह आपके सेटअप की किसी समस्या का समाधान मात्र है। इसे बेहतर तरीके से ढूंढें और ठीक करें।
वैकल्पिक क्वेरी
प्रश्न में आवश्यक जानकारी गायब है, लेकिन यह समकक्ष क्वेरी शायद तेज़ है और (email_recipient_id
पर एक इंडेक्स का उपयोग करने की अधिक संभावना है। ) - अधिक से अधिक LIMIT
. के लिए ।
SELECT COUNT(*) AS ct
FROM (
SELECT id
FROM email_recipients
WHERE email_campaign_id = 1607
LIMIT 43000
) r
WHERE EXISTS (
SELECT FROM email_activities
WHERE email_recipient_id = r.id);