版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/bisal/article/details/102735217
模拟表名,A表的数据量约1000万,B表的数据量约500万,进行连接,其中这几个条件字段,都创建了索引,
代码语言:javascript复制SQL> SELECT * from A a inner join B b on a.ID = b.id
where b.C_DATE <= trunc(sysdate)-1000;
我们知道在CBO优化器模式下,Oralce会基于Cost成本,来选择执行计划。从执行计划看,全表扫描用的Hash Join,被驱动表只扫描一次,HINT使用索引则用的嵌套循环连接Nested Loop,两个表的记录都很多,哪个表做被驱动表都会导致扫描次数过多,回表也过多,而且索引的CF高,索引扫描的成本,会更高些,SELECT返回所有列,需要考虑回表,因此干脆不回表,选择全表扫描,从Cost能看出,HINT索引的值更高。
从10053能看到SELECT的执行计划成本计算,根本没考虑索引,鉴于SELECT *和较高的CF,能不回表就不回表了,
代码语言:javascript复制PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 10000 | 195K| 5040 (1)| 00:01:01 |
| 1 | DELETE | A | | | | |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | NESTED LOOPS | | 85666 | 1673K| 5040 (1)| 00:01:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| B | 85666 | 1171K| 5034 (1)| 00:01:01 |
|* 5 | INDEX RANGE SCAN | IDX_B_01 | 85666 | | 232 (1)| 00:00:03 |
|* 6 | INDEX UNIQUE SCAN | PK_A_ID | 1 | 6 | 0 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM<=10000)
5 - access("B"."C_DATE"<=TRUNC(SYSDATE@!)-1000)
6 - access("A"."ID"="B"."ID")
DELETE的时候,毕竟要删除数据,因此回表势在必行的,只能在回表的各种路径中找一个合适的,所以会考虑索引路径,
SELECT和DELETE即使条件相同,相应的执行计划,可能还是有差别,归根结底在于Cost的计算和判断,如上例所示,可能会考虑是否需要回表、CF值高低等因素,所以Oracle在这方面还是很智能的,优化器的算法,作为他的核心商业机密,也就不足为奇了。