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

时间:2015-07-08 18:04:26

标签: mysql sql query-optimization

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

我想提取已执行特定操作的用户,我正在执行以下操作:

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

考虑到我的数据库的大小,这个查询在大约两秒钟内运行,这对我的用例来说是完全不可接受的。

如果我将查询拆分为两个子查询,首先执行:

,会出现奇怪的行为
select uid from action WHERE [CONDITIONS] order by [CRITERIA];

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

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

两个查询在同一数据集上的5ms下运行。

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

更新

如果我只是使用连接(参见下面的代码)要快得多(大约10ms),但我仍然不知道IN在这里工作的方式。

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

我怀疑行中实际匹配的行数大约是5M中的5-10个。

2 个答案:

答案 0 :(得分:1)

首先,order by的{​​{1}}无效,因此您可以在没有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, . . .)适用于. . .所需的其他列。

答案 1 :(得分:1)

IN ( SELECT ... )的优化效果非常差 - SELECT会被重复评估。

在某些新版本中,SELECT将会实现,并会自动生成INDEX。不过,JOIN很可能会继续加快。

看看EXPLAIN SELECT ...;它可能会提供一些(或不是)正在发生的线索。如果您想进一步讨论,请提供EXPLAIN,表格的完整SELECTSHOW CREATE TABLE