1、生成TOP SQL的执行计划
2、生成 TOP SQL的10046 TRACE文件
3、生成 10046 TRACE的tkprof 解析文件
4、统计信息是否过时,统计信息准确度
4.1 定位性瓶颈
4.1.1 查看统计信息是否过时
4.1.2 对比tkprof 解析文件中的执行计划与AWR生成的执行计划步骤是一致,各步骤中的ROWS是一致,如果步骤不一致
或ROWS相差很大证明统计信息不准确;对比执行计划中的TOP COST (全表扫描)与10046 TRACE中的等待事件是
否对应
4.2 优化
4.2.1 对执行计划与10046中ROWS差距很大的表收集统计信息
4.3 重新执行SQL生产新的执行计划和10046 TRACE,并对新的执行计划和10046 TRACE执行4.1.2的操作
5、优化访问路径(主要是优化全表访问)
5.1 定位性能瓶颈
5.1.1 解析最新执行计划,找到 TOP COST 的全表扫描,并对比执行计划中的TOP COST (全表扫描)与10046 TRACE中的
等待事件是否对应
5.1.2 对比 set autotrace trace 统计的IO信息与tkprof 解析文件中的IO信息是否一致或接近,并对比逻辑IO与物理IO
是否接近,如果逻辑IO与物理IO相差太远,证明SQL还有很大的优化空间
5.2 优化
5.2.1 查看全表扫描的表段大小
5.2.2 统计全表扫描表的ROWS
5.2.3 查看tkprof 解析文件中执行计划的ROWS,如果ROWS很少,却对一张大表进行了全表扫描就需要看是否可以使用索引
优化全表扫描
5.2.4 查看WHERE 子句中过滤的字段的选择性,如果选择性很高就适合创建索引
5.2.5 创建索引并收集统计信息
5.2.6 如果执行计划不稳定可以使用执行计划管理技术固定执行计划
5.3 重新执行SQL生产新的执行计划和10046 TRACE,并对新的执行计划和10046 TRACE执行5.1.1和5.1.2的操作
6. 优化表连接方式
6.1 性能瓶颈定位
6.1.1 查看执行计划,优化TOP COST 表连接
6.1.2 查看 TOP COST 表连相关表和索引段大小,表的ROWS及返回的ROWS(执行计划和10046 TRACE中的都要看)
6.1.3 通过返回的 ROWS、访问路径和IO次数对比,判断表连接方式是否合适。比如嵌套循环连接,返回
100条记录,驱动表过滤后有1000条记录,被驱动表有一千万条记录,假设对被驱动表进行全表扫描
,这个时候使用嵌套循环就不合适了,应该使用HASH连接。返回的ROWS很少,比如只有10条记录,就
适合使用嵌套循环连接。
7、优化表连接顺序(小结果集驱动,尽量减少参与表连接的结果集的数据量)
7.1 定位性能瓶颈
7.1.1 查看执行计划和tkprof 解析文件中执行计划的ROWS,确保每次表连接都是小结果集驱动。
7.2 优化
7.2.1 如果出现大结果集驱动的情况,使用提示固定表连接的顺序使用小结果集驱动
1、生成TOP SQL的执行计划
SQL> set autotrace trace;
SQL> set timing on;
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
2998 rows selected.
Elapsed: 00:00:00.54
Execution Plan
----------------------------------------------------------
Plan hash value: 98820498
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 999 | 38961 | 694 (1)| 00:00:09 |
|* 1 | HASH JOIN | | 999 | 38961 | 694 (1)| 00:00:09 |
|* 2 | HASH JOIN | | 1000 | 9000 | 350 (1)| 00:00:05 |
|* 3 | TABLE ACCESS FULL| T2 | 1000 | 4000 | 6 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T3 | 2941 | 14705 | 344 (1)| 00:00:05 |
|* 5 | TABLE ACCESS FULL | T1 | 2943 | 88290 | 344 (1)| 00:00:05 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
2 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
3 - filter("T2"."OBJECT_ID"<3001)
4 - filter("T3"."OBJECT_ID"<3001)
5 - filter("T1"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
80 recursive calls
0 db block gets
2722 consistent gets
2502 physical reads
0 redo size
72724 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
12 sorts (memory)
0 sorts (disk)
2998 rows processed
SQL> set autotrace off;
执行计划中最后的ROWS是999,统计信息中 rows processed 是2998,说明统计信息不准。
在有数据缓存的情况下再执行SQL
2998 rows selected.
Elapsed: 00:00:00.45
Execution Plan
----------------------------------------------------------
Plan hash value: 98820498
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 999 | 38961 | 694 (1)| 00:00:09 |
|* 1 | HASH JOIN | | 999 | 38961 | 694 (1)| 00:00:09 |
|* 2 | HASH JOIN | | 1000 | 9000 | 350 (1)| 00:00:05 |
|* 3 | TABLE ACCESS FULL| T2 | 1000 | 4000 | 6 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T3 | 2941 | 14705 | 344 (1)| 00:00:05 |
|* 5 | TABLE ACCESS FULL | T1 | 2943 | 88290 | 344 (1)| 00:00:05 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
2 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
3 - filter("T2"."OBJECT_ID"<3001)
4 - filter("T3"."OBJECT_ID"<3001)
5 - filter("T1"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2635 consistent gets --逻辑读和物理读与10046追踪到的逻辑读和物理读次数是一致的,说明 set autorace 中的统计信息是正确的。
2485 physical reads
0 redo size
72724 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2998 rows processed
2、生成 TOP SQL的10046 TRACE文件
alter session set tracefile_identifier='10046_0619_1';
alter session set events '10046 trace name context forever, level 12';
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
alter session set events '10046 trace name context off';
3、生成 10046 TRACE的tkprof 解析文件
tkprof orcl_ora_5968_10046_0619_1.trc 10046_0619_1.txt
4、统计信息是否过时,统计信息准确度
4.1 定位性瓶颈
4.1.1 查看统计信息是否过时,经检查统计信息没过时。
SELECT owner,
table_name,
num_rows,
sample_size,
STALE_STATS,
trunc(sample_size / num_rows * 100) estimate_percent
FROM DBA_TAB_STATISTICS
WHERE owner='LIXIA' AND table_name in('T3','T1','T2');
OWNER TABLE_NAME NUM_ROWS SAMPLE_SIZE STA ESTIMATE_PERCENT
------------------------------ ------------------------------ ---------- ----------- --- ----------------
LIXIA T1 86318 86318 NO 100
LIXIA T2 1000 1000 NO 100
LIXIA T3 86327 86327 NO 100
4.1.2 对比tkprof 解析文件中的执行计划与AWR生成的执行计划步骤是一致,各步骤中的ROWS是一致,如果步骤不一致
或ROWS相差很大证明统计信息不步骤;对比执行计划中的TOP COST (全表扫描)与10046 TRACE中的等待事件是
否对应。经检查统计信息不准确。
tkprof 解析文件10046_0619_1.txt 追踪到的实际ROWS,与执行计划中的统计信息估算的ROWS相差太远,说明统计信息不准。
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.06 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 201 0.06 0.44 2485 2635 0 2998
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 203 0.06 0.50 2485 2635 0 2998
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Rows Row Source Operation
------- ---------------------------------------------------
2998 HASH JOIN (cr=2635 pr=2485 pw=0 time=242416 us cost=694 size=38961 card=999)
2998 HASH JOIN (cr=1269 pr=1252 pw=0 time=36547 us cost=350 size=9000 card=1000)
1000 TABLE ACCESS FULL T2 (cr=15 pr=0 pw=0 time=567 us cost=6 size=4000 card=1000)
4998 TABLE ACCESS FULL T3 (cr=1254 pr=1252 pw=0 time=32534 us cost=344 size=14705 card=2941)
2998 TABLE ACCESS FULL T1 (cr=1366 pr=1233 pw=0 time=25298 us cost=344 size=88290 card=2943)
4.2 优化
4.2.1 对执行计划与10046中ROWS差距很大的表收集统计信息
exec dbms_stats.gather_table_stats('LIXIA','T3',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO');
exec dbms_stats.gather_table_stats('LIXIA','T2',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO');
exec dbms_stats.gather_table_stats('LIXIA','T1',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO');
4.3 重新执行SQL生产新的执行计划和10046 TRACE,并对新的执行计划和10046 TRACE执行4.1.2的操作
收集统计信息后SQL执行计划表连接的顺序发生了改变
SQL> set autotrace trace;
SQL> set timing on;
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
Elapsed: 00:00:00.26
Execution Plan
----------------------------------------------------------
Plan hash value: 1184213596
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 39000 | 699 (1)| 00:00:09 |
|* 1 | HASH JOIN | | 1000 | 39000 | 699 (1)| 00:00:09 |
|* 2 | HASH JOIN | | 1000 | 34000 | 350 (1)| 00:00:05 |
|* 3 | TABLE ACCESS FULL| T2 | 1000 | 4000 | 6 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T1 | 2943 | 88290 | 344 (1)| 00:00:05 |
|* 5 | TABLE ACCESS FULL | T3 | 4324 | 21620 | 349 (1)| 00:00:05 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
3 - filter("T2"."OBJECT_ID"<3001)
4 - filter("T1"."OBJECT_ID"<3001)
5 - filter("T3"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2704 consistent gets
1252 physical reads
0 redo size
91045 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2998 rows processed
按100%的采样比例收集统计信息,执行计划中T3和T1表的ROWS接近实际ROWS,但ID0和ID1的ROWS为1000,与实际不符(统计信息是准确的,
估计是CBO估算算法的问题)。
exec dbms_stats.gather_table_stats('LIXIA','T3',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO',estimate_percent => 100);
exec dbms_stats.gather_table_stats('LIXIA','T2',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO',estimate_percent => 100);
exec dbms_stats.gather_table_stats('LIXIA','T1',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO',estimate_percent => 100);
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
Elapsed: 00:00:00.26
Execution Plan
----------------------------------------------------------
Plan hash value: 1184213596
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 39000 | 699 (1)| 00:00:09 |
|* 1 | HASH JOIN | | 1000 | 39000 | 699 (1)| 00:00:09 |
|* 2 | HASH JOIN | | 1000 | 34000 | 350 (1)| 00:00:05 |
|* 3 | TABLE ACCESS FULL| T2 | 1000 | 4000 | 6 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T1 | 2943 | 88290 | 344 (1)| 00:00:05 |
|* 5 | TABLE ACCESS FULL | T3 | 4995 | 24975 | 349 (1)| 00:00:05 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
3 - filter("T2"."OBJECT_ID"<3001)
4 - filter("T1"."OBJECT_ID"<3001)
5 - filter("T3"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
2704 consistent gets
1252 physical reads
0 redo size
91045 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2998 rows processed
5、优化访问路径(主要是优化全表访问)
5.1 定位性能瓶颈
5.1.1 解析最新执行计划,找到 TOP COST 的全表扫描,并对比执行计划中的TOP COST (全表扫描)与10046 TRACE中的
等待事件是否对应
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
2998 rows selected.
Elapsed: 00:00:00.49
Execution Plan
----------------------------------------------------------
Plan hash value: 1184213596
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 39000 | 699 (1)| 00:00:09 |
|* 1 | HASH JOIN | | 1000 | 39000 | 699 (1)| 00:00:09 |
|* 2 | HASH JOIN | | 1000 | 34000 | 350 (1)| 00:00:05 |
|* 3 | TABLE ACCESS FULL| T2 | 1000 | 4000 | 6 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T1 | 2943 | 88290 | 344 (1)| 00:00:05 |
|* 5 | TABLE ACCESS FULL | T3 | 4995 | 24975 | 349 (1)| 00:00:05 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
3 - filter("T2"."OBJECT_ID"<3001)
4 - filter("T1"."OBJECT_ID"<3001)
5 - filter("T3"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2702 consistent gets
2485 physical reads
0 redo size
91045 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2998 rows processed
TOP CONST 是在T1和T3表的全表扫描
5.1.2 对比 set autotrace trace 统计的IO信息与tkprof 解析文件中的IO信息是否一致或接近,并对比逻辑IO与物理IO
是否接近,如果逻辑IO与物理IO相差太远,证明SQL还有很大的优化空间
SQL> set autotrace off;
SQL> alter session set tracefile_identifier='10046_621_2';
Session altered.
Elapsed: 00:00:00.04
SQL> alter session set events '10046 trace name context forever, level 12';
Session altered.
Elapsed: 00:00:00.10
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
alter session set events '10046 trace name context off';
tkprof orcl_ora_5624_10046_621_2.trc 10046_621_2.txt
********************************************************************************
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.05 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 201 0.09 0.48 2485 2702 0 2998
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 203 0.10 0.54 2485 2702 0 2998
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Rows Row Source Operation
------- ---------------------------------------------------
2998 HASH JOIN (cr=2702 pr=2485 pw=0 time=313515 us cost=699 size=39000 card=1000)
1000 HASH JOIN (cr=1250 pr=1233 pw=0 time=35488 us cost=350 size=34000 card=1000)
1000 TABLE ACCESS FULL T2 (cr=15 pr=0 pw=0 time=815 us cost=6 size=4000 card=1000)
2998 TABLE ACCESS FULL T1 (cr=1235 pr=1233 pw=0 time=32558 us cost=344 size=88290 card=2943)
4998 TABLE ACCESS FULL T3 (cr=1452 pr=1252 pw=0 time=21496 us cost=349 size=24975 card=4995)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 201 0.00 0.00
direct path read 299 0.02 0.33
SQL*Net message from client 201 17.28 26.72
********************************************************************************
统计信息估算的card(rows)与10046追踪到的实际ROWS很接近,证明统计信息是正确的。
5.2 优化
5.2.1 查看全表扫描的表段大小
SQL> select bytes/1024/1024 m from dba_segments where segment_name='T1';
M
----------
10
SQL> select bytes/1024/1024 m from dba_segments where segment_name='T2' and owner='LIXIA';
M
----------
.125
SQL> select bytes/1024/1024 m from dba_segments where segment_name='T3' and owner='LIXIA';
M
----------
10
5.2.2 统计全表扫描表的ROWS
SQL> select NUM_ROWS,TABLE_NAME from dba_tables where table_name in ('T1','T2','T3') and OWNER='LIXIA';
NUM_ROWS TABLE_NAME
---------- ------------------------------
88327 T3
1000 T2
86318 T1
SELECT owner,
table_name,
num_rows,
sample_size,
STALE_STATS,
trunc(sample_size / num_rows * 100) estimate_percent
FROM DBA_TAB_STATISTICS
WHERE owner='LIXIA' AND table_name=upper('T3');
OWNER TABLE_NAME NUM_ROWS SAMPLE_SIZE STA ESTIMATE_PERCENT
------------------------------ ------------------------------ ---------- ----------- --- ----------------
LIXIA T3 88327 88327 NO 100
SELECT owner,
table_name,
num_rows,
sample_size,
STALE_STATS,
trunc(sample_size / num_rows * 100) estimate_percent
FROM DBA_TAB_STATISTICS
WHERE owner='LIXIA' AND table_name in('T3','T1','T2');
OWNER TABLE_NAME NUM_ROWS SAMPLE_SIZE STA ESTIMATE_PERCENT
------------------------------ ------------------------------ ---------- ----------- --- ----------------
LIXIA T1 86318 86318 NO 100
LIXIA T2 1000 1000 NO 100
LIXIA T3 88327 88327 NO 100
5.2.3 查看tkprof 解析文件中执行计划的ROWS(谓词选择性),如果ROWS很少,却对一张大表进行了全表扫描就需要看是否可以使用索引
优化全表扫描
Rows Row Source Operation
------- ---------------------------------------------------
2998 HASH JOIN (cr=2702 pr=2485 pw=0 time=313515 us cost=699 size=39000 card=1000)
1000 HASH JOIN (cr=1250 pr=1233 pw=0 time=35488 us cost=350 size=34000 card=1000)
1000 TABLE ACCESS FULL T2 (cr=15 pr=0 pw=0 time=815 us cost=6 size=4000 card=1000)
2998 TABLE ACCESS FULL T1 (cr=1235 pr=1233 pw=0 time=32558 us cost=344 size=88290 card=2943)
4998 TABLE ACCESS FULL T3 (cr=1452 pr=1252 pw=0 time=21496 us cost=349 size=24975 card=4995)
T3表总记录数有88327条,返回的记录数是 4998,返回记录数为全表记录数的5.659%(4998/88327*100= 5.659 )。
T1表总记录数有86318条,返回的记录数是 2998,返回记录数为全表记录数的3.473%(2998/86318*100= 3.473 )。
T3和T1表的谓词选择性很好适合创建索引。
5.2.4 查看WHERE 子句中过滤的字段的选择性,如果选择性很高就适合创建索引
--查看字段的平均选择性
SQL> select 1/count( distinct object_id)*100 from lixia.t3;
1/COUNT(DISTINCTOBJECT_ID)*100
------------------------------
.001158373
SQL> select 1/count( distinct object_id)*100 from lixia.t1;
1/COUNT(DISTINCTOBJECT_ID)*100
------------------------------
.00115852
SQL> select 1/count( distinct object_id)*100 from lixia.t2;
1/COUNT(DISTINCTOBJECT_ID)*100
------------------------------
.1
T1/T2/T3表的OBJECT_ID选择性都是非常好的。
这里平均选择性非常好就不需要查看每个唯一值的选择性了,如果平均选择性不好比如5%或20%,就要看选择性不好
排在前十的唯一值的选择性。
select * from (
select num,count(1) v_rows,num/(select count(1) from lixia.t3)*100 xzx
from (
select count(1) num from lixia.t3 group by object_id
) group by num
) where rownum<11;
NUM V_ROWS XZX
---------- ---------- ----------
1 85331 .001132157
2 997 .002264313
1002 1 1.13442096
NUM是唯一值的记录数,V_ROWS是唯一值记录数出现的次数(比如第一行NUM为1,V_ROWS为85331表示有85331个唯一值的记录数为一),
有一个唯一值有1002条记录数,该唯一值的选择性为1.134%。T3表的OBJECT_ID字段是很适合创建索引的。
select * from (
select num,count(1) v_rows,num/(select count(1) from lixia.t2)*100 xzx
from (
select count(1) num from lixia.t2 group by object_id
) group by num
) where rownum<11;
NUM V_ROWS XZX
---------- ---------- ----------
1 1000 .1
select * from (
select num,count(1) v_rows,num/(select count(1) from lixia.t1)*100 xzx
from (
select count(1) num from lixia.t1 group by object_id
) group by num
) where rownum<11;
NUM V_ROWS XZX
---------- ---------- ----------
1 86318 .001158507
5.2.5 创建索引并收集统计信息
create index lixia.idx_t1_object_id on lixia.t1(object_id);
create index lixia.idx_t2_object_id on lixia.t2(object_id);
create index lixia.idx_t3_object_id on lixia.t3(object_id);
exec dbms_stats.gather_table_stats('LIXIA','T3',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO');
exec dbms_stats.gather_table_stats('LIXIA','T2',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO');
exec dbms_stats.gather_table_stats('LIXIA','T1',cascade=>true,no_invalidate=> FALSE,method_opt=>'FOR ALL COLUMNS SIZE AUTO');
5.2.6 如果执行计划不稳定可以使用执行计划管理技术固定执行计划
5.3 重新执行SQL生产新的执行计划和10046 TRACE,并对新的执行计划和10046 TRACE执行5.1.1和5.1.2的操作
SQL> set autotrace trace;
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
----------------------------------------------------------
Plan hash value: 804385229
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 39000 | 70 (0)| 00:00:01 |
|* 1 | HASH JOIN | | 1000 | 39000 | 70 (0)| 00:00:01 |
|* 2 | HASH JOIN | | 1000 | 34000 | 57 (0)| 00:00:01 |
|* 3 | INDEX FAST FULL SCAN | IDX_T2_OBJECT_ID | 1000 | 4000 | 3 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 | 2943 | 88290 | 54 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | IDX_T1_OBJECT_ID | 2943 | | 8 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_T3_OBJECT_ID | 5098 | 25490 | 13 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
3 - filter("T2"."OBJECT_ID"<3001)
5 - access("T1"."OBJECT_ID"<3001)
6 - access("T3"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
269 consistent gets
0 physical reads
0 redo size
72726 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2998 rows processed
逻辑读269,物理读为零,逻辑读不到优化优化前的十分之一。
清空缓冲池再执行SQL
alter system flush buffer_cache;
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
Execution Plan
----------------------------------------------------------
Plan hash value: 804385229
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 39000 | 70 (0)| 00:00:01 |
|* 1 | HASH JOIN | | 1000 | 39000 | 70 (0)| 00:00:01 |
|* 2 | HASH JOIN | | 1000 | 34000 | 57 (0)| 00:00:01 |
|* 3 | INDEX FAST FULL SCAN | IDX_T2_OBJECT_ID | 1000 | 4000 | 3 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 | 2943 | 88290 | 54 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | IDX_T1_OBJECT_ID | 2943 | | 8 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_T3_OBJECT_ID | 5098 | 25490 | 13 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
3 - filter("T2"."OBJECT_ID"<3001)
5 - access("T1"."OBJECT_ID"<3001)
6 - access("T3"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
269 consistent gets
64 physical reads
0 redo size
72725 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2998 rows processed
逻辑读269,物理读64
清空缓冲池再执行SQL,并启用10046事件
SQL> set autotrace off;
alter system flush buffer_cache;
alter session set tracefile_identifier='10046_622_1';
alter session set events '10046 trace name context forever, level 12';
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
alter session set events '10046 trace name context off';
tkprof orcl_ora_568_10046_622_1.trc 10046_622_1.txt
********************************************************************************
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.05 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 201 0.01 0.15 64 269 0 2998
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 203 0.01 0.21 64 269 0 2998
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Rows Row Source Operation
------- ---------------------------------------------------
2998 HASH JOIN (cr=269 pr=64 pw=0 time=205437 us cost=70 size=39000 card=1000)
1000 HASH JOIN (cr=57 pr=52 pw=0 time=76444 us cost=57 size=34000 card=1000)
1000 INDEX FAST FULL SCAN IDX_T2_OBJECT_ID (cr=6 pr=5 pw=0 time=35764 us cost=3 size=4000 card=1000)(object id 88067)
2998 TABLE ACCESS BY INDEX ROWID T1 (cr=51 pr=47 pw=0 time=39932 us cost=54 size=88290 card=2943)
2998 INDEX RANGE SCAN IDX_T1_OBJECT_ID (cr=8 pr=8 pw=0 time=21449 us cost=8 size=0 card=2943)(object id 88066)
4998 INDEX RANGE SCAN IDX_T3_OBJECT_ID (cr=212 pr=12 pw=0 time=19739 us cost=13 size=25490 card=5098)(object id 88068)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 201 0.00 0.00
db file sequential read 60 0.01 0.08
db file scattered read 1 0.00 0.00
SQL*Net message from client 201 1.44 5.97
********************************************************************************
从tkprof解析过的文件中我们看到时间返回的ROWS与CBO估计返回的ROWS是很接近的。实际执行计划于set autotrace 中看到的执行计划是一致的。
INDEX FAST FULL SCAN IDX_T2_OBJECT_ID引发了db file scattered read。
6. 优化表连接方式
6.1 性能瓶颈定位
6.1.1 查看执行计划,优化TOP COST 表连接
alter system flush buffer_cache;
select /*+ use_nl(t1,t2,t3)*/ t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
Execution Plan
----------------------------------------------------------
Plan hash value: 1009382155
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 39000 | 3004 (1)| 00:00:37 |
| 1 | NESTED LOOPS | | 1000 | 39000 | 3004 (1)| 00:00:37 |
| 2 | NESTED LOOPS | | 1000 | 39000 | 3004 (1)| 00:00:37 |
| 3 | NESTED LOOPS | | 1000 | 9000 | 1003 (0)| 00:00:13 |
|* 4 | INDEX FAST FULL SCAN | IDX_T2_OBJECT_ID | 1000 | 4000 | 3 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | IDX_T3_OBJECT_ID | 1 | 5 | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_T1_OBJECT_ID | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 30 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("T2"."OBJECT_ID"<3001)
5 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
filter("T3"."OBJECT_ID"<3001)
6 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
filter("T1"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1158 consistent gets
30 physical reads
0 redo size
73024 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2998 rows processed
1158次逻辑读,30次物理读。 COST 为3004。COST远大于HASH 表连接。
在这个执行计划中,访问路径都是进行的索引扫描成本很大,成本是在进行嵌套循环连接中变的很大。
********************************************************************************
select /*+ use_nl(t1,t2,t3)*/ t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.11 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 201 0.14 0.28 30 1160 0 2998
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 203 0.15 0.39 30 1160 0 2998
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Rows Row Source Operation
------- ---------------------------------------------------
2998 NESTED LOOPS (cr=1160 pr=30 pw=0 time=2411231 us cost=3004 size=39000 card=1000)
2998 NESTED LOOPS (cr=947 pr=17 pw=0 time=2287591 us cost=3004 size=39000 card=1000)
2998 NESTED LOOPS (cr=522 pr=13 pw=0 time=2250210 us cost=1003 size=9000 card=1000)
1000 INDEX FAST FULL SCAN IDX_T2_OBJECT_ID (cr=140 pr=5 pw=0 time=54356 us cost=3 size=4000 card=1000)(object id 88067)
2998 INDEX RANGE SCAN IDX_T3_OBJECT_ID (cr=382 pr=8 pw=0 time=61004 us cost=1 size=5 card=1)(object id 88068)
2998 INDEX RANGE SCAN IDX_T1_OBJECT_ID (cr=425 pr=4 pw=0 time=61453 us cost=1 size=0 card=1)(object id 88066)
2998 TABLE ACCESS BY INDEX ROWID T1 (cr=213 pr=13 pw=0 time=96282 us cost=2 size=30 card=1)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 201 0.00 0.00
Disk file operations I/O 1 0.01 0.01
db file sequential read 26 0.04 0.19
db file scattered read 1 0.00 0.00
SQL*Net message from client 201 4.35 14.59
********************************************************************************
tkprof解析的10046 事件中T3和T1ROWS为2998,CBO估算只有一条数据返回,两者相差太远。
查看了统计信息收集的采样比例为100%,而且统计信息也没过时,ROWS不一致估计是CBO算法
的问题。
SELECT owner,
table_name,
num_rows,
sample_size,
STALE_STATS,
trunc(sample_size / num_rows * 100) estimate_percent
FROM DBA_TAB_STATISTICS
WHERE owner='LIXIA' AND table_name in ('T1','T2','T3');
OWNER TABLE_NAME NUM_ROWS SAMPLE_SIZE STA ESTIMATE_PERCENT
------------------------------ ------------------------------ ---------- ----------- --- ----------------
LIXIA T1 86318 86318 NO 100
LIXIA T2 1000 1000 NO 100
LIXIA T3 88327 88327 NO 100
6.1.2 查看 TOP COST 表连相关表和索引段大小表的ROWS
6.1.3 通过返回的 ROWS、访问路径和IO次数对比,判断表连接方式是否合适。比如嵌套循环连接,返回
100条记录,驱动表过滤后有1000条记录,被驱动表有一千万条记录,假设对被驱动表进行全表扫描
,这个时候使用嵌套循环就不合适了,应该使用HASH连接。返回的ROWS很少,比如只有10条记录,就
适合使用嵌套循环连接。
通过 tkprof的解析文件我们可以看到SQL返回的数据有2998条,使用嵌套循环连接是不合适的。而且在执行计划中
索引扫描和回表的成本都很低,表连接的成本很高(TOP COST)。
优化:去除提示让CBO选择HASH 连接。
7、优化表连接顺序(小结果集驱动,尽量减少参与表连接的结果集的数据量)
7.1 定位性能瓶颈
7.1.1 查看执行计划和tkprof 解析文件中执行计划的ROWS,确保每次表连接都是小结果集驱动。
alter system flush buffer_cache;
select /*+ leading(t3,t1,t2)*/ t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
Execution Plan
----------------------------------------------------------
Plan hash value: 1137224572
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 39000 | 270K (1)| 00:54:06 |
|* 1 | HASH JOIN | | 1000 | 39000 | 270K (1)| 00:54:06 |
|* 2 | INDEX FAST FULL SCAN | IDX_T2_OBJECT_ID | 1000 | 4000 | 3 (0)| 00:00:01 |
| 3 | MERGE JOIN CARTESIAN | | 15M| 500M| 270K (1)| 00:54:06 |
|* 4 | INDEX RANGE SCAN | IDX_T3_OBJECT_ID | 5098 | 25490 | 13 (0)| 00:00:01 |
| 5 | BUFFER SORT | | 2943 | 88290 | 270K (1)| 00:54:06 |
| 6 | TABLE ACCESS BY INDEX ROWID| T1 | 2943 | 88290 | 53 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IDX_T1_OBJECT_ID | 2943 | | 7 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID" AND "T2"."OBJECT_ID"="T3"."OBJECT_ID")
2 - filter("T2"."OBJECT_ID"<3001)
4 - access("T3"."OBJECT_ID"<3001)
7 - access("T1"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
269 consistent gets
64 physical reads
0 redo size
72725 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
2998 rows processed
使用leading提示后,连接方式和连接顺序都是错误的,出现了迪卡儿乘机连接,连接顺序如下:
1)第一步T3连接(迪卡儿乘积连接)T1
2)第一步的结果集连接T2表
alter system flush buffer_cache;
alter session set tracefile_identifier='10046_622_5';
alter session set events '10046 trace name context forever, level 12';
select /*+ leading(t3,t1,t2)*/ t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
alter session set events '10046 trace name context off';
select /*+ leading(t3,t1,t2)*/ t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 201 5.27 5.44 64 269 0 2998
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 203 5.27 5.44 64 269 0 2998
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Rows Row Source Operation
------- ---------------------------------------------------
2998 HASH JOIN (cr=269 pr=64 pw=0 time=3321663 us cost=270485 size=39000 card=1000)
1000 INDEX FAST FULL SCAN IDX_T2_OBJECT_ID (cr=6 pr=5 pw=0 time=34602 us cost=3 size=4000 card=1000)(object id 88067)
14984004 MERGE JOIN CARTESIAN (cr=263 pr=59 pw=0 time=6804213 us cost=270439 size=525150115 card=15004289)
4998 INDEX RANGE SCAN IDX_T3_OBJECT_ID (cr=212 pr=12 pw=0 time=16938 us cost=13 size=25490 card=5098)(object id 88068)
14984004 BUFFER SORT (cr=51 pr=47 pw=0 time=3307091 us cost=270426 size=88290 card=2943)
2998 TABLE ACCESS BY INDEX ROWID T1 (cr=51 pr=47 pw=0 time=24662 us cost=53 size=88290 card=2943)
2998 INDEX RANGE SCAN IDX_T1_OBJECT_ID (cr=8 pr=8 pw=0 time=7519 us cost=7 size=0 card=2943)(object id 88066)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 201 0.00 0.00
db file sequential read 60 0.03 0.09
db file scattered read 1 0.00 0.00
SQL*Net message from client 201 0.01 1.19
7.2 优化
7.2.1 如果出现大结果集驱动的情况,使用提示固定表连接的顺序使用小结果集驱动
优化这个测试SQL的办法就是取消leading,让ORACLE 选择正确的表连接方式和正确的连接顺序
注意:错误使用提示指定表连接的顺序,生成的执行计划的连接方式和连接顺序都是错误的。
alter system flush buffer_cache;
alter session set tracefile_identifier='10046_622_4';
alter session set events '10046 trace name context forever, level 12';
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001;
alter session set events '10046 trace name context off';
select t1.object_id,t1.object_name
from lixia.t1 ,lixia.t2 ,lixia.t3
where t1.object_id=t2.object_id
and t2.object_id=t3.object_id
and t1.object_id <3001
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 201 0.07 0.15 64 269 0 2998
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 203 0.07 0.15 64 269 0 2998
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Rows Row Source Operation
------- ---------------------------------------------------
2998 HASH JOIN (cr=269 pr=64 pw=0 time=147255 us cost=70 size=39000 card=1000)
1000 HASH JOIN (cr=57 pr=52 pw=0 time=47223 us cost=57 size=34000 card=1000)
1000 INDEX FAST FULL SCAN IDX_T2_OBJECT_ID (cr=6 pr=5 pw=0 time=16604 us cost=3 size=4000 card=1000)(object id 88067)
2998 TABLE ACCESS BY INDEX ROWID T1 (cr=51 pr=47 pw=0 time=21771 us cost=54 size=88290 card=2943)
2998 INDEX RANGE SCAN IDX_T1_OBJECT_ID (cr=8 pr=8 pw=0 time=4735 us cost=8 size=0 card=2943)(object id 88066)
4998 INDEX RANGE SCAN IDX_T3_OBJECT_ID (cr=212 pr=12 pw=0 time=23644 us cost=13 size=25490 card=5098)(object id 88068)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 201 0.00 0.00
db file sequential read 60 0.01 0.06
db file scattered read 1 0.00 0.00
SQL*Net message from client 201 1.25 5.58
alter system flush buffer_cache;
set autotrace trace;
Execution Plan
----------------------------------------------------------
Plan hash value: 804385229
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 39000 | 70 (0)| 00:00:01 |
|* 1 | HASH JOIN | | 1000 | 39000 | 70 (0)| 00:00:01 |
|* 2 | HASH JOIN | | 1000 | 34000 | 57 (0)| 00:00:01 |
|* 3 | INDEX FAST FULL SCAN | IDX_T2_OBJECT_ID | 1000 | 4000 | 3 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 | 2943 | 88290 | 54 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | IDX_T1_OBJECT_ID | 2943 | | 8 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_T3_OBJECT_ID | 5098 | 25490 | 13 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
3 - filter("T2"."OBJECT_ID"<3001)
5 - access("T1"."OBJECT_ID"<3001)
6 - access("T3"."OBJECT_ID"<3001)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
269 consistent gets
64 physical reads
0 redo size
72725 bytes sent via SQL*Net to client
2665 bytes received via SQL*Net from client
201 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2998 rows processed