LIMIT x OFFSET y
обычно выполняет не намного быстрее, чем LIMIT x + y
. Большой OFFSET
всегда сравнительно дорогой. Предлагаемый индекс in the linked question помогает, но пока вы не можете получить только для индексации, Postgres все же должен проверить видимость в куче (основное отношение) не менее x + y
строк, чтобы определить правильный результат.
SELECT *
FROM messages
WHERE groupid = 957
ORDER BY id DESC
LIMIT 20
OFFSET 31980;
CLUSTER
на индексе (groupid,id)
будет способствовать увеличению локальности данных в куче и уменьшить количество страниц данных для чтения на запрос. Определенно победа. Но если все groupid
будут в равной степени опрошены, это не удалит узкое место слишком маленького ОЗУ для кеша. Если у вас есть параллельный доступ, рассмотрим pg_repack вместо CLUSTER
:
ли вы на самом деле нужно все столбцы вернулись? (SELECT *
) Индекс покрытия, разрешающий Сканирование только по индексу может помочь, если вам потребуется только несколько небольших столбцов. (autovacuum
должен быть достаточно сильным, чтобы справляться с записью в таблицу).
Кроме того, согласно вашему связанному вопросу, ваша таблица составляет 32 ГБ на диске. (Обычно это немного больше в ОЗУ). Индекс (groupid,id)
добавляет еще 308 MB по крайней мере (без наворотов):
SELECT pg_size_pretty(7337880.0 * 44); -- row count * tuple size
У вас есть 8 Гб оперативной памяти, из которых вы ожидаете около 4,5 Гб, которые будут использоваться для кеша (effective_cache_size = 4608MB
). Этого достаточно для кэширования индекса для повторного использования, но недостаточно для кэширования всей таблицы.
Если ваш запрос происходит, чтобы найти страницы данных в кеше, это быстро. Иначе, не так много. Большая разница, даже с SSD-хранилищем (гораздо больше с HDD).
Не имеет отношения к этому запросу, но 8 МБ от work_
mem (work_mem = 7864kB
) кажется способным к малым для вашей установки. В зависимости от других факторов я бы установил это как минимум 64 МБ (если у вас не много одновременных запросов с сортировкой/хэш-операциями). Как @Craig прокомментировал, EXPLAIN (BUFFERS, ANALYZE)
может рассказать нам больше.
Наилучший план запроса также зависит от значений частот. Если фильтр пропускает всего несколько строк, результат может быть пустым для определенного groupid
, и запрос выполняется сравнительно быстро. Если требуется извлечь большую часть таблицы, выигрывает обычное последовательное сканирование. Вам нужна действительная статистика таблицы (autovacuum
). И, возможно, больше статистики мишенью для groupid
:
Когда вы объясняете анализ, вы, вероятно, получили данные «горячие» в кеше. В этих случаях вы, вероятно, этого не делаете, поэтому больше ввода-вывода. Используйте 'explain (buffers, analysis)', чтобы увидеть использование буфера. –
Для чего вам нужен офсет? Если для разбивки на страницы читайте [this] (http://use-the-index-luke.com/no-offset). Возможно, вы можете ускорить обработку, делая вещи по-другому. –