这是我的查询:
SELECT B.RECORDID, A.ITEMCODE, A.ITEMNAME, A.STOCKINHAND, B.SALEPRICE
FROM ITEMMASTER A, STOCKENTRY B
WHERE A.ITEMID = B.ITEMID
AND RECORDID = (SELECT MAX(RECORDID) FROM STOCKENTRY
WHERE ITEMID = A.ITEMID)
AND A.STOCKINHAND > 0
AND B.SALEPRICE > 0
AND B.INVOICEDATE IS NOT NULL
ORDER BY A.ITEMNAME, B.INVOICEDATE;
表 B (StockEntry) 可能包含一条或多条记录,而表 A (ItemMaster) 肯定只有一行用于该 ItemID。
如果我删除 WHERE 子句中的子查询,它会显示一行或多行。我觉得通过 WHERE 子句中的子查询选择 max(RecordID) 会减慢查询速度。我在 RecordID、InvoiceDate、ItemID 上确实有索引,但 MySQL 日志仍然显示此查询执行不佳。由于某些原因,我无法更改列顺序。
有没有更好的方法来优化这个查询?
最佳答案
它可能很慢,因为它正在为外部查询的每一行运行一个相关子查询。有两种解决方案往往运行效率更高。
一种是使用派生表,它使用子查询,但它只执行一次子查询来准备派生表。
SELECT B.RECORDID, A.ITEMCODE, A.ITEMNAME, A.STOCKINHAND, B.SALEPRICE
FROM ITEMMASTER A
JOIN STOCKENTRY B ON A.ITEMID = B.ITEMID
JOIN (SELECT ITEMID, MAX(RECORDID) AS MAXRECORDID
FROM STOCKENTRY GROUP BY ITEMID) M
ON (M.ITEMID, M.MAXRECORDID) = (B.ITEMID, B.RECORDID)
WHERE A.STOCKINHAND > 0
AND B.SALEPRICE > 0
AND B.INVOICEDATE IS NOT NULL
ORDER BY A.ITEMNAME, B.INVOICEDATE;
另一种解决方案是使用排除连接 来查找 B 中的行,使得不存在具有相同 itemid 和更大 recordid 的其他行。使用正确的索引(例如 (ITEMID, RECORDID) 上的复合索引),这应该表现得很好。
SELECT B.RECORDID, A.ITEMCODE, A.ITEMNAME, A.STOCKINHAND, B.SALEPRICE
FROM ITEMMASTER A
JOIN STOCKENTRY B ON A.ITEMID = B.ITEMID
LEFT OUTER JOIN STOCKENTRY B2
ON B.ITEMID = B2.ITEMID AND B.RECORDID < B2.RECORDID
WHERE B2.ITEMID IS NULL
AND A.STOCKINHAND > 0
AND B.SALEPRICE > 0
AND B.INVOICEDATE IS NOT NULL
ORDER BY A.ITEMNAME, B.INVOICEDATE;
此类问题在 Stack Overflow 上经常出现。我添加了 greatest-n-per-group标记问题以便您可以查看其他案例。
回复 @RPK 的评论:
我自己不使用 MySQL QB,而且该应用程序已经更改了很多次,我无法就如何使用它提出建议。但是在 mysql 监视器(命令行)中,我使用了 EXPLAIN 的组合和 PROFILING给我统计数据。
但是,您评论说不会修改(或创建?)索引。这会阻碍您的优化尝试。
关于mysql - 优化查询。想在子查询中不使用 max 的情况下选择最后一条记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6958555/