Oracle执行计划WHERE 1=1



我使用的是Oracle数据库,但我无法访问诸如运行执行计划之类的管理工具。

使用SQL Server,SQL/数据库/查询(?(引擎似乎会完全忽略WHERE子句中的一个表达式,如。。。

1=1

其中CCD_ 2可以被替换为任何文字值,只要这些值匹配即可。

Oracle如何处理此问题?Oracle是否也忽略该表达式?

我的意思是,哪个更快?

SELECT A, B, C
FROM TBL

SELECT A, B, C
FROM TBL
WHERE C IN (<every distinct value in C>)

SQL报表生成器经常添加不必要的代码,了解哪些是无害的,哪些是潜在的有害代码很有帮助。一个额外的1=1谓词几乎可以肯定是无害的。但是C IN (<every distinct value in C>)可能会导致错误和性能问题,应该避免。

1=1-允许

虽然我不能证明谓词永远不会引起问题,但根据我的经验和一些简单的测试,我可以自信地说1=1永远不会给你带来问题。我自己和其他人已经多次遇到这个额外的谓词,从未见过任何问题。下面的简单测试用例表明谓词甚至没有出现在解释计划中。优化器将其识别为垃圾,并在编译时将其删除。

explain plan for select * from dual where 1=1;
select * from table(dbms_xplan.display);
Plan hash value: 272002086

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     2 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| DUAL |     1 |     2 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------

C IN(C中的每个不同值(-避免

避免额外的值列表的一个次要原因是,用户可能会错误地将其修改为NULL比较。像C IN (1,2,3)这样的条件很简单,但如果存在NULL,则比较会变得更复杂。在有人错误地将此代码修改为C IN (1,2,3,NULL)之前,您可能需要避免此不必要的代码。或者系统可能会忘记更新值。这是一个";真实的";行代码,删除它可以减少潜在错误的数量。

不必要地比较值也有一些潜在的性能影响。实际的比较本身可能无关紧要——CPU可以琐碎地检查C IN (1,2,3)。真正的问题是,不必要的比较为Oracle提供了另一种创建执行计划的潜在方法,这种方法可能会误导优化器使用慢速访问路径。

例如,假设我们从一个小表开始,其中只有一行和一个C:值

create table tbl(a number, b number, c number);
insert into tbl select 1, 2, 3 from dual;
create index tbl_c on tbl(c);
begin
dbms_stats.gather_table_stats(user, 'TBL');
end;
/

只有一行,所以Oracle如何检索数据无关紧要。在我的系统上,它使用索引范围扫描

explain plan for select * from tbl where c = 3;
select * from table(dbms_xplan.display);
Plan hash value: 1444222704

---------------------------------------------------------------------------------------------
| Id  | Operation                           | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |       |     1 |     9 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TBL   |     1 |     9 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | TBL_C |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("C"=3)

问题来了。有人插入了一百万行,所有行都具有相同的简单值,但之后忘记了收集表上的统计数据。从索引中一次读取一百万行的效率远低于简单地扫描整个表。但由于存在WHERE C = 3谓词,Oracle认为使用索引仍然很快:

insert into tbl select 1,2,3 from dual connect by level <= 1000000;
commit;
explain plan for select * from tbl where c = 3;
select * from table(dbms_xplan.display);
--(Same plan as above)

然而,如果该谓词被删除,就没有机会选择糟糕的索引范围扫描。相反,我们在下面的解释计划中看到了一个完整的表格扫描:

explain plan for select * from tbl;
select * from table(dbms_xplan.display);

Plan hash value: 2144214008

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     9 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| TBL  |     1 |     9 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

最新更新