“NOT IN”的快速替代方案

Joh*_*000 5 mysql performance join select query-performance

我有一个表 A,它有一个名为 id 的字段,它是该表的主键。我还有一个名为 B 的表,它还有一个名为 id 的字段作为主键。

现在我想从表 A 中获取所有行,其中 id 值不作为任何表 B id 字段值中的值存在。

我的第一个查询是这样的:

SELECT a.id FROM a WHERE a.id NOT IN (SELECT DISTINCT b.id FROM b)
Run Code Online (Sandbox Code Playgroud)

然后我构建了一个看起来像这样的查询以提高速度:

SELECT a.id FROM a LEFT JOIN b ON a.id = b.id WHERE b.id IS NULL
Run Code Online (Sandbox Code Playgroud)

现在我在表 A 中得到 600k 行,在表 B 中得到 400k 行,并且事情变得非常缓慢。有没有更好的查询来运行这种操作,或者有没有更好的方法来解决这个问题?任何提示或指示?

Rol*_*DBA 2

您必须做的是增加join_buffer_size。什么是 join_buffer_size ?

用于普通索引扫描、范围索引扫描以及不使用索引并因此执行全表扫描的联接的缓冲区的最小大小。通常,获得快速连接的最佳方法是添加索引。当无法添加索引时,增加 join_buffer_size 的值以获得更快的完全连接。为两个表之间的每个完全连接分配一个连接缓冲区。对于不使用索引的多个表之间的复杂联接,可能需要多个联接缓冲区。

我突出显示了这句话,因为您的查询非常简单。您正在对一个整数进行联接,我假设该整数已在两个表中建立了索引。如果表中的 idb未索引,请尽快索引。

我建议将join_buffer_size提高到 4M。

您可以在会话中更改join_buffer_size并重新运行查询

SET join_buffer_size = 1024 * 1024 * 4;
SELECT a.id FROM a LEFT JOIN b ON a.id = b.id WHERE b.id IS NULL;
Run Code Online (Sandbox Code Playgroud)

试一试 !!!