Из ваших комментариев следующий запрос на самом деле довольно производительный:
SELECT *
FROM accounts
ORDER BY id
LIMIT 1;
Причина, по которой он работает хорошо, заключается в том, что шаг LIMIT
и ORDER BY
- единственное, что нужно сделать Postgresдо SELECT
, и уникальный индекс accounts_pkey
можно легко отсканировать здесь.На самом деле, Postgres нужно только найти самое низкое значение id
, а затем вернуться к кластерному индексу, чтобы охватить SELECT *
.
Однако запрос в вашем вопросе немного другой:
SELECT *
FROM accounts
WHERE pid = 'hd' AND fid = '123'
ORDER BY id ASC
LIMIT 1;
В этом случае Postgres выбирает сканирование всего индекса accounts_pkey
, начиная с шага фильтрации, соответствующего вашему предложению WHERE
.Поскольку accounts_pkey
охватывает только столбец id
, Postgres должен выполнить поиск в кластеризованном индексе, чтобы найти значения pid
и fid
.В идеале Postgres должен начинать с самого низкого значения id
и идти по индексу до тех пор, пока не найдет первое совпадение по значениям pid
и fid
.Независимо от того, что Postgres решит сделать, здесь может помочь следующий индекс покрытия:
CREATE INDEX idx_accounts_cover ON public.accounts USING btree (pid, fid, id);
Учитывая, что почти 6 миллионов записей теперь могут быть легко удалены с использованием указанного индекса, оставшиеся LIMIT
/ ORDER BY
операция на id
может быть более терпимой.И поскольку этот индекс также охватывает id
, Postgres должен будет выполнить возврат к кластерному индексу только один раз, в самом конце запроса.