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);
然后你传入 1
、2
、3
和 4
或者你传入 2
、2
、2
和 2
那么 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(记得展开说明计划以查看完整的详细信息)
让我们考虑这些查询:
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);
然后你传入 1
、2
、3
和 4
或者你传入 2
、2
、2
和 2
那么 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(记得展开说明计划以查看完整的详细信息)