PostgreSQL में आमतौर पर उचित सूची लंबाई में काफी छोटा अंतर होता है, हालांकि IN
अवधारणात्मक रूप से बहुत साफ है। बहुत लंबा AND ... <> ...
सूचियाँ और बहुत लंबी NOT IN
AND
. के साथ दोनों सूचियां बहुत अच्छा प्रदर्शन करती हैं NOT IN
. से भी बदतर ।
दोनों ही मामलों में, यदि वे इतने लंबे हैं कि आप प्रश्न पूछ सकते हैं, तो आपको इसके बजाय एक मूल्य सूची पर एक एंटी-जॉइन या सबक्वेरी बहिष्करण परीक्षण करना चाहिए।
WITH excluded(item) AS (
VALUES('item1'), ('item2'), ('item3'), ('item4'),('item5')
)
SELECT *
FROM thetable t
WHERE NOT EXISTS(SELECT 1 FROM excluded e WHERE t.item = e.item);
या:
WITH excluded(item) AS (
VALUES('item1'), ('item2'), ('item3'), ('item4'),('item5')
)
SELECT *
FROM thetable t
LEFT OUTER JOIN excluded e ON (t.item = e.item)
WHERE e.item IS NULL;
(आधुनिक पीजी संस्करणों पर दोनों वैसे भी एक ही क्वेरी प्लान तैयार करेंगे)।
यदि मूल्य सूची काफी लंबी है (कई दसियों हजारों आइटम) तो क्वेरी पार्सिंग की एक महत्वपूर्ण लागत शुरू हो सकती है। इस बिंदु पर आपको एक TEMPORARY
बनाने पर विचार करना चाहिए टेबल, COPY
डेटा को इसमें शामिल करना, संभवतः उस पर एक इंडेक्स बनाना, फिर सीटीई के बजाय अस्थायी तालिका पर उपरोक्त तरीकों में से एक का उपयोग करना।
डेमो:
CREATE UNLOGGED TABLE exclude_test(id integer primary key);
INSERT INTO exclude_test(id) SELECT generate_series(1,50000);
CREATE TABLE exclude AS SELECT x AS item FROM generate_series(1,40000,4) x;
जहां exclude
छोड़े जाने वाले मानों की सूची है।
फिर मैं मिलीसेकंड में सभी परिणामों के साथ समान डेटा पर निम्नलिखित दृष्टिकोणों की तुलना करता हूं:
NOT IN
सूची:3424.596AND ...
सूची:80173.823VALUES
आधारितJOIN
बहिष्करण:20.727VALUES
आधारित सबक्वेरी बहिष्करण:20.495- तालिका-आधारित
JOIN
, पूर्व-सूची में कोई अनुक्रमणिका नहीं:25.183 - उपश्रेणी आधारित तालिका, पूर्व-सूची पर कोई अनुक्रमणिका नहीं:23.985
... सीटीई-आधारित दृष्टिकोण को AND
. की तुलना में तीन हजार गुना तेज बनाना सूची और NOT IN
. से 130 गुना तेज सूची।
यहां कोड:https://gist.github.com/ringerc/5755247 (अपनी आंखों की रक्षा करें, जो इस लिंक का अनुसरण करते हैं)।
इस डेटा सेट आकार के लिए बहिष्करण सूची में एक इंडेक्स जोड़ने से कोई फर्क नहीं पड़ा।
नोट:
IN
SELECT 'IN (' || string_agg(item::text, ',' ORDER BY item) || ')' from exclude;
AND
SELECT string_agg(item::text, ' AND item <> ') from exclude;
)- सबक्वायरी और जॉइन आधारित टेबल बहिष्करण दोहराए गए रनों में समान थे।
- योजना की जांच से पता चलता है कि पीजी का अनुवाद
NOT IN
. होता है करने के लिए<> ALL
तो... आप देख सकते हैं कि वास्तव में एक विशाल है IN
. दोनों के बीच गैप और AND
सूचियाँ बनाम एक उचित जुड़ाव। मुझे आश्चर्य हुआ कि एक सीटीई के साथ VALUES
. का उपयोग करके इसे कितनी तेजी से कर रहा था सूची थी ... VALUES
को पार्स किया जा रहा है सूची में लगभग बिल्कुल भी समय नहीं लगा, वही प्रदर्शन कर रहा है या इससे थोड़ा तेज अधिकांश परीक्षणों में तालिका दृष्टिकोण।
यह अच्छा होगा यदि PostgreSQL स्वचालित रूप से एक लंबे समय तक IN
recognize को पहचान सके समान AND
. का खंड या शृंखला शर्तों और एक बेहतर दृष्टिकोण पर स्विच करें जैसे हैश जॉइन करना या इसे सीटीई नोड में बदलना। अभी यह नहीं जानता कि यह कैसे करना है।
यह भी देखें:
- यह आसान ब्लॉग पोस्ट मैग्नस हैगेंडर ने इस विषय पर लिखा था