我使用的是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 |
--------------------------------------------------------------------------