PostgreSQL - "इन" खंड में अधिकतम पैरामीटर?


147

Postgres में, आप इस तरह एक IN क्लॉज निर्दिष्ट कर सकते हैं:

SELECT * FROM user WHERE id IN (1000, 1001, 1002)

क्या किसी को पता है कि अधिकतम कितने पैरामीटर आप IN में पास कर सकते हैं?

जवाबों:


83

यहां स्थित स्रोत कोड के अनुसार , लाइन 850 पर शुरू होने के बाद, PostgreSQL स्पष्ट रूप से तर्कों की संख्या को सीमित नहीं करता है।

निम्नलिखित पंक्ति 870 से एक कोड टिप्पणी है:

/*
 * We try to generate a ScalarArrayOpExpr from IN/NOT IN, but this is only
 * possible if the inputs are all scalars (no RowExprs) and there is a
 * suitable array type available.  If not, we fall back to a boolean
 * condition tree with multiple copies of the lefthand expression.
 * Also, any IN-list items that contain Vars are handled as separate
 * boolean conditions, because that gives the planner more scope for
 * optimization on such clauses.
 *
 * First step: transform all the inputs, and detect whether any are
 * RowExprs or contain Vars.
 */

56

यह वास्तव में वर्तमान प्रश्न का उत्तर नहीं है, हालांकि यह दूसरों की भी मदद कर सकता है।

कम से कम मैं बता सकता हूं कि पोस्ग्रेसक्यूएल के JDBC ड्राइवर 9.1 का उपयोग करते हुए, PostgreSQL बैकएंड के लिए 32767 मूल्यों (= Short.MAX_VALUE) की एक तकनीकी सीमा है।

यह postgresql jdcc ड्राइवर के साथ "x से डिलीट जहाँ आईडी (... 100k मान ...)" की एक परीक्षा है:

Caused by: java.io.IOException: Tried to send an out-of-range integer as a 2-byte value: 100000
    at org.postgresql.core.PGStream.SendInteger2(PGStream.java:201)

6
ओपी ने डीबी इंजन सीमा के बारे में पूछा है, लेकिन जेडडीबीसी सीमा की खोज मैं यहां आया हूं और यही मैं उसके लिए प्यार कर रहा था। तो एक सीमा है, हालांकि, काफी अधिक है।
9ilsdx 9rvj 0lo

36
explain select * from test where id in (values (1), (2));

जल्दी योजना

 Seq Scan on test  (cost=0.00..1.38 rows=2 width=208)
   Filter: (id = ANY ('{1,2}'::bigint[]))

लेकिन अगर दूसरा प्रश्न आज़माएँ:

explain select * from test where id = any (values (1), (2));

जल्दी योजना

Hash Semi Join  (cost=0.05..1.45 rows=2 width=208)
       Hash Cond: (test.id = "*VALUES*".column1)
       ->  Seq Scan on test  (cost=0.00..1.30 rows=30 width=208)
       ->  Hash  (cost=0.03..0.03 rows=2 width=4)
             ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=4)

हम देख सकते हैं कि पोस्टग्रुप टेम्प टेबल का निर्माण करते हैं और इसके साथ जुड़ते हैं


लेकिन मैंने जो सुना, वह पोस्ट-ग्राउंड-9.3 + दोनों एक ही परफ़ॉर्मर लगता है। datadoghq.com/blog/…
PiyusG

18

उन तत्वों की संख्या की कोई सीमा नहीं है जिन्हें आप IN क्लॉज में दे रहे हैं। यदि अधिक तत्व हैं, तो इसे सरणी के रूप में माना जाएगा और फिर डेटाबेस में प्रत्येक स्कैन के लिए यह जांच करेगा कि यह सरणी में निहित है या नहीं। यह दृष्टिकोण इतना स्केलेबल नहीं है। इनवॉइस का उपयोग करने के बजाय अस्थायी तालिका के साथ INNER JOIN का उपयोग करने का प्रयास करें। अधिक जानकारी के लिए http://www.xaprb.com/blog/2006/06/28/why-large-in-clauses-are-problematic/ देखें । INNER JOIN तराजू के साथ-साथ क्वेरी ऑप्टिमाइज़र का उपयोग करके हैश ज्वाइन और अन्य ऑप्टिमाइज़ेशन का उपयोग किया जा सकता है। जबकि IN खंड के साथ ऑप्टिमाइज़र के लिए क्वेरी को ऑप्टिमाइज़ करने का कोई तरीका नहीं है। मैंने इस बदलाव के साथ कम से कम 2x का स्पीडअप देखा है।


