CREATE TABLE product (
product_id SERIAL,
factory_key VARCHAR(60),
relevant BOOLEAN
)
Indexes:
"product_factory_key_key" btree (factory_key);
"product_factory_key_relevant_key" btree (factory_key, relevant) WHERE relevant = false;
"product_relevant_key" btree (relevant);
事実:
product
テーブルには約 1 億件のレコードがあります- 少数の工場があります。たとえば、1 つの工場に 500 万個の製品があるとします。
- 何百万もの工場キーがあります
- 各ファクトリに関係のない行は少数です。たとえば、500 万個の製品を扱う工場があり、関連性のない製品が約 100 個あるとします。
- ただし、関係のない行が何百万行もあります。最も一般的なケースは、1 つのファクトリ キー、5 行の製品、おそらく 2 行の関連しないものです。
これは問題のクエリです:
SELECT * FROM product WHERE factory_key='some_product_key' AND relevant=false LIMIT 10;
説明分析:
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.00..23.06 rows=10 width=188) (actual time=2709.654..32252.961 rows=10 loops=1)
-> Seq Scan on product (cost=0.00..7366785.34 rows=3194759 width=188) (actual time=2709.634..32252.904 rows=10 loops=1)
Filter: ((NOT relevant) AND ((product_key)::text = 'some_product_key'::text))
Rows Removed by Filter: 449486
Total runtime: 32253.150 ms
(5 rows)
問題:
これは次の理由で問題があります。
このファクトリに一致する行が非常に多いため、プランナーは seq スキャンを使用することを選択したと思います。(約 320 万行がこのファクトリまたは約 3% に一致します)
ただし、非常に少数の行のみが関連していないためです。そして、私は関連していないものを探しています。seq スキャンは非常に高価になります。
すでに複合インデックスproduct_factory_key_relevant_key
を作成しましたが、インデックスを利用していません。
編集:
postgres に複合キーの使用を強制しようとしています:product_factory_key_relevant_key
SET enable_seqscan=off
ただし、現在はインデックススキャンを使用しています。実際には、seqscan よりもまだ遅いです。(つまり、seq スキャンを実行するプランナーは正しかったと思います)
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.57..34.03 rows=10 width=188) (actual time=8.088..469974.692 rows=10 loops=1)
-> Index Scan using product_factory_key_relevant_key on product (cost=0.57..10689307.49 rows=3194776 width=188) (actual time=8.083..469974.655 rows=10 loops=1)
Index Cond: (relevant = false)
Filter: ((NOT relevant) AND ((product_key)::text = 'some_product_key'::text))
Rows Removed by Filter: 2205295
Total runtime: 469974.820 ms
(6 rows)