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);
Факты:
- У нас около 100 миллионов записей в таблице
product
- Есть небольшое количество заводов. Например, на 1 заводе может быть 5 миллионов изделий.
- Есть миллионы заводских ключей
- Только небольшое количество строк НЕ относится к каждой фабрике. Например, есть фабрика с 5 миллионами продуктов, имеет около 100 продуктов, которые НЕ актуальны.
- Однако существует миллион строк НЕ релевантных строк. Так как, самый распространенный случай - это один заводской ключ, 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)
Проблема:
Это проблематично, потому что:
Я полагаю, что планировщик решил использовать последовательное сканирование, потому что существует так много строк, которые соответствуют этой фабрике. (около 3,2 миллиона строк соответствуют этой фабрике или примерно 3%)
Однако, потому что только ЧРЕЗВЫЧАЙНО небольшое количество строк НЕ имеет значения. И я ищу НЕ актуально. Последовательное сканирование оказывается чрезвычайно дорогим.
Я уже создал составной индекс product_factory_key_relevant_key
, однако он не использует преимущества индекса.
ИЗМЕНИТЬ:
Я пытаюсь заставить postgres использовать составной ключ: product_factory_key_relevant_key
SET enable_seqscan=off
Хотя сейчас он использует сканирование индекса. На самом деле это все еще медленнее, чем seqscan. (поэтому я думаю, что планировщик был прав, выполняя последовательное сканирование)
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)
CREATE INDEX CONCURRENTLY
, если не можете позволить себе заблокировать запись на несколько часов. - person Craig Ringer   schedule 19.04.2014explain analyze
. - person Craig Ringer   schedule 19.04.2014explain
. Вам нужноexplain analyze
, чтобы увидеть проблемы со статистикой. explain.depesz.com/s/jNot . См. также stackoverflow.com/tags/postgresql-performance/info. - person Craig Ringer   schedule 19.04.2014