MySQL и MariaDB не имеют необходимой специфики, но сводные таблицы - это путь. Но сначала ...
mysql> SELECT NOW() - INTERVAL 30 DAY;
+-------------------------+
| NOW() - INTERVAL 30 DAY |
+-------------------------+
| 2019-03-10 11:48:24 |
+-------------------------+
Вы действительно хотите охватить 30-дневный период, начинающийся с некоторой секунды ? Обычно люди хотят всего 30 полных дней:
WHERE ts >= CURDATE() - INTERVAL 30 DAY
AND ts < CURDATE();
mysql> SELECT CURDATE() - INTERVAL 30 DAY, CURDATE();
+-----------------------------+------------+
| CURDATE() - INTERVAL 30 DAY | CURDATE() |
+-----------------------------+------------+
| 2019-03-10 | 2019-04-09 |
+-----------------------------+------------+
1 row in set (0.00 sec)
или даже соблюдать месяцы переменной длины:
WHERE ts >= CURDATE() - INTERVAL 1 MONTH
AND ts < CURDATE();
mysql> SELECT CURDATE() - INTERVAL 1 MONTH, CURDATE();
+------------------------------+------------+
| CURDATE() - INTERVAL 1 MONTH | CURDATE() |
+------------------------------+------------+
| 2019-03-09 | 2019-04-09 |
+------------------------------+------------+
Если вы готовы смотреть только на целые дни, создание и ведение сводной таблицы (в виде материализованного представления) легко и очень эффективно:
CREATE TABLE SummaryXY (
x ...,
y ...,
dy DATE,
ct INT UNSIGNED,
PRIMARY KEY(x,y,dy)
) ENGINE=InnoDB;
У вас будет работа по добавлению новых строк сразу после полуночи каждую высоту.
Если, с другой стороны, вам нужно идти до текущей секунды, обновление может осуществляться через IODKU (INSERT ... ON DUPLICATE KEY UPDATE...
), который по мере необходимости позаботится об обновлении или вставке.
Если вам нужно вернуться к часам, а не дням, измените dy
. Но если вам действительно нужно вернуться к произвольной секунде, то выполните задачу в 2 этапа:
SELECT
( SELECT COUNT(*) FROM RawData WHERE ... (the partial day 30 days ago) ) +
( SELECT SUM(ct) FROM SummaryXY WHERE ... (the 30 full days) );
(И иметь дело с неполным текущим днем либо по IODKU, либо по аналогии SELECT COUNT(*) FROM RawDATA
.)
Был ли ваш простой пример настолько сложным, насколько вам нужно? То, что я описываю, будет хорошо работать для X=constant AND y=constant AND ts...
, но не для X>constant
и т. Д.
Если вам нужно AVG(value)
, то сохраните COUNT(*)
(как указано выше) и SUM(VALUE)
. Тогда это дает вам среднее значение:
SUM(value_sum) / SUM(ct)
Если вам также нужно WHERE x=1 AND w=2 AND ts...
, то создайте вторую сводную таблицу на основе x,w,ts
.
Если вам также нужно WHERE x=1 AND y=1 AND z=3 AND ts...
, то создайте сводную таблицу на основе x,y,z,ts
, но используйте ее для x,y,ts
. Возможно типичным является 5 сводных таблиц для 40 случаев.
Дополнительные обсуждения сводных таблиц: http://mysql.rjweb.org/doc.php/summarytables
Ваш второй запрос (GROUP BY X, Y ORDER BY COUNT(*) DESC
) в настоящее время выполняет сканирование таблицы большой таблицы Raw, даже если вы индексировали ts
. С моей предлагаемой сводной таблицей запрос будет представлять собой таблицу из сводной таблицы. Поскольку это может быть в 10 раз меньше, сканирование таблицы будет значительно быстрее.
Дополнительная сортировка по COUNT(*)
это незначительное бремя; это зависит от количества строк в наборе результатов.