我在 REST API 端点上遇到了奇怪的行为。基本上我有两个表,一个带有 id 和其他相关字段的用户表,以及一个带有 uid(映射用户 id)和其他几个字段的操作表。
我想提取已执行特定操作的用户,我正在执行以下操作:
SELECT * FROM users where id IN (select uid from action WHERE [CONDITIONS] order by [CRITERIA]);
考虑到我的数据库大小,此查询运行时间约为两秒,这对于我的用例来说是完全 Not Acceptable 。
如果我将查询分成两个子查询,首先执行,就会出现奇怪的行为:
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 个这一事实很重要。
最佳答案
IN ( SELECT ... )
的优化非常差 - SELECT
被重复评估。
在某些新版本中,SELECT
将被具体化,并且 INDEX
将自动生成。尽管如此,JOIN
很可能会继续变得更快。
查看解释选择...
;它可能会提供一些关于正在发生(或未发生)的事情的线索。如果您想进一步讨论,请提供表的EXPLAIN
、完整的SELECT
和SHOW CREATE TABLE
。
关于MySQL IN 与子查询性能奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31300310/