PostgreSQL- "IN"절의 최대 매개 변수 수?


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

이것은 현재의 질문에 대한 답은 아니지만 다른 사람들에게도 도움이 될 수 있습니다.

적어도 Posgresql의 JDBC 드라이버 9.1을 사용하여 PostgreSQL 백엔드에 전달할 수있는 기술적 인 제한 32767 값 (= Short.MAX_VALUE)이 있음을 알 수 있습니다.

이것은 postgresql jdbc 드라이버를 사용하여 "(여기서 ID를 (... 100k 값 ...) 인 x에서 삭제") 테스트입니다.

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
OP는 DB 엔진 제한에 대해 질문했지만 JDBC 제한을 검색 중입니다. 제가 여기에 왔으며 이것이 내가 좋아했던 것입니다. 그러나 한계가 상당히 높습니다.
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)

postgres가 임시 테이블을 빌드하고 조인하는 것을 볼 수 있습니다.


그러나 postgres-9.3 + 둘 다 동일한 성능을 가진 것으로 보입니다. datadoghq.com/blog/…
PiyusG

18

IN 절에 전달하는 요소 수에는 제한이 없습니다. 더 많은 요소가 있으면 배열로 간주 한 다음 데이터베이스의 각 스캔에 대해 배열에 포함되어 있는지 확인합니다. 이 접근 방식은 그렇게 확장 가능하지 않습니다. IN 절을 사용하는 대신 임시 테이블과 함께 INNER JOIN을 사용하십시오. 자세한 내용은 http://www.xaprb.com/blog/2006/06/28/why-large-in-clauses-are-problematic/ 을 참조 하십시오 . INNER JOIN 스케일과 쿼리 최적화 프로그램을 사용하면 해시 조인 및 기타 최적화를 사용할 수 있습니다. IN 절을 사용하면 옵티마이 저가 쿼리를 최적화 할 수있는 방법이 없습니다. 이 변경으로 최소 2 배의 속도가 향상되었습니다.


2
당신이 말하는 링크는 그것이 말하는 DBMS를 말하지 않습니다. Oracle DB에서 임시 테이블을 사용하면 쿼리를 구문 분석하고 계획하는 데 많은 오버 헤드가 발생 하여 쿼리 결합 ORIN절 을 사용하는 것보다 성능이 크게 향상 된다는 것을 확인할 수는 있지만 Postgres 9.5의 문제를 확인할 수는 없습니다 . 이 답변을 참조하십시오 .
blubb December

17

Oracle DB에 대해 더 많은 경험이있는 사람도이 한계에 대해 걱정했습니다. 나는 목록에 ~ 10,000 매개 변수가있는 쿼리에 대한 성능 테스트를 수행 했으며 실제로 모든 소수를 쿼리 매개 변수로 나열IN 하여 첫 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-hackers 메일 링리스트 의이 오래된 스레드 는 그러한 쿼리를 계획하는 데 여전히 무시할 수없는 비용이 있음을 나타내므로 소금 한 알을 내 말로 가져 가십시오.


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[]).
Kiran Jonnalagadda

4
어쨌든 @KiranJonnalagadda는 내부 작업이 필요하지 않으면 성능을 향상시킵니다 (아마도 무시할 수 있음).
로드리고

1

그냥 해봐 대답은 2 바이트 값으로-> 범위를 벗어난 정수입니다.


0

임의로 긴 ID 목록을 추가하는 대신 해당 쿼리를 리팩토링하는 것이 좋습니다. ID가 실제로 패턴의 패턴을 따르는 경우 범위를 사용할 수 있습니다.

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

또 다른 옵션은 내부 선택을 추가하는 것입니다.

SELECT * 
FROM user 
WHERE id IN (
    SELECT userId
    FROM ForumThreads ft
    WHERE ft.id = X
);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.