WHERE 子句中的"equal to NULL"条件仍允许查询执行和使用资源



在我们的PL/SQL代码中,我发现了一个错误,当查询的WHERE子句中使用的变量为NULL时。所以我们在查询的 WHERE 子句中有一个语句,比如"table1.column1 = NULL"。在这种情况下,我已经知道对 UNKNOWN 的评估,并且正如预期的那样,查询没有返回任何记录。

但是"table1"很大,我看到长查询将我们错误地空变量到这个表,它跟踪索引。因此,我进行了一些小研究,发现以下查询:

1.

select *
from table1
where table1.column1 = NULL

阿拉伯数字。

select *
from table1
where 1=2

实际执行。它们都具有正确的计划和正常(作为WHERE子句中具有正确数据的查询(执行时间。此外,此查询会消耗资源。

问题是:为什么完全不会返回任何结果的查询仍然在 Oracle 中执行并消耗资源?

优化程序可能不希望用户编写无意义的查询,因此不会检查它。

请注意,每次检查无意义的查询都会花费额外的时间,并且大多数情况不会从中获得任何好处。
为什么要付出额外的努力来惩罚大量的查询,以简单地避免错误查询的负载?惩罚无用查询的作者似乎是正确的,而不是所有其他的人来取悦他。

优化程序确实意识到了这一点,并将在查询中注入"stop this"过滤器:

我有一个包含 300 万行的表test。一个简单的

select * 
from test;

结果为以下执行计划:

----------------------------------------------------------------                 
| Id  | Operation         | Name | E-Rows |E-Bytes| Cost (%CPU)|                 
----------------------------------------------------------------                 
|   0 | SELECT STATEMENT  |      |   3145K|    72M|  3587   (1)|                 
|   1 |  TABLE ACCESS FULL| TEST |   3145K|    72M|  3587   (1)|                 
----------------------------------------------------------------                 

现在让我们看一下以下计划:

select * 
from test
where 1=2;
-----------------------------------------------------------------                
| Id  | Operation          | Name | E-Rows |E-Bytes| Cost (%CPU)|                
-----------------------------------------------------------------                
|   0 | SELECT STATEMENT   |      |      1 |    24 |     0   (0)|                
|*  1 |  FILTER            |      |        |       |            |                
|   2 |   TABLE ACCESS FULL| TEST |   3145K|    72M|  3587   (1)|                
-----------------------------------------------------------------                
Predicate Information (identified by operation id):                              
---------------------------------------------------                              
1 - filter(NULL IS NOT NULL)                                                  

正如你所看到的,Oracle确实意识到WHERE条件永远不会为真,并注入了一个计划步骤,该步骤基本上阻止了其下方"表访问完整"的执行。估计行 1

如果检索运行时使用的实际计划,也可以看到:

------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows |   A-Time   |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |       |     1 (100)|      0 |00:00:00.01 |
|*  1 |  FILTER            |      |      1 |        |       |            |      0 |00:00:00.01 |
|   2 |   TABLE ACCESS FULL| TEST |      0 |   3145K|    72M|  3587   (1)|      0 |00:00:00.01 |
------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):                                   
-------------------------------------------------------------                                   
1 - SEL$1                                                                                    
2 - SEL$1 / TEST@SEL$1                                                                       
Predicate Information (identified by operation id):                                             
---------------------------------------------------                                             
1 - filter(NULL IS NOT NULL)                                                                 

您可以看到所有计划步骤(包括"表访问完整"(的"A 行"(="实际行"(为零,这意味着从未从表中读取数据。


请注意,对于不太明显的条件,但可以从约束中推断出永远不会为真的条件也会发生这种情况。 测试表的id列是主键,因此NOT NULL

运行时:

select *
from test
where id is null;

优化程序知道这是一个永远不会为真的条件(因为 NOT NULL 约束(,并生成与以前相同的"停止此"计划:

-----------------------------------------------------------------                
| Id  | Operation          | Name | E-Rows |E-Bytes| Cost (%CPU)|                
-----------------------------------------------------------------                
|   0 | SELECT STATEMENT   |      |      1 |    24 |     0   (0)|                
|*  1 |  FILTER            |      |        |       |            |                
|   2 |   TABLE ACCESS FULL| TEST |   3145K|    72M|  3587   (1)|                
-----------------------------------------------------------------                
Predicate Information (identified by operation id):                              
---------------------------------------------------                              
1 - filter(NULL IS NOT NULL)                                                  

相关内容

  • 没有找到相关文章

最新更新