~ 150M 레코드 테이블에서 고유 한 숫자 ID로 식별되는 1,000 - 50,000 개의 레코드를 검색해야합니다. 우리는 AWS RDS에서 데이터베이스를 호스팅하고 있습니다. 이 테이블에는 여러 개의 integer
열이 있는데 하나는 character varying(500)
이고 id 열은 bigint
입니다. 모든 열은 btree
색인을가집니다.Postgres : IN 대 JOIN을 사용하여 많은 수의 행 선택
현재 생산 쿼리이 허용 m < 1,000 1 초 이내에 반환
SELECT *
FROM mytable t
WHERE id IN (N1, N2, .. Nm)
이다. 문제는 m이 선형 적으로 증가하는 것입니다. 쿼리는 m = 30,000에 대해 20 초 이상 걸립니다.
인덱스 된 임시 테이블을 만들고 INNER JOIN을 사용하여 성능이 크게 개선되지 않았습니다. (https://stackoverflow.com/a/24647700/226960)
다음은 m> 70k에 대한 축약 된 덤프입니다.
CREATE TEMPORARY TABLE temp_phrases (phrase_id integer) ON COMMIT DROP
CREATE TABLE temp_phrases: OK, time: 0.01 seconds.
CREATE INDEX temp_phrases_phrase_id_idx ON temp_phrases(phrase_id)
CREATE INDEX '.temp_phrases.'_phrase_id_idx: OK, time: 0 seconds.
INSERT INTO TABLE temp_phrases: 70544, time: 0.3 seconds.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EXPLAIN SELECT * FROM temp_phrases LEFT JOIN thesaurus ON thesaurus.id = temp_phrases.phrase_id
Nested Loop Left Join (cost=0.57..665368.61 rows=79815 width=34)
-> Seq Scan on temp_phrases (cost=0.00..1111.15 rows=79815 width=4)
-> Index Scan using thesaurus_pkey on thesaurus (cost=0.57..8.31 rows=1 width=42)
Index Cond: (id = temp_phrases.phrase_id)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SELECT * FROM temp_phrases LEFT JOIN thesaurus ON thesaurus.id = temp_phrases.phrase_id
TEMP TABLE AND JOIN: 70544 results, 52.2seconds
이있는 하드웨어 관련 병목
https://stackoverflow.com/a/24254825/226960
원래 id IN(_list_)
쿼리를 향상시킬 수있다 나타냅니다, 우리는 쿼리를 반복하면 결과를 얻을 1 초 미만 소요? 추가 RDS IOPS가 도움이 될까요?
편집
EXPLAIN (ANALYZE, BUFFERS)
출력
INSERT INTO TABLE temp_phrases: 41504, time: 0.17 seconds.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM temp_phrases LEFT JOIN thesaurus ON thesaurus.id = temp_phrases.phrase_id
Nested Loop Left Join (cost=0.57..396319.90 rows=46920 width=34) (actual time=0.708..23874.200 rows=41504 loops=1)
Buffers: shared hit=167593 read=39458 dirtied=138, local hit=184
-> Seq Scan on temp_phrases (cost=0.00..653.20 rows=46920 width=4) (actual time=0.012..21.138 rows=41504 loops=1)
Buffers: local hit=184
-> Index Scan using thesaurus_pkey on thesaurus (cost=0.57..8.42 rows=1 width=42) (actual time=0.569..0.572 rows=1 loops=41504)
Index Cond: (id = temp_phrases.phrase_id)
Buffers: shared hit=167593 read=39458 dirtied=138
Planning time: 1.493 ms
Execution time: 23887.493 ms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SELECT * FROM temp_phrases LEFT JOIN thesaurus ON thesaurus.id = temp_phrases.phrase_id
TEMP TABLE AND JOIN: 41504 results, 24.2seconds
'IN' 대신'EXISTS'를 시도하십시오. 나는 네가 더 나은 성적을 얻을 것이라고 믿는다. –
** [편집] ** 귀하의 질문에 ** ** explain (analyze, buffers) **을 사용하여 생성 된 실행 계획을 추가하십시오. [** 포맷 된 텍스트 **] (http://stackoverflow.com/help/formatting)하시기 바랍니다. [스크린 샷 없음] (http://meta.stackoverflow.com/questions/285551/why-may-i-not -Upload-images-of-code-on-so-ask-a-question/285557 # 285557) –
INSERT INTO temp_phrases 다음에 (VACUUM) ANALYZE를 수행하십시오. 이렇게하면 통계가 업데이트되고 색인 계획이 생성 될 수 있습니다. – joop