Никак, эта оптимизация дает средний чек по всем записям.
Если хотите получить средние данные по нескольким срезам — придётся делать оптимизацию по каждому срезу при каждой записи. Это несколько усложнит программу, но при нескольких миллионах записей и частых запросах результат (выигрыш в скорости) будет того стоить.
Сейчас для себя пишу учебный проект «Домашняя Бухгалтерия» (на Ruby on Rails) и столкнулся с проблемой хранения текущего баланса счёта (кошелька). Вижу два варианта:
1) одна запись в базе отвечающая за хранение состояние счёта
+ простота
— сложно узнать сколько было на счету месяц/год назад. Для этого надо будет просуммировать все совершенный транзакции и вычесть от текущего баланса
2) к каждой записи доход/расход добавляем поле «account_state» где хранить состояние счёта на момент выполнения данной транзакции
+ знаем состояние счёта в любой момент времени (месяц/год назад)
— сложность системы: если необходимо добавить/удалить/изменить доход/расход задним числом, тогда придется пересчитывать состояние счёта для всех транзакций
Я когда-то работал в торговой сети, где было 500 магазинов и по 2000 наименований в каждом. Там решили хранить остатки за каждый день. Получилось, что каждый день прибавлялось бы по 50-100 мегабайт. Их не надо было бы пересчитывать, но если бы понадобилось корректировать, это была бы беда. И самое главное, что эти данные не были точными. Инвентаризации постоянно находили значительные расхождения. То есть хранить неточные оценочные данные не было большого смысла. Они нужны были только ради построения прогнозов, которые делали далеко не по всем наименованиям.
Кстати, в приборах обычно используют именно скользящее среднее для подавление шумов. Проблема только в том, что вход в скользящее среднее занимает время.
Не только. Ещё дисперсия. :) Проблема в том, что в обычных БД этого нет, даже суммы пересчитываются полностью — попробовал на postgres, те же проблемы, только пошустрее работает. По сути я пишу то, что должен делать встроенный оптимизатор запросов.
Да, верно, люди с Вашим высокоразвитым интеллектом догадались бы за секунду. Им эта статья ни к чему. Однако моему техническому директору не было известно, что средняя разность раскладывается как разность средних, и её можно исправлять, и что квадратичные величины тоже раскладываются на суммы.
А вы уверены, что мы в России работаем? Не угадали, не в России. И не стоит обсуждать личности людей. По отдельности такие вещи знают многие, а вместе у понятном виде разные знания просто так не лежат. Если бы я нашёл подобные оптимизации в поисковиках, не писал бы эту статью.
Задача технического директора — держать команду, которая может решать технические задачи и ставить ей эти задачи, а не решать их своими силами. Это я вам как технический директор заявляю.
Завтра в проекте понадобится выравнять картинку в DIV по нижней части текста, а послезавтра — распознать изображение с камеры в iOS. И что, ТД должен и это знать? Нет, он должен организовать подчиненных и подрядчиков так, чтобы эти задачи решились максимально быстро, дешево и надежно.
Обычно хранятся накопленные суммы, например, по каждому счету и сумма этих сумм делится на количество строк в таблице либо количество строк в выборке. Опять же, накопленные суммы легко корректировать. Так же возможно построение по различным измерениям. И OLAP не такой уж дорогой получается ;-)
Да, я как-то тоже замышлял OLAP на коленке с автоматической свёрткой по всем возможным измерениям. Но в конторе надо было дёшево и сердито, поэтому решили, пусть клиенты скажут, что им нужно, и обошлись простыми отчётами.
Реально в банке для подсчетов средних значений по всем клиентам, отделениям, годам/месяцам/неделям/дням и пр. достаточно было одной(!) дополнительной таблицы, правда с «хитрым» наполнением. Стоимость была 1-2 месяца для 1 разработчика. -
Ок, тогда, скажите, пожалуйста, можно ли сделать триггер, который бы не запускал пересчёт суммы по всей колонке, а увеличивал бы её на значение из добавленной записи?
Ну вот реальная ситуация: продажи в 10 оптовых магазинах создают 500 000 строк в неделю, 3000 продуктов. Мне надо пересчитать годовые итоги и по категориям продуктов, и по отдельным из них. Руководитель просит дать ему таблицу в Excel. Не веб-отчёт.
Накапливаете по каждому продукту в таблице ежегодные + ежемесячные (для текущего года) + еженедельные (для текущего месяца) + ежедневные (для текущей недели) и т.д. (вплоть до секунд) суммы и количество дней. Всегда имеете среднее. По окончанию периода «схлопываете» данные. Тоже самое по категориям. «Окончательный» пересчет происходит на закрытии периода. На практике пересчитывать, максимум, приходилось последний месяц, что далеко не все года.
duckduckgo «postgres materialized view выдаёт»: «Materialized Views are currently the #1 requested feature in a user survey for addition to PostgreSQL.»
Идея, конечно, хорошая, но нужно хорошо решить вопрос с параллельным доступом. Так как в момент времени от данных данных и до их записи, сами данные уже могут быть изменены.
Мы аналогичную практику уже применяли на одном проекте средней нагруженности. Кэшированные значения постоянно «уезжали» от реального значения, пока не решили вопрос с конкуретным доступом. Нужно делать атомарным этот ряд операций. Выбрать соответствующий уровень изолированности транзакций БД и предотвратить чтение конкурентными потоками данных (для переподсчета) в период выполнения этой атомарной операции.
Использование сигналов в том виде, как Вы написали — недостаточно. Кстати, select_for_update() (для AnswerAggregate) Django поддерживает только с версии 1.4, которая недавно вышла.
Как не пересчитывать суммы и средние каждый раз