mysql - 优化查询。想在子查询中不使用 max 的情况下选择最后一条记录

标签 mysql sql greatest-n-per-group query-performance

这是我的查询:

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/

相关文章:

MySQL CSV 一栏导出HTML代码

mysql - 为什么在 INNER JOIN 中使用 MAX() 时只能选择两列?

PHP MySQL 使用 JsonString (Array) 插入记录

sql - 将 0 转换为 DATE 和 DATETIME

sql-server - 如何使用 TOP 1 信息和来自 Top 1 信息的排序依据选择不同的信息

mysql - 如何在 MySQL 中构建一个非常简单的博客的表?

mysql - 如何获取 SQL 中的最新行?

javascript - 在nodeJs上,SQL Server可以将连接表返回为对象数组吗?

sql - 左外连接仅第一行

php - mysql 查询 - 有限制的博客文章和评论