我在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个。
答案 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
,表格的完整SELECT
和SHOW CREATE TABLE
。