Это целая куча коррелированных подзапросов, требующих соответствующей индексации.
Для разумного числа строк, возвращаемых запросом, коррелированные подзапросы могут дать разумную производительность. Но если внешний запрос возвращает тысячи строк, это будут тысячи выполнений подзапросов.
Я бы не стал запускать несколько SELECT для одной и той же таблицы, чтобы получить последние 7 дней, последние 15дней, последние 30 дней, а затем повторяя это, чтобы получить AVG, повторяя это, чтобы получить MAX, и снова, чтобы получить MIN.
Вместо этого я бы склонялся к использованию условного агрегирования, чтобы получить всю статистику AVG, MAX, MIN, для всех периодов времени 30 дней, 15 дней и 7 дней, за один проход по таблице.
... пауза, чтобы заметить, что представления могут быть проблематичнымидля исполнения;предикаты из внешнего запроса могут не помещаться в запрос представления. Мы не видим, что делает все определение представления, но я подозреваю, что мы можем материализовать большой набор.
Рассмотрим такой запрос:
SELECT ...
, ROUND( ( n.mal / a.avg_07_day - 1)*100 ,2) AS dif_7_dias
, ROUND( ( n.mal / a.avg_15_day - 1)*100 ,2) AS dif_15_dias
, ROUND( ( n.mal / a.avg_30_day - 1)*100 ,2) AS dif_30_dias
, ...
FROM vinhos
LEFT
JOIN ( SELECT h.codigowine
, AVG(IF( h.timestamp >= CURRENT_DATE + INTERVAL -30 DAY, h.preconormal, NULL)) AS avg_30_day
, MAX(IF( h.timestamp >= CURRENT_DATE + INTERVAL -30 DAY, h.preconormal, NULL)) AS max_30_day
, MIN(IF( h.timestamp >= CURRENT_DATE + INTERVAL -30 DAY, h.preconormal, NULL)) AS min_30_day
, AVG(IF( h.timestamp >= CURRENT_DATE + INTERVAL -15 DAY, h.preconormal, NULL)) AS avg_15_day
, MAX(IF( h.timestamp >= CURRENT_DATE + INTERVAL -15 DAY, h.preconormal, NULL)) AS max_15_day
, MIN(IF( h.timestamp >= CURRENT_DATE + INTERVAL -15 DAY, h.preconormal, NULL)) AS min_15_day
, AVG(IF( h.timestamp >= CURRENT_DATE + INTERVAL -7 DAY, h.preconormal, NULL)) AS avg_07_day
, MAX(IF( h.timestamp >= CURRENT_DATE + INTERVAL -7 DAY, h.preconormal, NULL)) AS max_07_day
, MIN(IF( h.timestamp >= CURRENT_DATE + INTERVAL -7 DAY, h.preconormal, NULL)) AS min_07_day
FROM precos h
GROUP
BY h.codigowine
HAVING h.codigowine IS NOT NULL
) a
ON a.codigowine = vinhos.codigowine
LEFT
JOIN ( SELECT s.codigowine
, MAX(s.precnormal) AS mal
, MIN(s.precnormal) AS mil
FROM precos s
WHERE s.timestamp >= CURRENT_DATE - INTERVAL 9 HOUR
GROUP
BY s.codigowine
HAVING s.codigowine IS NOT NULL
) n
ON n.codigowine = vinhos.codigowine
Рассмотримзапрос встроенного просмотра a
.
Обратите внимание, что мы можем запустить этот SELECT отдельно и получить возвращенный набор результатов, как если бы мы возвращали результат из таблицы. Мы ожидаем, что это сделает одиночный проход через ссылочную таблицу. Могут существовать некоторые предикаты (условия в предложении WHERE), которые будут фильтровать нашу строку или позволят нам лучше использовать индекс. Как написано в настоящее время, запрос может использовать индекс с начальным столбцом codigowine
, чтобы избежать (потенциально дорогой) операции «Использование файловой сортировки» для удовлетворения GROUP BY
.
I'mнемного смущен запросами - ИНТЕРВАЛ 9 ЧАС. Мне кажется, что эти подзапросы могут потенциально возвращать более одной строки. Там нет предложения LIMIT (и нет ORDER BY) ... но похоже, что мы ожидаем одно значение (скалярное), учитывая операцию деления.
Без понимания того, чего мы пытаемся достичьНе зная спецификации, я обернул свою путаницу и поместил ее в другое встроенное представление n
... не то, что мы хотим сделать, а просто, чтобы проиллюстрировать (снова) встроенное представление, возвращающее набор результатов. Какие бы значения мы ни пытались получить из - подзапроса INTERVAL 9 HOUR, я думаю, что мы можем вернуть их и в виде набора.
С учетом всего сказанного мы можем теперь обойтина ответ на заданный вопрос: добавление «вычисляемой таблицы».
Если нам не нужны до второго результата, но мы можем работать с кэшированной статистикой, я хотел бы рассмотреть материализацию набора результатов из встроенного представления a
в таблицу, а затем переписать запросвыше, чтобы заменить встроенное представление a
ссылкой на таблицу кеша.
CREATE TABLE calc_stats_n_days
( codigowine <datatype> PRIMARY KEY
, avg_30_day DOUBLE
, max_30_day DOUBLE
, min_30_day DOUBLE
, avg_15_day DOUBLE
, ...
Для начальной совокупности ...
INSERT INTO calc_stats_n_days
( codigowine, avg_30_day, maxg_30_day, min_30_day, avg_15_day, ... )
SELECT h.codigowine
, AVG(IF( h.timestamp >= CURRENT_DATE + INTERVAL -30 DAY, h.preconormal, NULL)) AS avg_30_day
, MAX(IF( h.timestamp >= CURRENT_DATE + INTERVAL -30 DAY, h.preconormal, NULL)) AS max_30_day
, MIN(IF( h.timestamp >= CURRENT_DATE + INTERVAL -30 DAY, h.preconormal, NULL)) AS min_30_day
, AVG(IF( h.timestamp >= CURRENT_DATE + INTERVAL -15 DAY, h.preconormal, NULL)) AS avg_15_day
, ...
Для текущей синхронизации, я бы, вероятно,создайте временную таблицу, заполните ее тем же запросом, а затем выполните синхронизацию между временной таблицей и целевой таблицей. Может быть INSERT ... ON DUPLICATE KEY
и DELETE
анти-объединение (для удаления старых строк).