MySQL Месяц и год группировка медленная производительность - PullRequest
2 голосов
/ 19 марта 2020

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

SELECT MONTH(MT4_TRADES.CLOSE_TIME) as MONTH
     , YEAR(MT4_TRADES.CLOSE_TIME) as YEAR
     , SUM(MT4_TRADES.SWAPS) as SWAPS
     , SUM(MT4_TRADES.VOLUME)/100 as VOLUME
     , SUM(MT4_TRADES.PROFIT) AS PROFIT 
  FROM MT4_TRADES 
  JOIN MT4_USERS 
    ON MT4_TRADES.LOGIN = MT4_USERS.LOGIN 
 WHERE MT4_TRADES.CMD < 2  
   AND MT4_TRADES.CLOSE_TIME <> "1970-01-01 00:00:00" 
   AND MT4_USERS.AGENT_ACCOUNT <> "1" 
 GROUP 
    BY YEAR(MT4_TRADES.CLOSE_TIME)
     , MONTH(MT4_TRADES.CLOSE_TIME) 
 ORDER 
    BY YEAR

Это полный запрос, любое предложение будет высоко оценено.

Это результат объяснения:

enter image description here

1 Ответ

1 голос
/ 19 марта 2020

Повторяя комментарий от @Barmar, посмотрите на вывод EXPLAIN, чтобы увидеть план выполнения запроса. Убедитесь, что используются подходящие индексы.

Вероятно, большой камень производительности - это операция "Использование сортировки файлов".

Чтобы обойти это, нам нужен подходящий доступный индекс. и это потребует некоторых изменений в таблице. (Типичный вопрос об «улучшении производительности запросов» topi c в SO имеет ограничения, которые мы «не можем добавлять индексы или вносить какие-либо изменения в таблицу».)

Я бы посмотрел функциональный индекс (функция добавлена ​​в MySQL 8.0, для MySQL 5.7, я бы посмотрел на добавление сгенерированных столбцов и включение сгенерированных столбцов во вторичный индекс, функция добавлена ​​в MySQL 5.7)

CREATE INDEX `MT4_TRADES_ix2` ON MT4_TRADES ((YEAR(close_time),MONTH(close_time))

Я бы соблазнился go с индексом покрытия, а также изменил бы группировку на одно выражение, например DATE_FORMAT(close_time,'%Y-%m')

CREATE INDEX `MT4_TRADES_ix3` ON MT4_TRADES ((DATE_FORMAT(close_time,'%Y-%m')
  ,swaps,volume,profit,login,cmd,closetime)

из запроса, похоже, что login is будет УНИКАЛЬНЫМ в таблице MT4_USERS, вероятно, это ПЕРВИЧНЫЙ КЛЮЧ или УНИКАЛЬНЫЙ КЛЮЧ, поэтому индекс будет доступен, но мы просто предполагаем ...

С подходящими доступными индексами мы может так что-то вроде этого:

SELECT DATE_FORMAT(close_time,'%Y-%m')                                    AS close_year_mo
     , SUM(IF(t.cmd < 2 AND t.close_time <> '1970-01-01', t.swaps  ,NULL))      AS swaps
     , SUM(IF(t.cmd < 2 AND t.close_time <> '1970-01-01', t.volume ,NULL))/100  AS volume
     , SUM(IF(t.cmd < 2 AND t.close_time <> '1970-01-01', t.profit ,NULL))      AS profit 
  FROM MT4_TRADES t
  JOIN MT4_USERS u
    ON u.login = t.login 
   AND u.agent_account <> '1' 
 GROUP BY close_year_mo
 ORDER BY close_year_mo

, и мы ожидаем, что MySQL выполнит свободное сканирование индекса, с выводом EXPLAIN top show "использующий индекс для группировки", а не шоу " Использование сортировки файлов "


РЕДАКТИРОВАТЬ

* 10 29 * Для версий MySQL до 5.7 мы могли бы создать новые столбцы, например, year_close и month_close, заполнить столбцы результатами выражений YEAR(close_time) и MONTH(close_time) (мы могли бы создать BEFORE INSERT и BEFORE UPDATE запускает автоматическую обработку этого для нас)

Затем мы можем создать индекс с этими столбцами в качестве ведущих столбцов

 CREATE INDEX ...  ON MT4_TRADES ( year_close, month_close, ... )

И затем ссылаться на новые столбцы в запросе

SELECT t.year_close  AS `YEAR`
     , t.month_close  AS `MONTH`

  FROM MT4_TRADES t
  JOIN ...
 WHERE ...
 GROUP
    BY t.year_close
     , t.month_close

В идеале включать в индекс все ссылочные столбцы из MT4_TRADES, чтобы покрывал индекс для запроса.

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