Mysql 使用MIN/MAX的查询作为子查询比单独查询慢得多

Mysql 使用MIN/MAX的查询作为子查询比单独查询慢得多,mysql,sql,mariadb,Mysql,Sql,Mariadb,考虑对一个大约有1M行的表执行以下查询。 结构在最后。TL;DR:它有唯一的键“max\u filter”`id\u chat`、`id\u device`、`id\u message` 选择MAX`id\u消息` 从“消息”键` 其中'id\u chat`=94609 和'id_device`=26664 和'id\u message`子查询会导致MySQL创建临时表。改为使用设备表的联接: SELECT MAX(a.id_message) FROM message_keys a JOIN d

考虑对一个大约有1M行的表执行以下查询。 结构在最后。TL;DR:它有唯一的键“max\u filter”`id\u chat`、`id\u device`、`id\u message`

选择MAX`id\u消息` 从“消息”键` 其中'id\u chat`=94609 和'id_device`=26664
和'id\u message`子查询会导致MySQL创建临时表。改为使用设备表的联接:

SELECT MAX(a.id_message)
FROM message_keys a
JOIN devices b
    ON a.device_id = b.id
WHERE a.id_chat = 94609
    AND a.id_device = 26664
    AND a.id_message <= 238798
    AND b.id_user = 1;
对于此查询:

SELECT (SELECT MAX(mk.id_message)
        FROM message_keys mk
        WHERE mk.id_chat = 94609 AND
              mk.id_device = d.id AND
              mk.id_message <= 238798
       ) as max
FROM devices d
WHERE d.id_user = 1;
最佳索引为设备id_用户、id和消息id_密钥id_设备、id_聊天、id_消息


特别是,第一个查询可以为查询选择三个单列索引中的任意一个。第二,它必须使用设备上的id,这可能不是查询的最佳索引。

如果按键分组,会发生什么

SELECT (
SELECT MAX(id_message)
FROM message_keys
WHERE message_keys.id_chat = 94609
    AND message_keys.id_device = devices.id
    AND message_keys.id_message <= 238798 GROUP BY 
message_keys.id_chat,message_keys.id_device ,message_keys.id_message
) AS max
FROM devices
WHERE devices.id_user = 1

如果您通过连接和聚合来完成这项工作,会花费相同的时间吗?比较两个查询的执行计划,并请显示设备表结构。第二个查询是explain中的一个相关子查询依赖的子查询,速度非常慢,优化程度很差。您确实应该将这个查询重写为一种内部连接方法,如果索引正确的话,这种方法的性能应该优于相关子查询used@MKhalidJunaid完成。我在回答中提供的带有JOIN的新查询占用的时间几乎相同。我现在能想到的唯一可能的解决方案是为用户拥有的每个设备运行单独的查询。您的查询将专门为设备26664生成一行,我需要的是用户1拥有的每个设备的最大值。基本上,我需要与第二次查询相同的输出。因此,我分别添加了id_user、id和id_device、id_chat、id_message to devices和message_key,并确保查询使用它们,但没有任何更改,仍然需要500毫秒。@jlblca9l_kpblca。我怀疑其中一台设备有大量的信息,所有的设备都有相同数量的163118条信息。事实上,为每个设备执行10个独立查询的并集速度大约是原来的两倍。它返回一个错误子查询,并按预期返回多行。
SELECT (
SELECT MAX(id_message)
FROM message_keys
WHERE message_keys.id_chat = 94609
    AND message_keys.id_device = devices.id
    AND message_keys.id_message <= 238798 GROUP BY 
message_keys.id_chat,message_keys.id_device ,message_keys.id_message
) AS max
FROM devices
WHERE devices.id_user = 1