У меня есть скромная таблица из примерно 10 тыс. Строк, которая часто сортируется по столбцу с именем «name». Итак, я добавил индекс для этого столбца. Теперь выбирает на это быстро:
EXPLAIN ANALYZE SELECT * FROM crm_venue ORDER BY name ASC LIMIT 10;
...query plan...
Limit (cost=0.00..1.22 rows=10 width=154) (actual time=0.029..0.065 rows=10 loops=1)
-> Index Scan using crm_venue_name on crm_venue (cost=0.00..1317.73 rows=10768 width=154) (actual time=0.026..0.050 rows=10 loops=1)
Total runtime: 0.130 ms
Если я увеличу LIMIT
до 60 (это примерно то, что я использую в приложении), общее время выполнения не увеличится намного дальше.
Поскольку я использую «шаблон логического удаления» в этой таблице, я рассматриваю только те записи, где delete_date NULL
. Так что это общий выбор, который я делаю:
SELECT * FROM crm_venue WHERE delete_date IS NULL ORDER BY name ASC LIMIT 10;
Чтобы сделать этот запрос также быстрым, я поместил индекс в столбец name
с таким ограничением:
CREATE INDEX name_delete_date_null ON crm_venue (name) WHERE delete_date IS NULL;
Теперь можно быстро упорядочить с помощью ограничения логического удаления:
EXPLAIN ANALYZE SELECT * FROM crm_venue WHERE delete_date IS NULL ORDER BY name ASC LIMIT 10;
Limit (cost=0.00..84.93 rows=10 width=154) (actual time=0.020..0.039 rows=10 loops=1)
-> Index Scan using name_delete_date_null on crm_venue (cost=0.00..458.62 rows=54 width=154) (actual time=0.018..0.033 rows=10 loops=1)
Total runtime: 0.076 ms
Отлично! Но это то, где я попал в беду. Приложение редко вызывает первые 10 строк. Итак, давайте выберем еще несколько строк:
EXPLAIN ANALYZE SELECT * FROM crm_venue WHERE delete_date IS NULL ORDER BY name ASC LIMIT 20;
Limit (cost=135.81..135.86 rows=20 width=154) (actual time=18.171..18.189 rows=20 loops=1)
-> Sort (cost=135.81..135.94 rows=54 width=154) (actual time=18.168..18.173 rows=20 loops=1)
Sort Key: name
Sort Method: top-N heapsort Memory: 21kB
-> Bitmap Heap Scan on crm_venue (cost=4.67..134.37 rows=54 width=154) (actual time=2.355..8.126 rows=10768 loops=1)
Recheck Cond: (delete_date IS NULL)
-> Bitmap Index Scan on crm_venue_delete_date_null_idx (cost=0.00..4.66 rows=54 width=0) (actual time=2.270..2.270 rows=10768 loops=1)
Index Cond: (delete_date IS NULL)
Total runtime: 18.278 ms
Как вы можете видеть, оно идет от 0,1 мс до 18 !!
Понятно, что происходит то, что упорядочение больше не может использовать индекс для запуска сортировки. Я заметил, что когда я увеличиваю число LIMIT
с 20 до более высоких чисел, это всегда занимает около 20-25 мс.
Я делаю это неправильно или это ограничение PostgreSQL? Как лучше всего настроить индексы для этого типа запросов?