〜150Mのレコードテーブルから一意の数値IDで識別される1,000〜50,000のレコードを取得する必要があります。 AWS RDSでデータベースをホストしています。テーブルには、複数のinteger
カラムがあり、idカラムにはcharacter varying(500)
とbigint
の1つがあります。すべての列はbtree
のインデックスを持ちます。Postgres:IN vs 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が役立つでしょうか?
EDIT
EXPLAIN (ANALYZE, BUFFERS)
出力B-Treeインデックス、またはまったくインデックスを使用して
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」を試してください。私はあなたがより良いパフォーマンスを得ると信じています。 –
**あなたの質問に** [編集] **してください**を使用して生成された実行計画を追加する '説明(分析、バッファ)' **。 [**フォーマットされたテキスト**](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