SQL: уменьшить набор результатов до X строк? - PullRequest
0 голосов
/ 26 января 2020

У меня есть следующая таблица MYSQL:

measuredata:
- ID (bigint)
- timestamp
- entityid
- value (double)

Таблица содержит> 1 миллиард записей. Я хочу иметь возможность визуализировать любое временное окно. Временное окно может быть размером от одного дня до многих лет. В БД примерно каждую минуту измеряются значения.

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

Эти значения должны отображаться в графической диаграмме-диаграмме на веб-странице.

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

Итак, есть ли способ уменьшить набор результатов непосредственно на стороне DB? Я знаю "среднее" и "сумма" и т. Д. c. как агрегатная функция. Но как я могу агрегировать 100 тыс. Строк из большого временного окна, чтобы, скажем, 800 последних строк?

Просто получить эти 100 тыс. Строк и позволить диаграмме выполнить волхвы c не является предпочтительным вариантом. Размер переноса - одна из причин, по которой это невозможно.

Нет ли на стороне БД чего-либо, что я могу использовать? Что-то вроде avg () для сокращения X строк до Y усредненных строк? Или просто волшебный c, чтобы просто пропустить каждую #-ю строку, чтобы уменьшить X до Y?

обновление: хотя я сейчас использую MySQL, я не привязан к этому. Если PostgreSQL fi предоставляет функцию, которая может решить проблему, я готов сменить БД.

update2: возможно, я нашел возможное решение: https://mike.depalatis.net/blog/postgres-time-series-database.html См. Раздел «Агрегация данных».

Ключ не в том, чтобы использовать метку unixtime, а дату и « trun c "it, отредактируйте значения и сгруппируйте их по дате редактирования trun c. Может работать для меня, но потребует переделки моей структуры таблицы. Хм ... может быть, еще кое-что ... все еще исследую ...

update3: Вдохновленный обновлением 2, я пришел с этим запросом:

SELECT (`timestamp` - (`timestamp` % 86400)) as aggtimestamp, `entity`, `value`  FROM `measuredata` WHERE `entity` = 38 AND timestamp > UNIX_TIMESTAMP('2019-01-25') group by aggtimestamp

Работает, но моя БД / Кажется, что индекс / структура не очень оптимизированы для этого: запрос за прошлый год занял ~ 75 с c (медленный тестовый компьютер), но в итоге получил только одно значение в день. Это может быть объединено с avg (value), но это еще больше увеличивает время запроса ... (~ 82se c). Я посмотрю, можно ли еще оптимизировать это. Но теперь у меня есть идея, как работает «понижающая выборка» данных, особенно с агрегацией в сочетании с «группированием по».

1 Ответ

0 голосов
/ 26 января 2020

Вероятно, нет эффективного способа сделать это. Но, если вы хотите, вы можете разбить строки на группы одинакового размера, а затем извлечь, скажем, первый ряд из каждой группы. Вот один из методов:

select md.*
from (select md.*,
             row_number() over (partition by tile order by timestamp) as seqnum
      from (select md.*, ntile(800) over (order by timestamp) as tile
            from measuredata md
            where . . .   -- your filtering conditions here
           ) md
     ) md
where seqnum = 1;
...