我有这个问题:
SELECT timestmp
FROM devicelog
WHERE device_id = 5
ORDER BY id DESC LIMIT 1
获取时间不到0.001秒,但是一旦我将它放入子查询中,它就会减慢到大约3.05秒。有什么理由为什么会这样做,或者我如何解决它?
这是第二个查询(我想要优化的那个):
SELECT device.id,
(SELECT timestmp
FROM devicelog
WHERE device_id = device.id
ORDER BY id DESC LIMIT 1) as timestmp
FROM device
表“设备”只有10-15条记录(devicelog有几百万条记录),所以我假设每条记录逐一进行,然后执行子查询,但显然它正在做其他事情。 devicelog的PK是id,设备中的PK也是id。对于timestmp
(这是一个日期时间)和device_id
的devicelog有一个索引,它也是一个返回到devicelog的FK。还有其他指数,但它们无关紧要(如名称,描述等)。
我只需要循环浏览设备,然后显示最后一个时间戳记录。
如果我在PHP中列出每个设备,然后单独执行第一个查询,它将表现得非常好,但我想在一个完整的查询中执行此操作。就像,我可以做一些像(伪代码):
foreach($row in <devicelog>)
query('<first query> where id = $row[id]')
在devicelog上进行整个连接太昂贵了,因为计数很高。
答案 0 :(得分:1)
使用内部联接
尝试此操作 SELECT d.id, dl.timestamp
FROM device d
INNER JOIN devicelog dl
ON dl.device_id = d.id
ORDER BY d.id DESC LIMIT 1
列出您可能认为是GROUP BY的所有设备
SELECT d.id, dl.timestamp
FROM device d
INNER JOIN devicelog dl
ON dl.device_id = d.id
GROUP BY d.id
ORDER BY d.id DESC
编辑:
如果你有很多索引,最好索引你的列id
试试这个
ALTER TABLE `device` ADD INDEX `id` (`id`)
答案 1 :(得分:1)
根据提供的第一个答案的评论,您的问题和查询与您要查找的内容不符。
您可以做的是在每台设备上进行预聚合以获取最大ID日志,然后将其加入您的主设备列表......
SELECT
d.name,
d.id,
DeviceMax.lastTime
from
device d
LEFT JOIN ( select dl.device_id,
max( dl.timestamp ) lastTime
from
devicelog dl
group by
dl.device_id ) as DeviceMax
ON d.id = DeviceMax.device_id
现在,如果您需要从设备日志中获取该特定条目的其他内容,我们可以添加到该...
LEFT JOIN devicelog dl2
on DeviceMax.Device_id = dl2.Device_id
AND DeviceMax.lastTime = dl2.timestamp
然后您可以将“dl2”别名中的任何其他列添加到您的查询中。
另外,对于你的设备日志表,我会有一个覆盖索引(device_id,timestamp)
来自反馈的评论
然后我会提出这个作为对你的建议,当有人需要“最高数量”或“大多数”某事或“最近”等等时,这在网络开发领域也很常见。
仅使用一个方面对您的Device表进行非规范化...为LastDeviceLogID添加一列。然后,只要您的DeviceLog添加了一个条目,您就可以使用后插入触发器来执行...
update Device
set LastDeviceLogID = newRecord.DeviceLogID
where ID = newRecord.Device_ID
列可能不准确,但原则就在那里。通过这种方式,您永远不需要执行LIMIT 1,MAX()等操作并查看数百万条记录,您可以像执行一样简单地进行操作
SELECT
d.name,
d.id,
dl.timestamp,
dl.othercolumns
from
device d
LEFT JOIN devicelog dl
on d.LastDeviceLogID = dl.DeviceLogID