बड़ी तालिका में धीमा सूचकांक स्कैन


12

PostgreSQL 9.2 का उपयोग करते हुए, मुझे अपेक्षाकृत बड़ी तालिका (200+ मिलियन पंक्तियों) पर धीमी क्वेरी के साथ परेशानी है। मैं कुछ भी पागल करने की कोशिश नहीं कर रहा हूं, सिर्फ ऐतिहासिक मूल्यों को जोड़ रहा हूं। नीचे क्वेरी और क्वेरी प्लान आउटपुट है।

मेरी तालिका लेआउट:

                                   Table "public.energy_energyentry"
  Column   |           Type           |                            Modifiers
-----------+--------------------------+-----------------------------------------------------------------
 id        | integer                  | not null default nextval('energy_energyentry_id_seq'::regclass)
 prop_id   | integer                  | not null
 timestamp | timestamp with time zone | not null
 value     | double precision         | not null
Indexes:
    "energy_energyentry_pkey" PRIMARY KEY, btree (id)
    "energy_energyentry_prop_id" btree (prop_id)
    "energy_energyentry_prop_id_timestamp_idx" btree (prop_id, "timestamp")
Foreign-key constraints:
    "energy_energyentry_prop_id_fkey" FOREIGN KEY (prop_id) REFERENCES gateway_peripheralproperty(id) DEFERRABLE INITIALLY DEFERRED

डेटा 2012-01-01 से लेकर अब तक, नए डेटा के साथ लगातार जोड़ा जा रहा है। prop_idसमान रूप से वितरित विदेशी कुंजी में लगभग 2.2k अलग-अलग मूल्य हैं ।

मुझे लगता है कि पंक्ति का अनुमान बहुत दूर नहीं है, लेकिन लागत का अनुमान कारक 4x से बड़ा लगता है। यह शायद एक मुद्दा नहीं है, लेकिन क्या मैं इसके बारे में कुछ भी कर सकता हूं?

मुझे उम्मीद है कि डिस्क का उपयोग मुद्दा हो सकता है, क्योंकि मेज हर समय स्मृति में नहीं है।

EXPLAIN ANALYZE 
SELECT SUM("value") 
FROM "energy_energyentry" 
WHERE 
  "prop_id"=82411 
  AND "timestamp">'2014-06-11' 
  AND "timestamp"<'2014-11-11'
;
 Aggregate  (cost=214481.45..214481.46 rows=1 width=8) (actual time=51504.814..51504.814 rows=1 loops=1)
   ->  Index Scan using energy_energyentry_prop_id_timestamp_idx on  energy_energyentry (cost=0.00..214434.08 rows=18947 width=8) (actual time=136.030..51488.321 rows=13578 loops=1)
         Index Cond: ((prop_id = 82411) AND ("timestamp" > '2014-06-11 00:00:00+00'::timestamp with time zone) AND ("timestamp" < '2014-11-11 00:00:00+00'::timestamp with time zone))
 Total runtime: 51504.841 ms

किसी भी सुझाव यह कैसे तेजी से बनाने के लिए?
मैं भी सिर्फ सुनने के साथ ठीक हूँ मैं कुछ भी अजीब नहीं था।


1
कृपया हमें बताएं कि आपकी तालिका कैसी दिखती है, इसके क्या सूचकांक हैं और डेटा का प्रसार है।
कॉलिन के टी हार्ट

मैंने आपके द्वारा पूछा गया अतिरिक्त सूचना पत्र जोड़ा। दुनो चाहे मैं कुछ भी याद करूं।
एक्सिलियन

2
अजीब बात है: आपका व्याख्या विश्लेषण दिखाता है prop_time_idx, फिर भी तालिका परिभाषा दिखाता है entry_prop_id_timestamp_idx। क्या यह वही सूचकांक है? कृपया ठीक करें।
कॉलिन के टी हार्ट

यदि आप 'लागत अनुमानों को 4x बड़ा मानते हैं' इस तथ्य से संदर्भित करते हैं कि लागत संख्या वास्तविक समय की तुलना में 4 गुना अधिक है , तो कृपया ध्यान दें कि दोनों का एक-दूसरे से कोई लेना-देना नहीं है। लागत केवल एक अनुमान है, क्वेरी ऑप्टिमाइज़र को सबसे अच्छी दिखने वाली योजना चुनने में मदद करती है। इस संदर्भ के बाहर, यह आमतौर पर एक व्यर्थ मूल्य है।
dezso 10

