IN 参数的数量是否会改变查询的执行计划?

Does the amount of IN parameters change the execution plan of a query?

让我们考虑这些查询:

select * from person where com_code in (1, 2, 3, 4)
select * from person where com_code in (1, 2, 2, 2)
select * from person where com_code in (1, 2, 3)
select * from person where com_code in (0,1,2,3,4,5,6,7,8,9,10,11,12,13)

Oracle 内存中是否存储了不同的执行计划? 换句话说,IN参数的数量是否改变了执行计划? 会不会有1个参数的执行计划,2个参数的另一个执行计划等等?

我在 SQL 开发者中的测试表明,当 in 运算符中的参数越多时,查询的成本会越大。

一个值:

两个值:

三个值:

因此,回答您的问题:“IN 参数的数量是否会改变查询的执行计划?”是的。

这也可以帮助:How efficiently does Oracle handle a very long IN operator list

是的,执行计划发生了变化。首先,条件是计划的一部分。因此,检查 id in (1,2)id in (1,2,3) 是否意味着两个不同的比较,因此是两个不同的计划。不过,总体计划 table 以何种顺序和以何种方式访问​​可以是相同的。

但不必相同,因此即使是 Oracle 决定的路线也可以改变。以 1000 行的 table 和 where id in (...) 的查询为例。如果 IN 子句包含一个或两个 ID,Oracle 将使用索引。对于 IN 子句中的所有千个 ID,Oracle 将决定进行完整的 table 扫描。

select * from thousandrows where id in (1,2); -- index
select * from thousandrows where id in (1,...,1000); -- full table scan

关于 Oracle 内存中的计划,我从 V$SQL_PLAN 了解到 Oracle 存储每个查询的计划。因此,对于两个具有完全相同的执行计划的查询,就像这两个:

select * from thousandrows where id in (1,2);
select * from thousandrows where id = 1 or id = 2;

Oracle 仍会在内存中保留同一计划的两个副本,每个查询一个。

Will there be an execution plan for 1 parameter, another one for 2 parameters, etc.?

SQL 引擎将检查查询文本并查看它是否与现有查询相同:

  • 如果相同则将使用现有计划。
  • 如果有任何差异,那么它将解析新查询并生成新计划。

对于您的示例,无论参数数量多少,每个查询都会有一个执行计划,因为每个查询的查询文本都不同。所以对于4个不同的查询会有4个不同的执行计划。


如果使用绑定参数:

select * from person where com_code in (:a, :b, :c, :d);

然后你传入 1234 或者你传入 2222 那么 SQL 引擎将看到第二个查询的文本与第一个相同,并且假设 table 统计信息不变,将 re-use 第二个查询的第一个查询的执行计划(即使绑定变量不同)。

如果改变绑定参数的数量,则会生成不同的执行计划以匹配过滤器的数量。


如果您不使用绑定参数,那么 SQL 引擎将不得不在每次更改时解析查询文本,并且可能不会生成相同的查询计划。

例如:

select * from person where com_code in (2, 2, 2, 2);

将被 SQL 引擎重写为:

select * from person where com_code = 2;

并且会生成一个不同的解释计划:

select * from person where com_code in (1, 2, 3, 4);

db<>fiddle here(记得展开说明计划以查看完整的详细信息)