我知道这种限制以及重写SQL的替代方法。但我想知道原因?任何人都可以对此限制进行推断吗?
答案 0 :(得分:2)
像
这样的查询select * from table where id in (select id from othertable)
基本上会被解释为
select * from table where exists
(select id from othertable where table.id = othertable.id)
这是您对该查询的期望。您特别希望IN
查询使用othertable.id
上的索引。在manual中,它被描述为
MySQL本身做出的一些优化是:[...]
- MySQL重写IN,ALL,ANY和SOME子查询,试图利用子查询中的select-list列被索引的可能性。
如果添加limit
,这些不是纯粹的巧合,恰好是错误消息中提到的四个运算符:
select * from table where id in
(select id from othertable order by id limit 10)
ERROR 1235(42000):此版本的MySQL尚不支持'LIMIT& IN / ALL / ANY / SOME子查询'。
不再可能以类似的方式重写该查询,因为它与
不同select * from table where exists
(select id from othertable where table.id = othertable.id
order by id limit 10)
要执行带有限制的IN
,MySQL可以检索10个othertable
的第一行,将该结果集存储为派生的子表并检查id是否在那里。你当然可以这样做:
select * from table where id in
(select id from
(select id from othertable order by id limit 10) subtable)
与第一个例子类似,这将被解释为
select * from table where exists
(select * from
(select id from othertable order by id limit 10) subtable
where table.id = subtable.id)
所以它是优化器如何工作的混合(它将重写查询),limit
如何工作(它在查找行之后停止执行,而不是跳过它们),是什么预期(使用索引)并最终如果开发人员决定允许特定语法。
你可能会争辩说,如果MySQL遇到带有IN
子查询的limit
,MySQL总是可以回退以执行派生表 - 但你也可以明确地使用派生子表。您也可以争辩说,您可以考虑实施或以不同方式实施的方法 - 而且您是对的,有。这就是错误消息中有“ yet ”的原因。所以随意实施它们或至少描述它们,例如尽可能彻底地在功能请求中并考虑MySQL的所有其他部分如何工作。但要确保它们实际上比仅使用子表更快。