此脚本不依赖统计信息。
两表关联返回少量数据应该走嵌套循环,如果返回大量数据,应该走 HASH 连接,或者是排序合并连接。如果一个 SQL 语句返回行数较多(大于 1 万行),SQL 的执行计划在最后几步(Id<=5)走了嵌套循环,我们可以判定该执行计划中的嵌套循环是有问题的,应该走 HASH 连接。以下脚本抓出返回行数较多的嵌套循环 SQL。
select *from (select parsing_schema_name schema,sql_id,sql_text,rows_processed / executions rows_processedfrom v$sqlwhere parsing_schema_name = 'SCOTT'and executions > 0and rows_processed / executions > 10000order by 4 desc) awhere a.sql_id in (select sql_idfrom v$sql_planwhere operation like '%NESTED LOOPS%'and id <= 5);
在 scott 账户中分别创建 a 表和 b 表以及一个索引。
create table a as select * from dba_objects;
Table created.
create table b as select * from dba_objects;
Table created.
create index idx_b on b(object_id);
Index created.
运行如下 SQL 并且查看执行计划。
select /*+ use_nl(a,b) */ * from a,b where a.object_id=b.object_id;
72695 rows selected.Execution Plan----------------------------------------------------------Plan hash value: 2104163270-------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 60140 | 23M| 120K (1)| 00:24:07 || 1 | NESTED LOOPS | | | | | || 2 | NESTED LOOPS | | 60140 | 23M| 120K (1)| 00:24:07 || 3 | TABLE ACCESS FULL | A | 60140 | 11M| 187 (2)| 00:00:03 ||* 4 | INDEX RANGE SCAN | IDX_B | 1 | | 1 (0)| 00:00:01 || 5 | TABLE ACCESS BY INDEX ROWID| B | 1 | 207 | 2 (0)| 00:00:01 |-------------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------4 - access("A"."OBJECT_ID"="B"."OBJECT_ID")Note------ dynamic sampling used for this statement (level=2)Statistics----------------------------------------------------------632 recursive calls0 db block gets22985 consistent gets1196 physical reads0 redo size6085032 bytes sent via SQL*Net to client53725 bytes received via SQL*Net from client4848 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)72695 rows processed
我们可以使用脚本将错误的嵌套循环抓出。
select *from (select parsing_schema_name schema,sql_id,sql_text,rows_processed / executions rows_processedfrom v$sqlwhere parsing_schema_name = 'SCOTT'and executions > 0and rows_processed / executions > 10000order by 4 desc) awhere a.sql_id in (select sql_idfrom v$sql_planwhere operation like '%NESTED LOOPS%'and id <= 5);
SCHEMA SQL_ID SQL_TEXT ROWS_PROCESSED--------------- --------------- ------------------------------ --------------SCOTT 4dwp5u34yv7mj select /*+ use_nl(a,b) */ * 72695from a,b where a.object_id=b.object_id
