Как ускорить этот медленный запрос - PullRequest
0 голосов
/ 31 августа 2018

Я спроектировал базу данных MySQL и загрузил некоторые данные (всего около 10 миллионов строк). Я пытаюсь получить данные из двух таблиц, где временные интервалы перекрываются.

SELECT 
        cd.ParameterID,
        intervals.TimeStamp,
        intervals.GreenHouseID,
        intervals.TargetParam,
        intervals.ProductionID
FROM
        (
                SELECT 
                        pd.TimeStamp, 
                        p.GreenHouseID, 
                        pd.ParameterID AS TargetParam, 
                        pd.ProductionID
                FROM 
                        Production p INNER JOIN 
                        ProductionData pd ON pd.ProductionID=p.ID
                GROUP BY
                        pd.TimeStamp, p.GreenHouseID
        ) AS intervals,
    ClimateData cd
WHERE
        DATE_FORMAT(intervals.TimeStamp,'%Y-%m-%d') = DATE_FORMAT(cd.Time_stamp,'%Y-%m-%d') AND
        cd.GreenHouseID = intervals.GreenHouseID
GROUP BY
        intervals.ProductionID, intervals.TargetParam

К сожалению, запрос занимает слишком много времени (я еще не видел его завершенным).

Когда я использую EXPLAIN, я получаю следующий результат:

|id|select_type|table     |partitions|type |possible_keys|key          |key_len|ref                   |rows|filtered|Extra
|1|PRIMARY     |<derived2>|NULL      |ALL  |NULL         |NULL         |NULL   |NULL                  | 416|  100.00|Using where Using temporary
|1|PRIMARY     |cd        |NULL      |ref  |cd_ghid_idx  |cd_ghid_idx  |4      |intervals.GreenHouseID|1660|  100.00|Using where       
|2|DERIVED     |p         |NULL      |index|PRIMARY      |pr_gh_fk_idx |5      |NULL                  |  13|  100.00|Using index Using temporary
|2|DERIVED     |pd        |NULL      |ref  |pd_pr_fk_idx |pd_pr_fk_idx |5      |ghdb.p.ID             |  32|  100.00|NULL 

Я полагаю, что я ставлю индексы на все соответствующие столбцы, чтобы обеспечить быстрый запрос. Однако разработанный мной запрос использует временную таблицу (intervals). Это снижает производительность? Если так, как разработать более быстрый запрос?

Сервер MySQL находится на моем ноутбуке (16 ГБ ОЗУ, процессор E3-1505M v5). Я не сделал никаких изменений в настройке MySQL. Это было бы полезно?

Я бы хотел получить результат запроса за приемлемое время (через несколько минут все будет в порядке).

Спасибо.

1 Ответ

0 голосов
/ 12 сентября 2018
  • Пожалуйста, укажите SHOW CREATE TABLE для каждой таблицы, включая временную таблицу.
  • Похоже, что для временной таблицы существует индекс из одного столбца?
  • Температура по сравнению с постоянной должна иметь значение в производительности. Однако дополнительный шаг для создания временной таблицы может потребовать дополнительных затрат.
  • Скажите NOT NULL, где это необходимо.
  • Скрытие столбца в вызове функции (DATE_FORMAT в вашем случае) предотвращает использование индекса - следовательно, ALL.
  • Вы не можете «настроить выход из проблемы с производительностью», поэтому я не буду касаться настройки, кроме как задать значение innodb_buffer_pool_size.
  • Пожалуйста, не используйте "comma-join"; вместо этого используйте JOIN .. ON ..

Основная проблема производительности здесь:

WHERE DATE_FORMAT(intervals.TimeStamp,'%Y-%m-%d') = 
      DATE_FORMAT(cd.Time_stamp,'%Y-%m-%d')
  AND cd.GreenHouseID = intervals.GreenHouseID

Это должно выглядеть как

WHERE intervals.TimeStamp ...
  AND cd.GreenHouseID = intervals.GreenHouseID

Поскольку вы собираетесь построить intervals на лету, есть столбец, который содержит только дату. И вы можете также вычислить его через DATE(...) вместо DATE_FORMAT(...).

Поскольку вы вычисляете одну из дат, измените pd.TimeStamp на

    DATE(pd.TimeStamp) AS TS_Date

Тогда

WHERE intervals.TimeStamp >= cd.TS_Date
  AND intervals.TimeStamp  < cd.TS_Date + INTERVAL 1 DAY
  AND intervals.GreenHouseID = cd.GreenHouseID

Вам также понадобится вместе с этим «составным» индексом для intervals:

INDEX(GreenHouseID, TimeStamp) -- in this order

Ошибка осталась: я вижу GROUP BY pd.TimeStamp, ...; это не имеет смысла, поэтому я игнорирую это.

...