केवल 400 स्टेशनों के लिए, यह क्वेरी बड़े पैमाने पर तेज़ होगी :
SELECT s.station_id, l.submitted_at, l.level_sensor
FROM station s
CROSS JOIN LATERAL (
SELECT submitted_at, level_sensor
FROM station_logs
WHERE station_id = s.station_id
ORDER BY submitted_at DESC NULLS LAST
LIMIT 1
) l;
यहाँ dbfiddle
(इस क्वेरी के लिए योजनाओं की तुलना, एबेलिस्टो के विकल्प और आपके मूल)
EXPLAIN ANALYZE
ओपी द्वारा प्रदान किए गए परिणाम :
नेस्टेड लूप (लागत = 0.56..356.65 पंक्तियाँ = 102 चौड़ाई = 20) (वास्तविक समय = 0.034..0.979 पंक्तियाँ = 98 छोर = 1)
-> स्टेशनों पर एसईसी स्कैन (लागत = 0.00..3.02 पंक्तियों = 102 चौड़ाई = 4) (वास्तविक समय = 0.009..0.016 पंक्तियों = 102 छोरों = 1)
-> सीमा (लागत = 0.56..3.45 पंक्तियाँ = 1 चौड़ाई = 16) (वास्तविक समय = 0.009..0.009 पंक्तियाँ = 1 छोर = 102)
-> स्टेशन_लॉग्स (लागत = 0.56..664062.38 पंक्तियों = 230223 चौड़ाई = 16) पर स्टेशन_id__submitted_at का उपयोग करके सूचकांक स्कैन करें (वास्तविक समय = 0.009 $
सूचकांक कंडोम: (station_id = s.id)
योजना समय: 0.542 एमएस
निष्पादन समय: 1.013 एमएस - !!
आपके द्वारा आवश्यक एकमात्र इंडेक्स आपके द्वारा बनाया गया है station_id__submitted_at
:। UNIQUE
बाधा uniq_sid_sat
भी काम करता है, मूल रूप से। दोनों को बनाए रखना डिस्क स्थान की बर्बादी और प्रदर्शन लिखना जैसा लगता है।
मैं जोड़ा NULLS LAST
करने के लिए ORDER BY
क्योंकि क्वेरी में submitted_at
परिभाषित नहीं है NOT NULL
। आदर्श रूप से, यदि लागू हो!, NOT NULL
कॉलम में एक बाधा जोड़ें submitted_at
, अतिरिक्त सूचकांक को छोड़ दें और NULLS LAST
क्वेरी से हटा दें ।
यदि submitted_at
हो सकता है NULL
, तो UNIQUE
अपने वर्तमान सूचकांक और अद्वितीय बाधा दोनों को बदलने के लिए इस सूचकांक को बनाएं :
CREATE UNIQUE INDEX station_logs_uni ON station_logs(station_id, submitted_at DESC NULLS LAST);
विचार करें:
यह प्रासंगिक (आमतौर पर PK) प्रति एक पंक्ति के साथ एक अलग तालिकाstation
मान रहा है station_id
- जो आपके पास होना चाहिए। यदि आपके पास यह नहीं है, तो इसे बनाएं। फिर, इस rCTE तकनीक के साथ बहुत तेजी से:
CREATE TABLE station AS
WITH RECURSIVE cte AS (
(
SELECT station_id
FROM station_logs
ORDER BY station_id
LIMIT 1
)
UNION ALL
SELECT l.station_id
FROM cte c
, LATERAL (
SELECT station_id
FROM station_logs
WHERE station_id > c.station_id
ORDER BY station_id
LIMIT 1
) l
)
TABLE cte;
मैं फिडल में भी इसका इस्तेमाल करता हूं। आप अपने कार्य को हल करने के लिए एक समान क्वेरी का उपयोग कर सकते हैं, बिना station
टेबल के - यदि आप इसे बनाने के लिए आश्वस्त नहीं हो सकते हैं।
विस्तृत निर्देश, स्पष्टीकरण और विकल्प:
अनुक्रमणिका का अनुकूलन करें
आपकी क्वेरी अब बहुत तेज़ होनी चाहिए। यदि आपको अभी भी पठन प्रदर्शन का अनुकूलन करने की आवश्यकता है ...
इंडेक्स-ओनली स्कैन कीlevel_sensor
अनुमति देने के लिए इंडेक्स के अंतिम कॉलम के रूप में जोड़ना समझ में आता है , जैसे कि जोनलो ने टिप्पणी की थी । Con: यह इंडेक्स को बड़ा बनाता है - जो इसे उपयोग करने वाले सभी प्रश्नों के लिए थोड़ी लागत जोड़ता है। प्रो: यदि आपको वास्तव में इंडेक्स केवल स्कैन से मिलता है, तो हाथ में क्वेरी को ढेर पृष्ठों पर नहीं जाना पड़ता है, जो इसे लगभग दो बार उपवास करता है। लेकिन यह बहुत तेज क्वेरी के लिए एक अबाधित लाभ हो सकता है।
हालाँकि , मैं आपके मामले के लिए काम करने की उम्मीद नहीं करता। आपने उल्लिखित किया था:
... प्रति दिन लगभग 20k पंक्तियाँ station_id
।
आमतौर पर, यह रिलीजिंग लोड को इंगित करेगा ( station_id
प्रत्येक 5 सेकंड में 1 )। और आप नवीनतम पंक्ति में रुचि रखते हैं । सूचकांक-केवल स्कैन हीप पृष्ठों के लिए काम करता है जो सभी लेनदेन के लिए दिखाई देते हैं (दृश्यता मानचित्र में बिट सेट है)। आपको VACUUM
लिखने के भार के साथ रखने के लिए तालिका के लिए बेहद आक्रामक सेटिंग्स को चलाना होगा , और यह अभी भी अधिकांश समय काम नहीं करेगा। अगर मेरी धारणा सही है, तो इंडेक्स-ओनली स्कैन बाहर हैं, इंडेक्स में न जोड़ें level_sensor
।
OTOH, अगर मेरी धारणाएं पकड़ में हैं और आपकी तालिका बहुत बड़ी हो रही है , तो BRIN इंडेक्स मदद कर सकता है। सम्बंधित:
या, और भी अधिक विशिष्ट और अधिक कुशल: अप्रासंगिक पंक्तियों के थोक में कटौती करने के लिए केवल नवीनतम परिवर्धन के लिए एक आंशिक सूचकांक:
CREATE INDEX station_id__submitted_at_recent_idx ON station_logs(station_id, submitted_at DESC NULLS LAST)
WHERE submitted_at > '2017-06-24 00:00';
एक टाइमस्टैम्प का चयन करें जिसके लिए आप जानते हैं कि छोटी पंक्तियों का अस्तित्व होना चाहिए। आपको WHERE
सभी प्रश्नों के लिए एक मेल शर्त जोड़ना होगा , जैसे:
...
WHERE station_id = s.station_id
AND submitted_at > '2017-06-24 00:00'
...
आपको समय-समय पर सूचकांक और क्वेरी को अनुकूलित करना होगा।
अधिक विवरण के साथ संबंधित जवाब: