Mysql 嵌套连接的优化
我正试图在我的网站上获得一组商家的订单金额。我必须检查两种项目类型,这使得查询速度非常慢。这是我现在使用的(为可读性而转换的)查询Mysql 嵌套连接的优化,mysql,sql,query-optimization,Mysql,Sql,Query Optimization,我正试图在我的网站上获得一组商家的订单金额。我必须检查两种项目类型,这使得查询速度非常慢。这是我现在使用的(为可读性而转换的)查询 SELECT User.ID, COUNT(Order.ID) FROM User INNER JOIN UserGroup ON UserGroup.userID = User.ID AND UserGroup.groupID = 4 LEFT JOIN Meal ON Meal.userID = User.ID LEFT JOIN Produce O
SELECT User.ID, COUNT(Order.ID) FROM User
INNER JOIN UserGroup ON UserGroup.userID = User.ID AND UserGroup.groupID = 4
LEFT JOIN Meal ON Meal.userID = User.ID
LEFT JOIN Produce ON Produce.userID = User.ID
LEFT JOIN Order ON (type = 'Meal' AND typeID = Meal.ID) OR (type = 'Produce' AND typeID = Produce.ID)
WHERE Order.rating > 50 AND Order.status = 'DELIVERED'
ORDER BY User.ID ORDER BY COUNT(Order.ID) DESC
当然,所有链接和状态列都是索引。当我运行查询的EXPLAIN
时,我可以看到它将Order
选项卡作为type ALL
进行连接,我很确定这就是问题所在,我只是不知道如何使它也作为ref
进行连接。目前执行需要2.74秒
(不要检查此查询中的拼写错误,我更改了表名和字段名以确保可读性,可能遗漏了一些内容,但有关我的问题的所有信息都在其中。)
解释的输出
+----+-------------+-----------+--------+-------------------------+---------+---------+------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+--------+-------------------------+---------+---------+------------------+------+---------------------------------+
| 1 | SIMPLE | UserGroup | ref | userID,groupID | groupID | 4 | const | 74 | Using temporary; Using filesort |
| 1 | SIMPLE | User | eq_ref | PRIMARY,isDeleted | PRIMARY | 4 | UserGroup.userID | 1 | Using where |
| 1 | SIMPLE | Meal | ref | userID,isDeleted,status | userID | 4 | UserGroup.userID | 18 | |
| 1 | SIMPLE | Produce | ref | userID,status,isDeleted | userID | 4 | User.ID | 13 | |
| 1 | SIMPLE | Order | ALL | status,isDeleted,type | NULL | NULL | NULL | 1960 | |
+----+-------------+-----------+--------+-------------------------+---------+---------+------------------+------+---------------------------------+
我已经解决了这个问题。我可以走两条路:
使用上述注释中建议的联合
(执行时间:~10.5ms)
或者我可以将Order
表作为主表,并通过COALESCE()执行分组(执行时间:~76毫秒)
为了便于阅读,我决定使用后者。如果有人知道如何修复原始问题中的问题,请让我知道。我将它作为一个更大脚本的一部分来编写,在这个脚本中我可以快速加入查询修饰符。如果我必须对查询进行如此大的更改,这些查询将不再起作用。您能否发布EXPLAIN
的输出以及Order
表上的索引?通常,union ALl查询比join中带有or条件的query快。我知道这对SQL Server是正确的,我怀疑这对我的SQL Server也是正确的。您需要向我们展示表和索引定义,以及每个表的行计数。也许您的表定义不好。可能索引没有正确创建。也许你在你认为你有的专栏上没有索引。如果看不到表和索引定义,我们无法判断。我们还需要行计数,因为这会极大地影响查询优化。如果您知道如何进行解释或获取执行计划,请将结果也放入问题中。@HLGEM是正确的。您可以将其重写为两个查询中订单的ON条件的每个部分的并集。
SELECT User.ID, SUM(orderCount) AS totalOrders FROM (
(
SELECT User.ID, COUNT(Order.ID) AS orderCount
FROM User
INNER JOIN UserGroup ON User.ID = UserGroup.userID AND UserGroup.groupID = 4
LEFT JOIN Meal ON User.ID = Meal.userID
LEFT JOIN Order ON Order.type = 'Meal' AND Order.typeID = Meal.ID
GROUP BY User.ID
)
UNION ALL
(
SELECT User.ID, COUNT(Order.ID) AS orderCount
FROM User
INNER JOIN UserGroup ON User.ID = UserGroup.userID AND UserGroup.groupID = 4
LEFT JOIN Produce ON User.ID = Produce.userID
LEFT JOIN Order ON Order.type = 'Produce' AND Order.typeID = Produce.ID
GROUP BY User.ID
)
) AS uni
GROUP BY User.ID
ORDER BY totalOrders DESC
SELECT COALESCE(Meal.userID,Produce.userID) AS cook, COUNT(Order.ID) AS totalOrders
FROM Order
LEFT JOIN Meal ON Order.type = 'Meal' AND Order.typeID = Meal.ID
LEFT JOIN Produce ON Order.type = 'Produce' AND Order.typeID = Produce.ID
INNER JOIN UserGroup ON UserGroup.groupID = 4 AND (Meal.userID = UserGroup.userID OR Produce.userID = UserGroup.userID)
GROUP BY cook
HAVING cook IS NOT NULL
ORDER BY TotalOrders DESC