【发布时间】:2023-03-04 11:53:01
【问题描述】:
我最近参观了一次有趣的求职面试。那里有人问我一个关于使用包含长标量列表(即数千个值)的WHERE..IN 子句优化查询的问题。这个问题不是关于IN 子句中的子查询,而是关于简单的标量列表。
我马上回答说,这可以使用 INNER JOIN 和另一个表(可能是临时表)进行优化,该表仅包含那些标量。我的回答被接受了,并且审阅者有一条注释,“目前没有数据库引擎可以优化长 WHERE..IN 条件以具有足够的性能”。我点了头。
但是当我走出去的时候,我开始有些怀疑了。这种情况似乎相当微不足道,并被广泛用于现代 RDBMS 无法对其进行优化。所以,我开始了一些挖掘。
PostgreSQL:
似乎 PostgreSQL parse scalar IN() constructions into ScalarArrayOpExpr structure,也就是 sorted。此结构稍后在索引扫描期间用于定位匹配的行。对于此类查询,EXPLAIN ANALYZE 仅显示一个循环。没有完成任何连接。所以,我希望这样的查询比 INNER JOIN 更快。我在现有数据库上尝试了一些查询,我的测试证明了这一点。但我并不关心测试的纯度,而且 Postgres 在 Vagrant 之下,所以我可能错了。
MSSQL 服务器:
MSSQL 服务器builds a hash structure from the list of constant expressions and then does a hash join with the source table。尽管似乎没有进行排序,但我认为这是性能匹配。我没有做任何测试,因为我对这个 RDBMS 没有任何经验。
MySQL 服务器:
The 13th of these slides 说,在 5.0 之前,这个问题确实发生在 MySQL 的某些情况下。但除此之外,我没有发现任何其他与不良IN () 治疗有关的问题。不幸的是,我没有找到任何逆向证明。如果你这样做了,请踢我。
SQLite:
Documentation page 暗示了一些问题,但我倾向于相信那里描述的东西确实是概念层面的。没有找到其他信息。
所以,我开始认为我误解了我的面试官或滥用了 Google ;) 或者,可能是因为我们没有设置任何条件,我们的谈话变得有点模糊(我们没有指定任何具体的 RDBMS或其他条件。那只是抽象的谈话)。
看起来,数据库将IN() 重写为一组OR 语句(这有时会导致列表中的NULL 值出现问题,顺便说一句)的日子已经很久了。还是不行?
当然,如果标量列表比允许的数据库协议包长,INNER JOIN 可能是唯一可用的解决方案。
我认为在某些情况下,单独的查询解析时间(如果没有准备好)会影响性能。
此外,数据库可能无法准备 IN(?) 查询,这将导致一次又一次地重新解析它(这可能会降低性能)。实际上,我从未尝试过,但我认为即使在这种情况下,查询解析和规划与查询执行相比也并不大。
但除此之外,我没有看到其他问题。好吧,除了只是遇到这个问题的问题。如果您有查询,其中包含数千个 ID,则说明您的架构有问题。
你呢?
【问题讨论】:
-
根据我的经验,SQL Server 在大量 IN 参数上出现查询计划程序超时。
-
虽然有趣但不适合这个网站。你知道...我投票结束。
-
我写了This thing,这更多地与随机数有关。我确实做到了端到端。我所说的附录 C 在列表中使用了大。一千个元素。结果十分之二秒。
-
我在
IN()中看到了一个1TB MySQL表有70K值的案例。有效。考虑到它必须做多少工作,它“相当”快。它还发现了 MySQL (4.1(?)) 中的一些内存问题。 -
@RickJames 该查询的解释是什么?时间是什么?
标签: mysql sql-server postgresql sqlite query-optimization