मुख्य बात यह है कि आप JOIN
और GROUP
max(created)
. पाने के लिए हर चीज पर . यह मान अलग से प्राप्त करें।
आपने उन सभी इंडेक्स का उल्लेख किया है जिनकी यहां आवश्यकता है:report_rank.created
. पर और विदेशी चाबियों पर। तुम वहाँ ठीक कर रहे हो। (यदि आप "ठीक है" से बेहतर में रुचि रखते हैं, तो पढ़ते रहें !)
LEFT JOIN report_site
एक सादे JOIN
के लिए मजबूर किया जाएगा WHERE
. द्वारा खंड। मैंने एक सादा JOIN
. को प्रतिस्थापित किया . मैंने आपके वाक्य-विन्यास को भी बहुत सरल बना दिया है।
अपडेट किया गया जुलाई 2015 सरल, तेज़ प्रश्नों और बेहतर कार्यों के साथ।
एकाधिक पंक्तियों के लिए समाधान
report_rank.created
अद्वितीय नहीं है और आप सभी चाहते हैं नवीनतम पंक्तियाँ।
विंडो फ़ंक्शन का उपयोग करना rank()
एक सबक्वेरी में।
SELECT r.id, r.keyword_id, r.site_id
, r.rank, r.url, r.competition
, r.source, r.country, r.created -- same as "max"
FROM (
SELECT *, rank() OVER (ORDER BY created DESC NULLS LAST) AS rnk
FROM report_rank r
WHERE EXISTS (
SELECT *
FROM report_site s
JOIN report_profile p ON p.site_id = s.id
JOIN crm_client c ON c.id = p.client_id
JOIN auth_user u ON u.id = c.user_id
WHERE s.id = r.site_id
AND u.is_active
AND c.is_deleted = FALSE
)
) sub
WHERE rnk = 1;
क्यों DESC NULLS LAST
?
एक पंक्ति के लिए समाधान
अगर report_rank.created
अद्वितीय है या आप किसी भी 1 पंक्ति . से संतुष्ट हैं max(created)
. के साथ :
SELECT id, keyword_id, site_id
, rank, url, competition
, source, country, created -- same as "max"
FROM report_rank r
WHERE EXISTS (
SELECT 1
FROM report_site s
JOIN report_profile p ON p.site_id = s.id
JOIN crm_client c ON c.id = p.client_id
JOIN auth_user u ON u.id = c.user_id
WHERE s.id = r.site_id
AND u.is_active
AND c.is_deleted = FALSE
)
-- AND r.created > f_report_rank_cap()
ORDER BY r.created DESC NULLS LAST
LIMIT 1;
तेज होना चाहिए, अभी भी। और विकल्प:
गतिशील रूप से समायोजित आंशिक अनुक्रमणिका के साथ अंतिम गति
आपने पिछली क्वेरी में टिप्पणी वाला हिस्सा देखा होगा:
AND r.created > f_report_rank_cap()
आपने 50 mio का उल्लेख किया है। पंक्तियाँ, यह बहुत है। चीजों को गति देने का एक तरीका यहां दिया गया है:
- एक साधारण
IMMUTABLE
बनाएं फ़ंक्शन एक टाइमस्टैम्प लौटाता है जो जितना संभव हो उतना युवा होने के दौरान ब्याज की पंक्तियों से पुराना होने की गारंटी देता है। - एक आंशिक अनुक्रमणिका बनाएं केवल छोटी पंक्तियों पर - इस फ़ंक्शन के आधार पर।
WHERE
का उपयोग करें क्वेरी में स्थिति जो अनुक्रमणिका की स्थिति से मेल खाती है।- एक और फ़ंक्शन बनाएं जो इन ऑब्जेक्ट्स को डायनामिक डीडीएल के साथ नवीनतम पंक्ति में अपडेट करता है। (शून्य से सुरक्षित मार्जिन यदि नवीनतम पंक्ति (पंक्तियों) को हटा दिया जाता है / निष्क्रिय कर दिया जाता है - यदि ऐसा हो सकता है)
- इस सेकेंडरी फंक्शन को ऑफ-टाइम पर कम से कम समवर्ती गतिविधि प्रति क्रोनजॉब या मांग पर आमंत्रित करें। जितनी बार आप चाहें, नुकसान नहीं कर सकते, इसे बस टेबल पर एक छोटा अनन्य लॉक चाहिए।
यहां एक पूर्ण कार्यशील डेमो है .
@erikcw, आपको नीचे दिए गए निर्देश के अनुसार टिप्पणी वाले हिस्से को सक्रिय करना होगा।
CREATE TABLE report_rank(created timestamp);
INSERT INTO report_rank VALUES ('2011-11-11 11:11'),(now());
-- initial function
CREATE OR REPLACE FUNCTION f_report_rank_cap()
RETURNS timestamp LANGUAGE sql COST 1 IMMUTABLE AS
$y$SELECT timestamp '-infinity'$y$; -- or as high as you can safely bet.
-- initial index; 1st run indexes whole tbl if starting with '-infinity'
CREATE INDEX report_rank_recent_idx ON report_rank (created DESC NULLS LAST)
WHERE created > f_report_rank_cap();
-- function to update function & reindex
CREATE OR REPLACE FUNCTION f_report_rank_set_cap()
RETURNS void AS
$func$
DECLARE
_secure_margin CONSTANT interval := interval '1 day'; -- adjust to your case
_cap timestamp; -- exclude older rows than this from partial index
BEGIN
SELECT max(created) - _secure_margin
FROM report_rank
WHERE created > f_report_rank_cap() + _secure_margin
/* not needed for the demo; @erikcw needs to activate this
AND EXISTS (
SELECT *
FROM report_site s
JOIN report_profile p ON p.site_id = s.id
JOIN crm_client c ON c.id = p.client_id
JOIN auth_user u ON u.id = c.user_id
WHERE s.id = r.site_id
AND u.is_active
AND c.is_deleted = FALSE)
*/
INTO _cap;
IF FOUND THEN
-- recreate function
EXECUTE format('
CREATE OR REPLACE FUNCTION f_report_rank_cap()
RETURNS timestamp LANGUAGE sql IMMUTABLE AS
$y$SELECT %L::timestamp$y$', _cap);
-- reindex
REINDEX INDEX report_rank_recent_idx;
END IF;
END
$func$ LANGUAGE plpgsql;
COMMENT ON FUNCTION f_report_rank_set_cap()
IS 'Dynamically recreate function f_report_rank_cap()
and reindex partial index on report_rank.';
कॉल करें:
SELECT f_report_rank_set_cap();
देखें:
SELECT f_report_rank_cap();
खंड AND r.created > f_report_rank_cap()
. को हटा दें उपरोक्त प्रश्न में और अंतर देखें। सत्यापित करें कि अनुक्रमणिका EXPLAIN ANALYZE
. के साथ प्रयोग की जाती है ।
मैनुअल ऑन कंकरेंसी और REINDEX
: