SQL запрос для наиболее эффективного выбора средней температуры для нескольких записей за последние 24 часа - PullRequest
0 голосов
/ 04 мая 2020

У меня есть следующая таблица (sensor_temps), в которой хранятся значения температуры, измеряемые каждые 5 минут для сотен датчиков:

id  |  mac_addr          |  temp  |  updated
--------------------------------------------------------
3   | 16:8C:DD:7B:DA:1B  |  76    |  2020-05-03 11:31:06

У меня есть другая таблица (датчики), в которой хранятся данные для каждого датчика:

id  |  mac_addr          |  IP                 |  location_id
--------------------------------------------------------------
43  | 16:8C:DD:7B:DA:1B  |  xxx.xxx.xxx.xxx    |  ca-ab-sub-46

Запрос 1: Мне нужно построить график средней температуры во всех точках часа за последние 24 часа.

Запрос 2: Мне также нужно составить график средней температуры для каждого местоположения в час за последние 24 часа.

На данный момент я могу получить число показаний температуры, усредненных за час, используя:

SELECT HOUR(`updated`), COUNT(*), ROUND(AVG(`temp`))
FROM `sensor_temps`
WHERE `updated` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY HOUR(`updated`)
ORDER BY HOUR(`updated`)

Это самый эффективный способ сделать это?

Для запроса 2 я планирую сделать что-то вроде следующего:

SELECT HOUR(`updated`), COUNT(*), ROUND(AVG(`temp`))
FROM `sensor_temps`
WHERE `updated` > DATE_SUB(NOW(), INTERVAL 24 HOUR) AND `location_id` = `ca-ab-sub-46`
GROUP BY HOUR(`updated`)
ORDER BY HOUR(`updated`)

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

1 Ответ

0 голосов
/ 04 мая 2020

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

Допущения: однажды вставленные данные не изменились. То есть, когда они будут готовы, много.

Общая рекомендация для Datamodel:

  1. Создать два новые таблицы для хранения агрегированного значения из запроса 1 и запроса 2. Целью является хранение агрегированных данных, которые могут быть прочитаны GUI довольно быстро, а не агрегирование в реальном времени. В таблице должны быть все столбцы из соответствующих запросов select ( Запрос 1 и Запрос 2).
  2. Две таблицы должны быть заполнены к концу дня (после 00:00 следующего дня), используя запланированное задание. В основном сценарий вставки в insert into newtablequery1 select .. from query1. Аналогичным образом для запроса 2 требуется сценарий вставки.
  3. GUI для извлечения данных из этих новых таблиц для дат, отличных от текущего дня. Это будет потрясающе быстро.
  4. Теперь для текущей даты мы должны полагаться на предоставленные запросы (предложение по улучшению запросов можно найти чуть ниже в ветке). Эти предложения остаются в силе, когда 1,2 и 3 не являются жизнеспособными. Ниже приведено несколько улучшений:

    • Добавление неуникального индекса sensor_temps в обновленном столбце.
    • Разделение по месяцам Год для более быстрого поиска данных с растущими данными. Это несущественно, но может иметь значение, возможно, через пару лет.
    • Добавление уникального индекса для location_id улучшит запрос 2.
    • sensor.id должен быть первичным ключом и, следовательно, будет проиндексирован по умолчанию.

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

SELECT * FROM 
(SELECT HOUR(`updated`) AS hr, COUNT(*) as cnt , ROUND(AVG(`temp`)) as avgtemp
FROM `sensor_temps`
WHERE `updated` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY HOUR(`updated`)) sensor_temps_avg
ORDER BY hr

Запрос 2. Изменен запрос для создания встроенного представления из sensor_temps с агрегатом и последующего объединения с датчиками, что уменьшит таблицу ha sh, сформированную объединением.

select id,location_id,hr,cnt,avgtemp
from sensors,
(SELECT id,HOUR(`updated`) as hr, COUNT(*) as cnt, ROUND(AVG(`temp`)) as avgtemp
FROM `sensor_temps`
WHERE `updated` > DATE_SUB(NOW(), INTERVAL 24 HOUR) 
GROUP BY HOUR(`updated`)) sensor_temps_avg
where sensors.id = sensor_temps_avg.id
AND `location_id` = `ca-ab-sub-46`
ORDER BY HR

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

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