Я столкнулся с проблемой в PostgreSQL (версия 9.6.10), когда индексы не работают для ускорения запроса MAX с помощью простого фильтра равенства для другого столбца. Логически кажется, что простой многоколонный индекс на (A, B DESC)
должен сделать запрос очень быстрым.
Я не могу понять, почему я не могу заставить запрос работать, независимо от того, какие индексы определены.
Определение таблицы имеет следующее:
- первичный ключ foo VARCHAR PRIMARY KEY
(не используется в запросе)
- Поле UUID, которое НЕ ПУСТО (NULL), называется bar UUID
- Столбец sequential_id
, который был создан как BIGSERIAL UNIQUE
тип
Вот как именно выглядят соответствующие столбцы (имена изменены для конфиденциальности):
Table "public.foo"
Column | Type | Modifiers
----------------------+--------------------------+--------------------------------------------------------------------------------
foo_uid | character varying | not null
bar_uid | uuid | not null
sequential_id | bigint | not null default nextval('foo_sequential_id_seq'::regclass)
Indexes:
"foo_pkey" PRIMARY KEY, btree (foo_uid)
"foo_bar_uid_sequential_id_idx", btree (bar_uid, sequential_id DESC)
"foo_sequential_id_key" UNIQUE CONSTRAINT, btree (sequential_id)
Несмотря на наличие индекса, указанного выше на (bar_uid, sequential_id DESC)
, следующий запрос требует сканирования индекса и занимает 100-300 мс с несколькими миллионами строк в базе данных.
Запрос (получите максимум sequential_id
для данного bar_uid
):
SELECT MAX(sequential_id)
FROM foo
WHERE bar_uid = 'fa61424d-389f-4e75-ba2d-b77e6bb8491f';
Результат EXPLAIN ANALYZE
не использует правильный индекс. Кроме того, по какой-то причине он проверяет, если sequential_id IS NOT NULL
, даже если он объявлен как not null
.
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Result (cost=0.75..0.76 rows=1 width=8) (actual time=321.110..321.110 rows=1 loops=1)
InitPlan 1 (returns $0)
-> Limit (cost=0.43..0.75 rows=1 width=8) (actual time=321.106..321.106 rows=1 loops=1)
-> Index Scan Backward using foo_sequential_id_key on foo (cost=0.43..98936.43 rows=308401 width=8) (actual time=321.106..321.106 rows=1 loops=1)
Index Cond: (sequential_id IS NOT NULL)
Filter: (bar_uid = 'fa61424d-389f-4e75-ba2d-b77e6bb8491f'::uuid)
Rows Removed by Filter: 920761
Planning time: 0.196 ms
Execution time: 321.127 ms
(9 rows)
Я могу добавить, казалось бы, ненужный GROUP BY
к этому запросу, и это немного ускоряет его, но он все еще очень медленный для запроса, который должен быть почти мгновенным с определенными индексами:
SELECT MAX(sequential_id)
FROM foo
WHERE bar_uid = 'fa61424d-389f-4e75-ba2d-b77e6bb8491f'
GROUP BY bar_uid;
Результат EXPLAIN (ANALYZE, BUFFERS)
:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
GroupAggregate (cost=8510.54..65953.61 rows=6 width=24) (actual time=234.529..234.530 rows=1 loops=1)
Group Key: bar_uid
Buffers: shared hit=1 read=11909
-> Bitmap Heap Scan on foo (cost=8510.54..64411.55 rows=308401 width=24) (actual time=65.259..201.969 rows=309023 loops=1)
Recheck Cond: (bar_uid = 'fa61424d-389f-4e75-ba2d-b77e6bb8491f'::uuid)
Heap Blocks: exact=10385
Buffers: shared hit=1 read=11909
-> Bitmap Index Scan on foo_bar_uid_sequential_id_idx (cost=0.00..8433.43 rows=308401 width=0) (actual time=63.549..63.549 rows=309023 loops=1)
Index Cond: (bar_uid = 'fa61424d-389f-4e75-ba2d-b77e6bb8491f'::uuid)
Buffers: shared read=1525
Planning time: 3.067 ms
Execution time: 234.589 ms
(12 rows)
Кто-нибудь знает, что блокирует этот запрос порядка 10 миллисекунд? По логике это должно быть мгновенно с правильным определенным индексом. Требуется только время, чтобы перейти по ссылкам к значению листа в B-дереве.
Кто-то спросил:
Что вы получаете за SELECT * FROM pg_stats ГДЕ tablename = 'foo' и attname = 'bar_uid';?
schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram
------------+------------------------+-------------+-----------+-----------+-----------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+------------------+-------------+-------------------+------------------------+----------------------
public | foo | bar_uir | f | 0 | 16 | 6 | {fa61424d-389f-4e75-ba2d-b77e6bb8491f,5c5dcae9-1b7e-4413-99a1-62fde2b89c32,50b1e842-fc32-4c2c-b00f-4a17c3c1c5fa,7ff1999c-c0ea-b700-343f-9a737f6ad659,f667b353-e199-4890-9ffd-4940ea11fe2c,b24ce968-29fd-4587-ba1f-227036ee3135} | {0.203733,0.203167,0.201567,0.195867,0.1952,0.000466667} | | -0.158093 | | |
(1 row)