Как я могу улучшить производительность среднего метода в SQL? - PullRequest
4 голосов
/ 15 декабря 2010

У меня возникают некоторые проблемы с производительностью, когда SQL-запрос, вычисляющий среднее значение столбца, постепенно замедляется по мере увеличения количества записей. Есть ли тип индекса, который я могу добавить к столбцу, который позволит ускорить средние вычисления?

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

Чтобы быть более точным, данные, по сути, представляют собой журнал с таким определением:

table log {
  int duration
  date time
  string event
}

Я делаю запросы вроде

SELECT average(duration) FROM log WHERE event = 'finished'; # gets average time to completion
SELECT average(duration) FROM log WHERE event = 'finished' and date > $yesterday; # average today

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

Ответы [ 5 ]

7 голосов
/ 15 декабря 2010

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

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

2 голосов
/ 15 декабря 2010

Ускорение агрегатов обычно выполняется за счет сохранения дополнительных таблиц.

Предполагается, что размер таблицы detail(id, dimA, dimB, dimC, value), если вы хотите, чтобы производительность AVG (или других агрегатных функций) была почти постоянной, независимо от количествазаписей, которые вы могли бы представить новую таблицу

dimAavg(dimA, avgValue)

  • Размер этой таблицы будет зависеть только от количества различных значений dimA (более того, эта таблица может иметь смысл в вашейспроектировать, так как он может содержать область значений, доступных для dimA, подробно (и другие атрибуты, относящиеся к значениям домена; у вас может быть / должна быть уже такая таблица)
  • Эта таблица полезна только в том случае, если вы будете анализировать с помощьюТолько dimA, когда вам понадобится AVG (значение) в соответствии с dimA и dimB, оно станет бесполезным. Итак, вам нужно знать, по каким атрибутам вы хотите провести быстрый анализ. Количество строк, необходимое для хранения агрегатов по нескольким атрибутамn(dimA) x n(dimB) x n(dimC) x ..., который может расти или не расти довольно быстро.
  • Поддержаниеэта таблица увеличивает стоимость обновлений (в т.ч.вставляет и удаляет), но есть и другие способы оптимизации, которые вы можете использовать ...

Например, давайте предположим, что система преимущественно выполняет вставку, а обновляет и удаляет только изредка.

Позволяетдалее предположим, что вы хотите анализировать только по dimA и что id s увеличиваются.Тогда наличие такой структуры, как

dimA_agg(dimA, Total, Count, LastID) 

, может помочь без значительного влияния на систему.

Это потому, что у вас могут быть триггеры, которые не будут срабатывать при каждой вставке, но, скажем, всегда100 вставок.

Таким образом, вы все еще можете получить точные агрегаты из этой таблицы и таблицы подробностей с

SELECT a.dimA, (SUM(d.value)+MAX(a.Total))/(COUNT(d.id)+MAX(a.Count)) as avgDimA
FROM details d INNER JOIN
     dimA_agg a ON a.dimA = d.dimA AND d.id > a.LastID 
GROUP BY a.dimA

Приведенный выше запрос справильные индексы получат одну строку из dimA_agg и только менее 100 строк из detail - это будет работать почти в постоянное время (~ log fanout n) и не потребует обновления до dimA_agg длякаждая вставка (сокращение штрафов за обновление).

Значение 100 было приведено в качестве примера, вы должны найти оптимальное значение самостоятельно (или даже оставить его переменным, хотя в этом случае только триггеров будет недостаточно).

Сохранение удалений и обновлений должно запускаться при каждой операции, но вы все равно можете проверить, находится ли идентификатор удаляемой или обновленной записи в статистике или нет, чтобы избежать ненужных действий.sary обновления (сэкономит некоторый ввод / вывод).

Примечание: анализ сделан для домена с дискретными атрибутами;при работе с временными рядами ситуация усложняется - вам необходимо выбрать степень детализации домена, в котором вы хотите сохранить сводку.

РЕДАКТИРОВАТЬ

Есть также материализованных представлений , 2 , 3

2 голосов
/ 15 декабря 2010

Зависит от того, что вы делаете?Если вы не фильтруете данные, то, кроме кластерного индекса по порядку, как еще база данных рассчитывает среднее значение столбца?

Существуют системы, которые выполняют аналитическую онлайн-обработку (OLAP), которая будет делатьтакие вещи, как ведение сумм и усреднение информации, которую вы хотите изучить.Все зависит от того, что вы делаете, и от вашего определения «медленный».

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

0 голосов
/ 15 декабря 2010

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

Например, если у ваших данных есть столбец даты, вы можете вычислить среднее значение для записей 1 - Date1, а затем сохранить среднее значение для этого пакета вместе с Date1 и усредненными # записями. При следующем вычислении вы ограничите свой запрос результатами Date1..Date2, добавите количество записей и обновите последнюю запрашиваемую дату. У вас есть вся информация, необходимая для вычисления нового среднего значения.

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

0 голосов
/ 15 декабря 2010

Просто предположение, но индексы не сильно помогут, так как среднее число должно читать все записи (в любом порядке), индексы полезны для поднаборов поиска строк, хотя, если вам приходится перебирать все строки без специальных индексов упорядоченияне помогают ...

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