MySQL - медленный запрос при получении данных предыдущей строки

0

У меня есть этот запрос, который занимает 0.04 секунды для загрузки

SELECT sg.Name AS 'Customer Name', 
m.meter_id AS 'Serial No', 
DATE_FORMAT(datetime, '%Y/%m/%d') AS Date,  
MAX(wh_total) AS Present
FROM meter_data m 
INNER JOIN enrollment e 
ON e.Meter_Id = m.meter_id AND e.Status = 1 
INNER JOIN company_subgroup sg 
ON sg.Id = e.Subgroup_Id 
INNER JOIN company_group g 
ON g.Id = sg.Group_Id 
WHERE date(dateTime) BETWEEN '2018/06/01' AND '2018/06/30' 
AND m.meter_id = '12345' 
AND m.wh_total < 1000000000 
GROUP BY date(datetime)

Но если я добавил этот столбец "Предыдущий", для выполнения потребуется около 20 секунд.

SELECT sg.Name AS 'Customer Name', 
m.meter_id AS 'Serial No', 
DATE_FORMAT(datetime, '%Y/%m/%d') AS Date, 
// THIS (main issue)
COALESCE((SELECT MAX(wh_total) FROM meter_data WHERE date(dateTime) < date(m.dateTime) AND meter_id = '12345' 
AND wh_total < 1000000000 GROUP BY date(dateTime) ORDER BY date(dateTime) DESC LIMIT 1),0) AS Previous,
//
MAX(wh_total) AS Present,
// THIS (But I guess this does not affect the query that much since it only substract the two columns) 
ROUND(MAX(wh_total) - MIN((SELECT Previous)),2) AS Consumption 
//
FROM meter_data m 
INNER JOIN enrollment e 
ON e.Meter_Id = m.meter_id AND e.Status = 1 
INNER JOIN company_subgroup sg 
ON sg.Id = e.Subgroup_Id 
INNER JOIN company_group g 
ON g.Id = sg.Group_Id 
WHERE date(dateTime) BETWEEN '2018/06/01' AND '2018/06/30' 
AND m.meter_id = '12345' 
AND m.wh_total < 1000000000 
GROUP BY date(datetime)

В основном, столбец Previous получает данные предыдущей строки. Запрос выглядит примерно так:

Customer Name | Serial No | Date       | Previous | Present | Consumption
ABC           | 12345     | 06/01/2018 | 0        | 1       | 1
ABC           | 12345     | 06/02/2018 | 1        | 3       | 2
ABC           | 12345     | 06/03/2018 | 3        | 8       | 5 
ABC           | 12345     | 06/04/2018 | 8        | 10      | 2 

Я попытался использовать LAG (столбец) для получения данных предыдущих строк, к сожалению, версия MySQL - 5.6. Есть ли способ оптимизировать этот запрос?

  • 0
    Используйте самостоятельное соединение вместо подзапроса.
  • 0
    См. Meta.stackoverflow.com/questions/333952/…
Теги:

2 ответа

0

Попробуйте этот запрос. это сохранение предыдущих данных в пользователе var.

Я изменил его снова. Функция MAX получила ошибку. поэтому я поставил его в подзапрос.

SELECT r.'Customer NAME', r.'SERIAL NO', r.'DATE' , @prev AS Previous , @reav := r.'Present'
FROM (
    SELECT sg.Name AS 'Customer NAME', 
    m.meter_id AS 'SERIAL NO', 
    DATE_FORMAT(DATETIME, '%Y/%m/%d') AS 'DATE',  
    MAX(wh_total) AS 'Present'
    FROM meter_data m 
    INNER JOIN enrollment e 
    ON e.Meter_Id = m.meter_id AND e.Status = 1 
    INNER JOIN company_subgroup sg 
    ON sg.Id = e.Subgroup_Id 
    INNER JOIN company_group g 
    ON g.Id = sg.Group_Id 
    WHERE DATE(DATETIME) BETWEEN '2018/06/01' AND '2018/06/30' 
    AND m.meter_id = '12345' 
    AND m.wh_total < 1000000000 
    GROUP BY DATE(DATETIME)
) AS r
CROSS JOIN (SELECT @prev:=0) AS INIT;
  • 0
    я изменил свой ответ, чтобы исправить ошибки 2 SQL опечатка
  • 0
    Почему @prev для Previous всегда 0?
Показать ещё 3 комментария
0

Попробуй это

SELECT sg.Name AS 'Customer Name', 
        m.meter_id AS 'Serial No', 
        DATE_FORMAT(datetime, '%Y/%m/%d') AS Date, 
        COALESCE(mx.max_total,0) AS Previous,
        MAX(wh_total) AS Present,
        ROUND(MAX(wh_total) - MIN((mx.max_total)),2) AS Consumption 
FROM meter_data m 
        INNER JOIN enrollment e ON e.Meter_Id = m.meter_id AND e.Status = 1 
        INNER JOIN company_subgroup sg ON sg.Id = e.Subgroup_Id 
        INNER JOIN company_group g ON g.Id = sg.Group_Id 
        LEFT JOIN (SELECT date(dateTime) as dt,  MAX(wh_total) max_total
                    FROM meter_data 
                    WHERE meter_id = '12345' AND wh_total < 1000000000 
                    GROUP BY date(dateTime)) mx on mx.dt < date(m.dateTime)
WHERE date(m.dateTime) BETWEEN '2018/06/01' AND '2018/06/30' 
AND m.meter_id = '12345' 
AND m.wh_total < 1000000000 
GROUP BY date(m.datetime)

Примечание: если эта строка возвращает более одной строки, то ограничивайте это, добавив еще некоторое условие

  • 0
    Этот запрос занял 0,8 секунды, но все предыдущие строки возвращают одно и то же значение. Я постараюсь посмотреть на это. Может быть, только некоторые условия.
  • 0
    Я почти там, но я не могу сослаться на дату (m.dateTime) из meter_data внутри подзапроса. Я хотел сделать '.. AND wh_total <1000000000 AND dt <date (m.dateTime)' внутри подзапроса. Если я поставлю его в состояние ON, он просто вернет значение NULL.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню