MySQL IN 与子查询性能奇怪的行为

MySQL IN with subquery performance weird behaviour

我在 REST api 端点上遇到奇怪的行为。基本上我有两个 table,一个带有 id 和其他相关字段的用户 table,以及一个带有 uid(映射用户 ID)和其他几个字段的操作 table。

我想提取执行了特定操作的用户,我正在做这样的事情:

SELECT * FROM users where id IN (select uid from action WHERE [CONDITIONS] order by [CRITERIA]);

考虑到我的数据库的大小,此查询运行大约需要两秒钟,这对于我的用例来说是完全无法接受的table。

如果我将查询分成两个子查询,首先执行,就会出现奇怪的行为:

select uid from action WHERE [CONDITIONS] order by [CRITERIA];

比在手动连接要由 IN 运算符匹配的字符串后执行:

SELECT * FROM users where id IN [MANUAL CONCAT];

这两个查询在同一数据集上的运行时间都在 5 毫秒内。

我的(可能是错误的)理解是先执行子查询,然后再执行主查询。这是错的吗? MySQL 是否每次都执行 IN 子查询?

更新

如果我简单地使用连接(参见下面的代码)会快很多(大约 10 毫秒),但我仍然不明白 IN 在这里是如何工作的。

SELECT distinct * FROM users join action on users.id = action.uid where [CONDITIONS];

我怀疑实际匹配的行大约是 5M 中的 5-10 行这一事实。

首先,order by for in 没有用,所以你可以在没有 order by 的情况下重写它。

其次,exists通常比in快:

SELECT u.*
FROM users u
WHERE EXISTS (SELECT 1 FROM action a WHERE a.uid = u.id and [CONDITIONS]);

为了获得最佳性能,您需要在 action(uid, . . .) 上建立索引。 . . . 用于 [CONDITIONS].

所需的其他列

IN ( SELECT ... ) 优化很差——SELECT 被反复评估。

在某些新版本中,SELECT 将被具体化并自动生成 INDEX。不过,JOIN 很可能会继续变得更快。

看看EXPLAIN SELECT ...;它可能会提供一些关于正在(或未)发生的事情的线索。如果您想进一步讨论,请提供 EXPLAIN、完整的 SELECT 和 table(s) 的 SHOW CREATE TABLE