Как получить запрос postgres с ORDER BY для сканирования только по индексу? - PullRequest
0 голосов
/ 26 августа 2018

У меня довольно большая таблица, в которой наиболее распространенный запрос API выглядит примерно так:

/api/orders?status=confirmed

Фактический SQL, сгенерированный для обслуживания этого запроса, выглядит примерно так:

SELECT * FROM orders 
WHERE account_id = 'X' AND status = 'confirmed' AND versionID IS NULL 
ORDER BY int_id;

Что касается меня, я не могу понять, какой индекс сделает это действительно хорошо, работает на postgres 9.5.4.

Я создал индекс на (account_id, status, versionID), который делает все быстро по тому же запросу за исключением ORDER BY (он использует «сканирование только по индексу»), но как только этот ORDER BY включается, он возвращается Вернемся к комбинации «сканирования кучи растровых изображений» и «сканирования растровых индексов», которая в 50-100 раз медленнее.

Я также пытался создать индекс для (int_id ASC, account_id, status, versionID), и планировщик запросов, похоже, полностью его игнорировал.

Есть идеи о том, как создать индекс, который будет обслуживать полный запрос, используя "сканирование только индекса" или что-то эквивалентно быстрое?

Ответы [ 2 ]

0 голосов
/ 26 августа 2018

Если вы знаете, что фильтры предложений where согласованы, вы можете уменьшить индекс, если включите статические фильтры:

CREATE INDEX test_idx1 ON orders (account_id, int_id ASC NULLS LAST) WHERE status = 'confirmed' AND versionID IS NULL

В этом индексе будет упорядочен каждый счетпо int_id.Я считаю, что полезно явно установить ORDER BY так же, как индекс, чтобы вы могли доказать, что он работает:

SELECT * FROM orders WHERE account_id = 'X' AND status = 'confirmed' AND versionID IS NULL ORDER BY int_id ASC NULLS LAST;

Если вы можете перейти из SELECT * в список столбцов, вы также можете сделать это лучше:

SELECT address, name FROM orders WHERE account_id = 'X' AND status = 'confirmed' AND versionID IS NULL ORDER BY int_id;

Тогда это должно сделать сканирование только по индексу:

CREATE INDEX test_idx2 ON orders (account_id, int_id, address, name) WHERE AND status = 'confirmed' AND versionID IS NULL

0 голосов
/ 26 августа 2018

Для этого запроса:

SELECT o.*
FROM orders o
WHERE account_id = 'X' AND status = 'confirmed' AND versionID IS NULL 
ORDER BY int_id;

Оптимальным является составной индекс для (account_id, status, versionID, int_id).int_id должен быть последним ключом в индексе, потому что order by должен иметь место после фильтрации в предложении where.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...