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
。
我在 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
。