17

以下是存储过程中的 SQL 语句(为简洁起见,已截断):

SELECT * 
FROM item a 
WHERE a.orderId NOT IN (SELECT orderId FROM table_excluded_item);

这个语句需要30秒左右!但是如果我删除内部 SELECT 查询,它会下降到 1s。table_excluded_item不是很大,但我怀疑内部查询的执行超出了它的需要。

有没有更有效的方法来做到这一点?

4

3 回答 3

23

利用LEFT JOIN

SELECT  a.* 
FROM    item a 
        LEFT JOIN table_excluded_item b
            ON a.orderId = b.orderId
WHERE   b.orderId IS NULL

确保orderId从两个表中都已建立索引。

于 2013-01-05T02:04:25.920 回答
5

左连接方法的问题是在生成输出时可能会处理重复记录。有时,情况并非如此。. . 根据这篇文章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 中实现你想要的最快和最安全的方法。

于 2013-01-05T14:09:56.833 回答
1

试试这个并与LEFT JOIN查询时间进行比较:

SELECT * 
FROM item a 
HAVING orderId NOT IN (SELECT orderId FROM table_excluded_item);

这是不赞成的(使用HAVINGwhenWHERE可以使用),因为HAVING假设限制条件 ( orderId) 是结果集的一部分。但我认为在这种情况下它更有意义(因为它是结果集的一部分)并且因为它比方法更清楚正在发生的事情LEFT JOIN

它实际上可能有点慢,但发布结果,以便我们知道它是否比您的原始查询更好。

于 2013-01-05T02:47:39.413 回答