Улучшить производительность запросов в Postgresql с помощью индекса - PullRequest
2 голосов
/ 25 мая 2011

У меня есть таблицы PostgreSQL, каждая из которых содержит миллионы записей и более ста полей.
Одним из них является поле даты, которое мы фильтруем по этим запросам. Создание индекса для этого поля даты улучшило производительность запросов, которые читают небольшой диапазон дат, но при большом диапазоне дат производительность снизилась ...

Я должен расставить приоритеты один над другим? Производительность в малых диапазонах может быть улучшена без уменьшения запросов большого диапазона?

Ответы [ 4 ]

3 голосов
/ 26 мая 2011

На запросы в PostgreSQL нельзя ответить, просто используя информацию в индексе.Независимо от того, является ли строка видимой с точки зрения выполняемого запроса, она хранится в самой основной строке.Поэтому, когда вы добавляете индекс к чему-либо и выполняете запрос, который его использует, происходит два шага:

  • Перемещение по индексу, чтобы определить, какие блоки данных используются
  • Извлечение этих блоковблокирует и возвращает строки, соответствующие запросу

Поэтому возможно, что ответ на запрос с индексом может занять больше времени, чем просто переход непосредственно к блокам данных и выборка строк.Наиболее распространенный случай, когда это происходит, если вы на самом деле захватываете большую часть данных.Обычно, если используется более 20% таблицы, считается, что достаточно просто последовательно получить к ней доступ.Иногда планировщик полагает, что будет получен доступ менее чем к 20%, поэтому индекс предпочтительнее, но это не так;это один из способов добавления индекса, который может замедлить запрос.Это может быть ситуация, которую вы наблюдаете, основываясь на вашем описании - если большие диапазоны касаются большей части таблицы, чем оценки оптимизатора, использование индекса может быть чистым замедлением.

Чтобы понять этобаза данных собирает статистику по каждому столбцу в каждой таблице, чтобы определить, является ли конкретное условие WHERE достаточно избирательным для использования индекса.Идея состоит в том, что вам нужно сохранить столько блоков, не читая всю таблицу, чтобы добавление индекса ввода-вывода поверх нее все еще было чистым выигрышем.

Это вычисление может пойти не так, так что выв конечном итоге, в нескольких случаях вы выполняете больше операций ввода-вывода, чем просто прочитали таблицу напрямую.Причина большинства из них обнаруживается, если вы выполняете запрос, используя EXPLAIN ANALYZE.Если «ожидаемые» значения в сравнении с «фактическими» числами сильно отличаются, это может указывать на то, что оптимизатор имел плохую статистику в таблице.Другая возможность состоит в том, что оптимизатор только что ошибся из-за того, насколько избирателен запрос - он думал, что вернет только небольшое количество строк, но на самом деле возвращает большую часть таблицы.Здесь, опять же, лучшая статистика - нормальный способ начать работать над этим.Если вы используете PostgreSQL 8.3 или более раннюю версию, объем собранной статистики по умолчанию очень низкий.

В некоторых рабочих нагрузках также настраивается настраиваемая переменная random_page_cost, которая контролирует, где компромисс между индексом и сканированием таблицыслучается в.Это только то, что нужно учитывать после проверки статистики.См. Настройка сервера PostgreSQL , чтобы познакомиться с несколькими вещами, которые вы можете настроить здесь.

0 голосов
/ 25 мая 2011

Создание индекса для этого поля даты улучшило производительность запросов, которые читают небольшой диапазон дат, но при большом диапазоне дат производительность снизилась ...

Попробуйте кластеризовать вашу таблицу, используя этот индекс. Снижение производительности может быть связано с открытием всей таблицы на больших диапазонах. И если это так, кластеризация таблицы по этому индексу приведет к меньшему количеству обращений к диску.

0 голосов
/ 25 мая 2011

Два предложения:

1) Исследовать использование table inheritance для данных временных рядов. Например, создайте дочернюю таблицу за месяц, а затем УКАЗАТЬ дату на каждой таблице. PostgreSQL достаточно умен, чтобы выполнять index_scan только для дочерних таблиц, которые содержат фактические данные в диапазоне дат. После того, как дочерняя таблица «запечатана», потому что это новый месяц, выполните CLUSTER для таблицы, чтобы отсортировать данные по дате.

2) Посмотрите на создание группы INDEX, использующих предложения WHERE.

Предложение № 1 будет долгосрочным победителем, но для его настройки потребуется определенная работа (но он будет масштабироваться / работать вечно), но предложение № 2 может быть быстрым временным решением, если у вас есть ограниченный диапазон дат, который вас волнует о сканировании. Помните, что вы можете использовать только функции IMMUTABLE в предложении INDEX WHERE.

CREATE INDEX tbl_date_2011_05_idx ON tbl(date) WHERE date >= '2011-05-01' AND date <= '2011-06-01';
0 голосов
/ 25 мая 2011

Я бы попробовал несколько вещей:

  • увеличить параметры кэша БД
  • добавить индекс в поле даты
  • изменить / модифицировать приложение для работы с нимменьшие диапазоны (хотя это предположение может показаться очевидным, обычно его сначала выбрасывают)
...