我们有一些代码通过 SQL 生成器来生成形式为的参数化 IN 子句WHERE id IN (?, ?, ?, ...) AND ...
。
如果列表为空,则生成器无法发出,IN ()
因为这是无效的 SQL。相反,它的问题WHERE id IN (SELECT NULL WHERE FALSE)
是提供相同的语义。
我希望 MYSQL 可以将其减少到WHERE FALSE
。但有趣的是,它未能做到这一点,实际上产生了全表扫描!
示例查询(mytable 是我创建的一个简单的测试表,有 50K 行,id 作为 PK)
select *
from mytable
where id in (select null where false);
有趣的是,如果我将子查询替换为命中实际表的子查询,我会得到一个更好的计划:
询问:
select *
from mytable
where id in (select null from information_schema.tables where false);
我的问题是,MySQL 这样做是否有某些原因(例如第一个查询的某些特定语义?)这是一个已知的错误吗?
更新:我向 MySQL 提交了此问题,他们已承认此异常并将其作为功能请求接受。
“生成器”应该从
WHERE
.如有必要,请删除WHERE
.它不应该把一些可能低效的东西放在原来的位置上。如果您无法控制“发电机”,我深感遗憾。
MySQL 一直是“精益求精”。也就是说,它实现了足够的功能,但不关注边缘情况或速度,只关注正确性。
二十年前(前后),MySQL 实现了以下功能:
ALTER TABLE
通过简单的“复制”。几年前,他们开始优化大多数情况以提高速度。PARTITION
——但基本上还是没用。LEFT JOIN
未使用的A可以忽略。 MySQL 继续执行连接,而 MariaDB 添加了一个优化来忽略该子句。 (这样可以很容易地潜入VIEW
。)IN ( SELECT... )
最初是以一种非常低效的方式实施的。很久以后,一些案例得到了优化。我建议你的例子没有被抓住。