मान लें कि कम से कम 9.3 पोस्टग्रेज करता है।
सूचकांक
सबसे पहले, एक बहु-स्तंभ अनुक्रमणिका मदद करेगी:
CREATE INDEX observations_special_idx
ON observations(station_id, created_at DESC, id)
created_at DESC
थोड़ा बेहतर फिट है, लेकिन सूचकांक अभी भी लगभग उसी गति से पीछे की ओर स्कैन किया जाएगा DESC
के बिना ।
मान लें कि created_at
परिभाषित किया गया है NOT NULL
, अन्यथा DESC NULLS LAST
consider पर विचार करें अनुक्रमणिका में और क्वेरी:
- डेटाटाइम एएससी द्वारा पोस्टग्रेएसक्यूएल सॉर्ट करें, पहले शून्य?
अंतिम कॉलम id
केवल तभी उपयोगी होता है जब आपको इसमें से केवल एक इंडेक्स स्कैन मिलता है, जो शायद काम नहीं करेगा यदि आप लगातार बहुत सारी नई पंक्तियाँ जोड़ते हैं। इस मामले में, id
remove हटा दें सूचकांक से।
सरल क्वेरी (अभी भी धीमी)
अपनी क्वेरी को सरल बनाएं, आंतरिक उप-चयन मदद नहीं करता है:
SELECT id
FROM (
SELECT station_id, id, created_at
, row_number() OVER (PARTITION BY station_id
ORDER BY created_at DESC) AS rn
FROM observations
) s
WHERE rn <= #{n} -- your limit here
ORDER BY station_id, created_at DESC;
थोड़ा तेज़ होना चाहिए, लेकिन फिर भी धीमा होना चाहिए।
तेज़ क्वेरी
- मान लें कि आपके पास अपेक्षाकृत कुछ है स्टेशन और अपेक्षाकृत अनेक प्रति स्टेशन अवलोकन।
station_id
मानकर आईडी कोNOT NULL
as के रूप में परिभाषित किया गया है ।
वास्तव में . होना तेज़, आपको एक ढीले इंडेक्स स्कैन . के बराबर की आवश्यकता है (अभी तक पोस्टग्रेज में लागू नहीं किया गया है)। संबंधित उत्तर:
- प्रति उपयोगकर्ता नवीनतम रिकॉर्ड पुनर्प्राप्त करने के लिए क्वेरी द्वारा GROUP ऑप्टिमाइज़ करें
यदि आपके पास stations
. की एक अलग तालिका है (जिसकी संभावना प्रतीत होती है), आप इसका अनुकरण JOIN LATERAL
. के साथ कर सकते हैं (9.3+ पोस्ट करें):
SELECT o.id
FROM stations s
CROSS JOIN LATERAL (
SELECT o.id
FROM observations o
WHERE o.station_id = s.station_id -- lateral reference
ORDER BY o.created_at DESC
LIMIT #{n} -- your limit here
) o
ORDER BY s.station_id, o.created_at DESC;
यदि आपके पास stations
की तालिका नहीं है , अगली सबसे अच्छी बात एक को बनाना और बनाए रखना होगा। संभवतः संबंधपरक अखंडता को लागू करने के लिए एक विदेशी कुंजी संदर्भ जोड़ें।
यदि वह विकल्प नहीं है, तो आप मक्खी पर ऐसी तालिका को आसवन कर सकते हैं। आसान विकल्प होंगे:
SELECT DISTINCT station_id FROM observations;
SELECT station_id FROM observations GROUP BY 1;
लेकिन या तो अनुक्रमिक स्कैन की आवश्यकता होगी और धीमी गति से होना चाहिए। पोस्टग्रेज़ को उपरोक्त इंडेक्स (या station_id
. के साथ किसी भी btree अनुक्रमणिका का उपयोग करें) प्रमुख कॉलम के रूप में) पुनरावर्ती CTE . के साथ :
WITH RECURSIVE stations AS (
( -- extra pair of parentheses ...
SELECT station_id
FROM observations
ORDER BY station_id
LIMIT 1
) -- ... is required!
UNION ALL
SELECT (SELECT o.station_id
FROM observations o
WHERE o.station_id > s.station_id
ORDER BY o.station_id
LIMIT 1)
FROM stations s
WHERE s.station_id IS NOT NULL -- serves as break condition
)
SELECT station_id
FROM stations
WHERE station_id IS NOT NULL; -- remove dangling row with NULL
इसका उपयोग ड्रॉप-इन प्रतिस्थापन . के रूप में करें stations
. के लिए उपरोक्त सरल क्वेरी में तालिका:
WITH RECURSIVE stations AS (
(
SELECT station_id
FROM observations
ORDER BY station_id
LIMIT 1
)
UNION ALL
SELECT (SELECT o.station_id
FROM observations o
WHERE o.station_id > s.station_id
ORDER BY o.station_id
LIMIT 1)
FROM stations s
WHERE s.station_id IS NOT NULL
)
SELECT o.id
FROM stations s
CROSS JOIN LATERAL (
SELECT o.id, o.created_at
FROM observations o
WHERE o.station_id = s.station_id
ORDER BY o.created_at DESC
LIMIT #{n} -- your limit here
) o
WHERE s.station_id IS NOT NULL
ORDER BY s.station_id, o.created_at DESC;
परिमाण के क्रम . द्वारा यह अभी भी आपके पास जो था उससे तेज होना चाहिए ।
SQL Fiddle यहाँ (9.6)
db<>fiddle here