我使用的是Oracle数据库,但我无法访问管理工具,比如运行执行计划。
使用Server,似乎SQL /数据库/查询(?)引擎将完全忽略WHERE子句中的表达式,如.
1=1只要值匹配,就可以用任何文字值替换...where 1。
Oracle是如何处理这一问题的?Oracle也会忽略这个表达式吗?
我要说的是,哪个更快?
SELECT A, B, C
FROM TBL或
SELECT A, B, C
FROM TBL
WHERE C IN (<every distinct value in C>)发布于 2022-01-12 06:09:19
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中的每个不同的值)-避免它
避免额外的值列表的一个次要原因是用户可能为空比较错误地修改它们。像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谓词,所以甲骨文认为使用索引的速度仍然很快:
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 |
--------------------------------------------------------------------------https://stackoverflow.com/questions/70672915
复制相似问题