1
आपकी तिथि सीमा कितने प्रतिशत तालिका का प्रतिनिधित्व करती है (बिना इस पर ध्यान दिए कि मूल्यों के लिए prop)? यदि बस एक छोटा सा प्रतिशत, शायद एक सूचकांक ("timestamp", prop)बेहतर होगा। एक ही अग्रणी स्तंभ ( propआपके मामले में) के साथ कई सूचकांक भी अक्सर बेमानी होते हैं।
कॉलिन के टी हार्ट

जवाबों:


10

आपकी तालिका बड़ी है , और इसलिए पूरी तालिका में कोई भी सूचकांक है। ऐसा मानते हुए:

  • केवल नया डेटा (साथ timestamp = now()) दर्ज किया गया है
  • मौजूदा पंक्तियों को न तो बदला गया और न ही हटाया गया।
  • आपके पास 2012-01-01 के बाद से डेटा है लेकिन वर्तमान वर्ष पर प्रश्न मुख्य रूप से हैं (?)

मैं एक आंशिक, बहु-स्तंभ (कवरिंग!) सूचकांक का सुझाव दूंगा :

CREATE INDEX ON energy_energyentry (prop_id, "timestamp", value)
WHERE "timestamp" >= '2014-01-01 0:0';  -- adapt to your needs

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

अंतिम कॉलम मान केवल इसमें से केवल-इंडेक्स स्कैन करने के लिए शामिल है । आक्रामक ऑटोवैक्युम सेटिंग दृश्यता मानचित्र को अद्यतित रखने में मदद कर सकती है, जैसे @jjanes पहले ही उल्लेखित हैं

आंशिक सूचकांक को रैम में अधिक आसानी से फिट होना चाहिए और वहां लंबे समय तक रहना चाहिए।

WHEREसूचकांक को क्वेरी पर लागू करने के लिए योजनाकार को समझने के लिए आपको इस स्थिति को प्रश्नों में शामिल करना पड़ सकता है , जैसे:

SELECT sum(value) AS sum_value
FROM   energy_energyentry
WHERE  prop_id = 82411 
AND   "timestamp" > '2014-06-11 0:0' 
AND   "timestamp" < '2014-11-11 0:0'
AND   "timestamp" >= '2014-01-01 0:0'; -- seems redundant, but may be needed

चूँकि आपकी क्वेरी बहुत सी पंक्तियों ( rows=13578) को समेटे हुए है , यह कुछ समय लेने वाला है, यहाँ तक कि एक सूचकांक-केवल स्कैन के साथ भी। यह कहीं भी 50 सेकंड के पास नहीं होना चाहिए, हालांकि। किसी भी आधे रास्ते सभ्य हार्डवेयर पर एक सेकंड से भी कम।

संबंधित (लेकिन अनदेखा करें CLUSTERऔर FILLFACTOR, दोनों अप्रासंगिक हैं यदि आप इसे केवल इंडेक्स-स्कैन प्राप्त कर सकते हैं) :

एक तरफ:
चूंकि आपके पास वर्तमान में एक इंडेक्स है (prop_id, "timestamp"), इसलिए अतिरिक्त इंडेक्स की (prop_id)कीमत इससे अधिक हो सकती है:


अब जब Postgres BRIN इंडेक्स का समर्थन करता है, तो क्या यह उपयोगी होगा? मैं पोस्टग्रेज पर डेटा पर लगभग 140 मिलियन पंक्तियों को संग्रहीत करने की योजना बना रहा हूं, क्या BRIN उस बड़ी तालिका के लिए उपयोग करने के लिए सही सूचकांक है?
आर्य

2

यदि आप इंडेक्स बनाते हैं (prop_id, "टाइमस्टैम्प", "वैल्यू"), तो यह बिना टेबल पर आए मूल्य की गणना करने के लिए इंडेक्स-ओनली स्कैन का उपयोग कर सकता है। यह बहुत सारे रैंडम डिस्क एक्सेस को बचा सकता है।

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


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