以下是存储过程中的 SQL 语句(为简洁起见,已截断):
SELECT *
FROM item a
WHERE a.orderId NOT IN (SELECT orderId FROM table_excluded_item);
这个语句需要30秒左右!但是如果我删除内部 SELECT 查询,它会下降到 1s。table_excluded_item
不是很大,但我怀疑内部查询的执行超出了它的需要。
有没有更有效的方法来做到这一点?
以下是存储过程中的 SQL 语句(为简洁起见,已截断):
SELECT *
FROM item a
WHERE a.orderId NOT IN (SELECT orderId FROM table_excluded_item);
这个语句需要30秒左右!但是如果我删除内部 SELECT 查询,它会下降到 1s。table_excluded_item
不是很大,但我怀疑内部查询的执行超出了它的需要。
有没有更有效的方法来做到这一点?
利用LEFT JOIN
SELECT a.*
FROM item a
LEFT JOIN table_excluded_item b
ON a.orderId = b.orderId
WHERE b.orderId IS NULL
确保orderId
从两个表中都已建立索引。
左连接方法的问题是在生成输出时可能会处理重复记录。有时,情况并非如此。. . 根据这篇文章left outer join
,即使在存在重复列的情况下,MySQL 也会在列被索引时正确优化。不过,我承认对这种优化总是会发生持怀疑态度。
MySQL 有时会在IN
使用子查询优化语句时遇到问题。最好的解决方法是关联子查询:
SELECT *
FROM item a
WHERE not exists (select 1
from table_excluded_item tei
where tei.orderid = a.orderid
limit 1
)
如果您在 table_excluded_item.orderid 上有一个索引,那么这将扫描索引并在第一个值处停止(这limit 1
可能不是绝对必要的)。这是在 MySQL 中实现你想要的最快和最安全的方法。
试试这个并与LEFT JOIN
查询时间进行比较:
SELECT *
FROM item a
HAVING orderId NOT IN (SELECT orderId FROM table_excluded_item);
这是不赞成的(使用HAVING
whenWHERE
可以使用),因为HAVING
假设限制条件 ( orderId
) 是结果集的一部分。但我认为在这种情况下它更有意义(因为它是结果集的一部分)并且因为它比方法更清楚正在发生的事情LEFT JOIN
。
它实际上可能有点慢,但发布结果,以便我们知道它是否比您的原始查询更好。