2
आप जिस लिंक का जिक्र कर रहे हैं, वह यह नहीं बताता है कि यह किस DBMS की बात कर रहा है। मैं इस बात की पुष्टि कर सकते हैं कि Oracle DB पर, अस्थायी तालिकाओं का उपयोग के संयोजन प्रश्नों का उपयोग करने पर एक बड़े पैमाने पर प्रदर्शन को बढ़ावा देने देता है ORऔर INपार्स करने और इस तरह के प्रश्नों की योजना बनाने में बड़ा भूमि के ऊपर के कारण खंड, मैं Postgres 9.5 के साथ समस्या यह पुष्टि नहीं कर सके, को देखने के इस जवाब
14

17

जैसा कि ओरेकल डीबी के साथ कोई और अनुभव करता है, मैं इस सीमा के बारे में भी चिंतित था। मैंने एक- INसूची में ~ 10'000 मापदंडों के साथ क्वेरी के लिए एक प्रदर्शन परीक्षण किया , जिसमें प्राइमरी नंबर को क्वेरी पैरामीटर्स के रूप में सभी प्रमुख नंबरों को सूचीबद्ध करके पहले 100'000 पूर्णांक के साथ 100'000 तक के प्राइम नंबर लाए ।

मेरे परिणामों से संकेत मिलता है कि आपको क्वेरी प्लान ऑप्टिमाइज़र को ओवरलोड करने या इंडेक्स के उपयोग के बिना योजना प्राप्त करने के बारे में चिंता करने की आवश्यकता नहीं है , क्योंकि यह क्वेरी को उपयोग करने के लिए बदल देगा = ANY({...}::integer[])जहां यह उम्मीद के मुताबिक सूचकांक का लाभ उठा सकता है:

-- prepare statement, runs instantaneous:
PREPARE hugeplan (integer, integer, integer, ...) AS
SELECT *
FROM primes
WHERE n IN ($1, $2, $3, ..., $9592);

-- fetch the prime numbers:
EXECUTE hugeplan(2, 3, 5, ..., 99991);

-- EXPLAIN ANALYZE output for the EXECUTE:
"Index Scan using n_idx on primes  (cost=0.42..9750.77 rows=9592 width=5) (actual time=0.024..15.268 rows=9592 loops=1)"
"  Index Cond: (n = ANY ('{2,3,5,7, (...)"
"Execution time: 16.063 ms"

-- setup, should you care:
CREATE TABLE public.primes
(
  n integer NOT NULL,
  prime boolean,
  CONSTRAINT n_idx PRIMARY KEY (n)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE public.primes
  OWNER TO postgres;

INSERT INTO public.primes
SELECT generate_series(1,100000);

हालांकि, pgsql- हैकर्स मेलिंग सूची पर यह (बल्कि पुराना) धागा इंगित करता है कि इस तरह के प्रश्नों की योजना बनाने में अभी भी एक नगण्य लागत है, इसलिए नमक के एक दाने के साथ मेरा शब्द लें।


3

यदि आपके पास क्वेरी है जैसे:

SELECT * FROM user WHERE id IN (1, 2, 3, 4 -- and thousands of another keys)

यदि आप अपनी क्वेरी को फिर से लिखना चाहते हैं, तो आप प्रदर्शन बढ़ा सकते हैं:

SELECT * FROM user WHERE id = ANY(VALUES (1), (2), (3), (4) -- and thousands of another keys)

10
PostgreSQL का EXPLAINकहना है कि यह आंतरिक IN (...)रूप से मेरा पुनर्लेखन है ANY ('{...}'::integer[])
किरण जोनलगड्डा

4
वैसे भी, @KiranJonnalagadda, यह प्रदर्शन बढ़ाता है (नगण्य, शायद) अगर कोई आंतरिक कार्य की आवश्यकता नहीं है।
रॉड्रिगो

1

बस कोशिश की। उत्तर है -> 2-बाइट मान के रूप में आउट-ऑफ-द-रेंज पूर्णांक: 32768


0

आप मनमाने ढंग से आईडी की लंबी सूची जोड़ने के बजाय उस क्वेरी को फिर से भरने पर विचार कर सकते हैं ... यदि आप वास्तव में अपने उदाहरण में पैटर्न का पालन करते हैं तो आप एक सीमा का उपयोग कर सकते हैं:

SELECT * FROM user WHERE id >= minValue AND id <= maxValue;

एक अन्य विकल्प एक आंतरिक चयन जोड़ने के लिए है:

SELECT * 
FROM user 
WHERE id IN (
    SELECT userId
    FROM ForumThreads ft
    WHERE ft.id = X
);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.