下面是存储过程中的SQL语句(为简洁起见而截断):
SELECT *
FROM item a
WHERE a.orderId NOT IN (SELECT orderId FROM table_excluded_item);
此声明需要30秒左右!但是,如果我删除内部SELECT查询,它将降至1秒。 table_excluded_item
并不大,但我怀疑内部查询执行的次数超出了预期。
有更有效的方法吗?
答案 0 :(得分:18)
使用LEFT JOIN
SELECT a.*
FROM item a
LEFT JOIN table_excluded_item b
ON a.orderId = b.orderId
WHERE b.orderId IS NULL
确保已将两个表中的orderId
编入索引。
答案 1 :(得分:5)
左连接方法的问题是在生成输出时可能会处理重复记录。有时,事实并非如此。 。 。根据这个article,MySQL确实在列被索引时正确优化left outer join
,即使存在重复项。不过,我承认仍然持怀疑态度,这种优化总是会发生。
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中实现所需的最快,最安全的方法。
答案 2 :(得分:1)
尝试此操作并与LEFT JOIN
查询时间进行比较:
SELECT *
FROM item a
HAVING orderId NOT IN (SELECT orderId FROM table_excluded_item);
由于HAVING
假定限制条件(WHERE
)是结果集的一部分,因此不赞成使用HAVING
时可以使用orderId
。但我认为在这种情况下它更有意义(因为它是结果集的一部分),并且因为它比LEFT JOIN
方法更清楚。
它可能实际上有点慢,但发布结果,以便我们知道它是否比原始查询更好。