表格:
id | date | id_device | total | others 15/20 columns
----------------------------------------------------
我需要计算特定时间间隔内某天特定设备的每小时消耗量。
为此,我有一个查询,有效。 例如:2018-10-03,间隔时间为00-01。此间隔意味着(以及所有其他间隔)从00之前的最后一条记录开始,一直到00的最后一条记录结束。因此,像上面的示例一样,00间隔的总数为300-120, 300 (最后一条记录为00) 120 (最后一条记录在00之前)。 减法是在PHP中完成的。
id | date | id_device | total | others 15/20 columns
----------------------------------------------------
1 | 2018-10-02 23:50:20 | 1 | 100 | ....
2 | 2018-10-02 23:55:20 | 1 | 120 | ....
3 | 2018-10-03 00:01:20 | 1 | 150 | ....
.. | 2018-10-03 00:59:20 | 1 | 300 | ....
.. | 2018-10-03 01:00:20 | 1 | 350 | ....
SELECT `total` AS `total` FROM `mytable` AS `A`,
(
SELECT MIN(`date`) AS `firstValue`, MAX(`date`) AS `lastValue`
FROM `mytable`
WHERE `date` BETWEEN
COALESCE((SELECT `date` FROM `mytable` WHERE `date` < '2018-10-03 00:00:00' AND `id_device` = 1 ORDER BY `date` DESC LIMIT 1), '2018-10-03 00:00:00'
AND '2018-10-03 00:59:59'
AND `id_device` = 1
) AS `B`
WHERE `A`.`date` IN (`B`.`firstValue`,`B`.`lastValue`) AND `id_device` = 1
ORDER BY `A`.`date`
使用此查询,执行时间约为 0.9 / 1.5秒。而且太慢了(我必须为每个设备循环计算X次此查询)。
删除子查询,执行时间为实际上为0 。执行时间是完美的,但是这种方式的查询显然不适合我。
SELECT `total` AS `total` FROM `mytable` AS `A`,
(
SELECT MIN(`date`) AS `firstValue`, MAX(`date`) AS `lastValue`
FROM `mytable`
WHERE `date` BETWEEN
'2018-10-03 00:00:00'
AND '2018-10-03 00:59:59'
AND `id_device` = 1
) AS `B`
WHERE `A`.`date` IN (`B`.`firstValue`,`B`.`lastValue`) AND `id_device` = 1
ORDER BY `A`.`date`
我分别测试了子查询,执行时间为实际上为0 。
SELECT `date` FROM `mytable` WHERE `date` < '2018-10-03 00:00:00' AND `id_device` = 1 ORDER BY `date` DESC LIMIT 1
所以我不明白为什么原始查询这么慢。
答案 0 :(得分:0)
我认为,如果您可以在
中逻辑上设置较低的日期范围(例如5天前或30天前,取决于您的问题)SELECT `date` FROM `mytable` WHERE `date` < DATE_FORMAT('2018-10-03 00:00:00', '%Y-%m-%d %H:%i:%s') AND `id_device` = 1 ORDER BY `date` DESC LIMIT 1
可以在合理的时间内得到响应
答案 1 :(得分:0)
反转查询的层次结构(使外部查询成为子查询),或者最好还是使用联接。
如果可能的话,在加入和过滤时,尝试(显然是船长)使用索引字段。
在变量中为where
设置日期,并使用变量代替dateformat。否则,实际上将为每一行计算该查询,这会大大降低查询速度。
答案 2 :(得分:0)
我将从将子查询移至FROM
子句开始:
SELECT `total` AS `total`
FROM `mytable` AS `A`CROSS JOIN
(SELECT MIN(t2.`date`) AS `firstValue`, MAX(t2.`date`) AS `lastValue`
FROM `mytable` t2 CROSS JOIN
(SELECT t3.`date`
FROM `mytable` t3
WHERE t3.`date` < '2018-10-03' AND t3.`id_device` = 1
ORDER BY t3.`date` DESC
LIMIT 1
) d
WHERE t2.date >= COALESCE(d.date, '2018-10-03') AND
t2.date < '2018-10-04' AND
t2.id_device = 1
) B
WHERE `A`.`date` IN (B.firstValue, B.lastValue) AND
A.`id_device` = 1
ORDER BY `A`.`date`;
对于此查询,我将从mytable(id_device, date)
上的索引开始。
我也建议使用索引,但是您指出基本查询运行很快。因此,不需要其他索引。
您可能还可以使用union all
简化逻辑。