Я недавно столкнулся и решил проблему - но я не понимаю, почему вообще возникла проблема.
Упрощенно сказано, у меня есть 3 таблицы в базе данных postgres 10.5:
entities (id, name)
entities_to_stuff(
id,
entities_id -> fk entities.id,
stuff_id -> fk stuff.id,
unique constraint (entity_id, stuff_id)
)
stuff(id, name)
после вставки около 200 тыс. Записей выбирает по запросу:
select * from entities_to_stuff where entities_id = 1;
начало занимать 100 - 400 мс.
Как понятно, создание уникального ограничения создает индекс по уникальным полям.поэтому у меня есть индекс на (entities_id, stuff_id)
, entities_id
- самый левый столбец.
в соответствии с документами, запросы, включая самый левый столбец, являются наиболее эффективными ( postgres документы на этом ) - поэтому я предположил, что этот индекс мне подойдет.
Итак, я проверил план выполнения - он не использовал индекс.Итак, просто чтобы убедиться, что я сделал:
SET enable_seqscan = OFF;
и повторно выполнил запрос - большую часть времени он все еще занимал более 100 мс.
Затем я разозлился и создал этот индекс
create index "idx_entities_id" on "entities_to_stuff" ("entities_id");
и внезапно для запуска требуется 0,2 мс или даже меньше, и план выполнения также использует его, когда включены последовательные сканирования.
Как этот индекс на несколько порядков быстрее, чем ужесуществующий?
Редактировать:
план выполнения после генерации дополнительного индекса:
Index Scan using idx_entities_id on entities_to_stuff (cost=0.00..12.04 rows=2 width=32) (actual time=0.049..0.050 rows=1 loops=1)
Index Cond: (entities_id = 199283)
Planning time: 0.378 ms
Execution time: 0.073 ms
план только с уникальным ограничением, seq_scan = on
Gather (cost=1000.00..38679.87 rows=2 width=32) (actual time=344.321..1740.861 rows=1 loops=1)
Workers Planned: 2
Workers Launched: 0
-> Parallel Seq Scan on entities_to_stuff (cost=0.00..37679.67 rows=1 width=32) (actual time=344.088..1739.684 rows=1 loops=1)
Filter: (entities_id = 199283)
Rows Removed by Filter: 2907419
Planning time: 0.241 ms
Execution time: 740.888 ms
план с ограничением, seq-scan = off
Index Scan using uq_entities_to_stuff on entities_to_stuff (cost=0.43..66636.34 rows=2 width=32) (actual time=0.385..553.066 rows=1 loops=1)
Index Cond: (entities_id = 199283)
Planning time: 0.082 ms
Execution time: 553.103 ms