我有一个SQL查询:
SELECT company.*, salesorder.lastOrderDate
FROM company
INNER JOIN
(
SELECT companyId, MAX(orderDate) AS lastOrderDate
FROM salesorder
GROUP BY companyId
) salesorder ON salesorder.companyId = company.companyId;
这使我在公司主表的末尾多了一列,显示了他们的最后订单日期。
问题是,当分析这个查询时,它似乎没有那么高效:
有没有办法让它更有效率呢?
salesorder:
orderId, companyId, orderDate
1 333 2015-01-01
2 555 2016-01-01
3 333 2017-01-01
company
companyId, name
333 Acme
555 Microsoft
Query:
companyId, name, lastOrderDate
333 Acme 2017-01-01
555 Microsoft 2016-01-01
解释SELECT:
CREATE TABLE `salesorder` (
`orderId` int(11) NOT NULL,
`companyId` int(11) DEFAULT NULL,
`orderDate` date DEFAULT NULL,
PRIMARY KEY (`orderId`),
UNIQUE KEY `orderId_UNIQUE` (`orderId`) /*!80000 INVISIBLE */,
KEY `testComposite` (`companyId`,`orderDate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `company` (
`companyId` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`companyId`),
UNIQUE KEY `companyId_UNIQUE` (`companyId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
发布于 2019-12-26 23:35:10
按以下顺序添加包含列的复合索引:
INDEX(companyId, orderDate)
单列索引效率不高(在此查询中)。
因为PRIMARY KEY
是唯一的密钥,所以不要多余地声明UNIQUE
密钥。
由于表中只有几行,您不能相信EXPLAIN
(以及类似解释的输出)来判断查询会有多糟糕。尝试使用至少几十行。并提供EXPLAIN FORMAT=JSON SELECT ...
注意,上面写着“使用索引”。也就是说,所讨论的子查询可以完全在索引的BTree中执行。这是“好的”。(我假设您在添加了我建议的索引之后执行了EXPLAIN
?)
您之前的图像显示了很多行;这说明了什么?
我仍然不明白为什么EXPLAIN
中有3行和两个表扫描。无论如何,下面是另一个可以尝试的公式:
SELECT c.*,
( SELECT MAX(orderDate)
FROM salesorder
WHERE companyId = c.companyId
) AS lastOrderDate
FROM company AS c;
(我的INDEX
仍然很重要)
发布于 2020-01-06 09:52:11
看起来您可以像这样简化查询:
SELECT c.*, MAX(o.OrderDate) As lastOrderDate
FROM company c
INNER JOIN salesorder o on o.companyId = c.companyId
GROUP BY <list all company fields here>;
MySql甚至可以让您在GROUP BY
子句中只使用c.companyId
,但这不是真正的标准,也不是很好的实践。
https://stackoverflow.com/questions/58543135
复制相似问题