1 嵌套循环连接
条件1: 如果驱动表所对应的驱动结果集的记录数较少 ,同时在被驱动的表的连接列又存在唯一性索引 (或者在被驱动表的连接列有选择性非常好的非唯一索引)
那么使用嵌套循环连接。如果驱动表对应的驱动结果集对应的记录数较大,则即使连接列存在索引,效率也不会高。
条件2:驱动结果集为大表,通过谓词条件筛选后,能够将驱动结果集降低。
优点:嵌套循环连接相比其他连接,可以实现快速响应,即它第一时间返回已经满足条件的记录行数。
总结:较小的驱动结果集,被驱动表连接列存在选择性比较好的索引
案例 1
select *from a ,b where a.date=sysdate-10 and a.id=b.id(其中a表通过谓词帅选后有10W,b表数据量为3000, 则执行计划为 A表驱动 ,b表被驱动,走 nl连接,连接列有唯一索引 巴士)
2 哈希连接
1 驱动结果集数量较大,连接列不存在合适的索引,且驱动结果集通过hash 运气算对应的HASH table 可以完全容在PGA中。
2 连接列可选择性很好,如果不好,可能导致hash table中记录数较多,导致高的cpu消耗,很低的逻辑读取。(读取PGA hash table)。
3 反连接
对于使用not in not exists <>ALL条件产生的子查询展开使用的连接。
SQL> create table ac1 as select * from dba_objects;
表已创建。
SQL> create table ac2 as select * from ac1
2 ;
表已创建。
SQL> select * from ac1 where ac1.object_id not in (select object_id from ac2);
未选定行
SQL> set autotrace traceonly;
SQL> select * from ac1 where ac1.object_id not in (select object_id from ac2);
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 2231603900----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 72330 | 34M| | 2547 (1)| 00
:00:01 |
|* 1 | HASH JOIN RIGHT ANTI NA| | 72330 | 34M| 1712K| 2547 (1)| 00
:00:01 |
| 2 | TABLE ACCESS FULL | AC2 | 69805 | 886K| | 387 (1)| 00
:00:01 |
| 3 | TABLE ACCESS FULL | AC1 | 72330 | 33M| | 389 (1)| 00
:00:01 |
Predicate Information (identified by operation id):
---------------------------------------------------1 - access("AC1"."OBJECT_ID"="OBJECT_ID")
- dynamic statistics used: dynamic sampling (level=2)统计信息
----------------------------------------------------------
0 recursive calls
5 db block gets
1435 consistent gets
0 physical reads
0 redo size
2168 bytes sent via SQL*Net to client
597 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processedSQL>
半连接s
HASH JOIN SEMI
select * from t1 where t1.id in(select t2.id from t2);
select *from t1 where exists(select 1 from t2 where t1.id=t2.id);
分析案例:
1个sql 对应3个执行计划。即3个plan_HASH_VALUE.
在问题出现期间选择value1的执行计划。(一个740W数据的表进行全表扫描),对应的几个sql对应的cost值基本接近。
案例分析:
1 查看统计信息 。
2 查看真是表数据信息
原因分析总结:1 根据执行计划统计信息发现对一个740w表进行全表扫描cost值仅为10,(应该在几百k才对),且统计信息num rows显示为600多w比较准确。
2 通过分析发现 由于修改了会话级别的optimizer MODE参数为first_rows_10导致 对全表扫描预估的cost值不准确,导致CBO在选择执行计话时,选择了错误的cost值得执行计划。
3导致CBO评估出①个实际数据量730W且统计信息准确的大表全表扫描操作成本仅为2的原因,是参数optimizer_mode被修改为first_rows_10,导致了系统登录间隙性变慢的问题。
SQL> show parameter mode
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
instance_mode string READ-WRITE
optimizer_mode string ALL_ROWS
remote_dependencies_mode string TIMESTAMP
result_cache_mode string MANUAL
SQL>
知识点总结:
1 通过b树索引的查询效率,不会因为表数据量的增加而降低。
2 关键字(+)在哪里出现,则表明对应的对象要以null来补全。
3 Oracle索引跳跃式扫描,前导列distinct值越少越好。
4 大表也可以作为驱动表,但是需要谓词条件的access或者filter,使数据量降下来。