Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 在子查询中,快速查询速度会减慢_Mysql_Sql_Subquery - Fatal编程技术网

Mysql 在子查询中,快速查询速度会减慢

Mysql 在子查询中,快速查询速度会减慢,mysql,sql,subquery,Mysql,Sql,Subquery,我有一个疑问: 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 WH

我有一个疑问:

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,device中的PK也是它的id。devicelog上有一个timestmp的索引,它是日期时间和设备id,也是返回devicelog的FK。还有其他的索引,但它们是不相关的东西,如名称、描述等

我只需要它在设备中循环,然后显示最后的时间戳记录

如果我在PHP中列出每个设备,然后分别执行第一个查询,它的性能会非常好,但我希望在一个完整的查询中执行。比如,我可以做一些类似伪代码的事情:

foreach($row in <devicelog>)
   query('<first query> where id = $row[id]')

在devicelog上执行整个连接的成本太高,因为计数太高。

尝试使用内部连接

  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

列出所有设备,您可以考虑通过

  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`)

根据对第一个答案的评论,您的问题和查询与您要查找的内容不匹配

你可以做的是对每个设备进行预聚合,以获得最大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别名中获取任何其他列

另外,对于您的设备日志表,我会在设备id上有一个覆盖索引,timestamp

反馈意见

然后我会给你一个建议,这在web开发领域也是很常见的,当有人需要最高数量、大部分内容或最新的内容时

仅从一个方面取消设备表的规格化。。。为LastDeviceLogID添加一列。然后,每当您的DeviceLog添加了一个条目时,您只需使用一个后插入触发器即可

update Device 
   set LastDeviceLogID = newRecord.DeviceLogID
   where ID = newRecord.Device_ID
列可能不精确,但原则是存在的。这样,你就不需要做一个极限1,MAX,等等,并且浏览你的数百万条记录,你可以像做一样简单

SELECT 
      d.name,
      d.id,
      dl.timestamp,
      dl.othercolumns
   from
      device d
         LEFT JOIN devicelog dl
            on d.LastDeviceLogID = dl.DeviceLogID

这对于设备中的一行是可以的,但我需要列出所有设备以及最后一条devicelog记录。由于限制1,仍然只返回1行。不幸的是,大约花费了6.5秒。此查询非常简单。你能展示你的解释表吗?这都是基于对他的问题的误解,而不是根据他对你以上答案的第一次评论,他们想要什么。尝试了一下,大约需要7秒钟。设备id PK和时间戳上有几个索引。@RalphWiggum,非规范化技术的修订答案是的,我认为插入触发器是最好的方法,但试图避免使用插入触发器。