create table wxh_tbd1 as select * from dba_objects;
create table wxh_tbd2 as select * from dba_objects;
create index t_1 on wxh_tbd1(object_name);
create index t_2 on wxh_tbd1(object_id);
create index t_3 on wxh_tbd2(object_name);
insert into wxh_tbd1 select * from wxh_tbd1;
insert into wxh_tbd2 select * from wxh_tbd2;
commit;
select /*+ NO_NLJ_BATCHING(b) */
dbms_rowid.rowid_block_number(b.rowid) bl, a.object_id,b.object_type
from wxh_tbd1 a, wxh_tbd2 b
where a.object_name = b.object_name
and a.object_id > 899 and a.object_id<902;
sys@CRMG>select /*+ NO_NLJ_BATCHING(b) */
2 dbms_rowid.rowid_block_number(b.rowid) bl, a.object_id,b.object_type
3 from wxh_tbd1 a, wxh_tbd2 b
4 where a.object_name = b.object_name
5 and a.object_id > 899 and a.object_id<902;
BL OBJECT_ID OBJECT_TYPE
---------- ---------- --------------------------------------
23667 900 TABLE
32537 900 TABLE
23667 900 TABLE
32537 900 TABLE
23667 901 INDEX
32537 901 INDEX
23667 901 INDEX
32537 901 INDEX
8 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1274335627
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 4200 | 13 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID | WXH_TBD2 | 6 | 534 | 3 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 25 | 4200 | 13 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| WXH_TBD1 | 4 | 316 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | T_2 | 4 | | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | T_3 | 6 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("A"."OBJECT_ID">899 AND "A"."OBJECT_ID"<902)
5 - access("A"."OBJECT_NAME"="B"."OBJECT_NAME")
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
12 recursive calls
0 db block gets
166 consistent gets
0 physical reads
0 redo size
790 bytes sent via SQL*Net to client
524 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
8 rows processed
sys@CRMG>select
dbms_rowid.rowid_block_number(b.rowid) bl, a.object_id,b.object_type
2 3 from wxh_tbd1 a, wxh_tbd2 b
4 where a.object_name = b.object_name
5 and a.object_id > 899 and a.object_id<902;
BL OBJECT_ID OBJECT_TYPE
---------- ---------- --------------------------------------
23667 900 TABLE
32537 900 TABLE
23667 900 TABLE
32537 900 TABLE
23667 901 INDEX
32537 901 INDEX
23667 901 INDEX
32537 901 INDEX
8 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 748461386
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 4200 | 13 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 25 | 4200 | 13 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| WXH_TBD1 | 4 | 316 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | T_2 | 4 | | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | T_3 | 6 | | 1 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID | WXH_TBD2 | 6 | 534 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("A"."OBJECT_ID">899 AND "A"."OBJECT_ID"<902)
5 - access("A"."OBJECT_NAME"="B"."OBJECT_NAME")
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
10 recursive calls
0 db block gets
166 consistent gets
0 physical reads
0 redo size
790 bytes sent via SQL*Net to client
524 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
8 rows processed
------------------------------------------------
| Id | Operation | Name |
------------------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | COUNT STOPKEY | |
| 2 | TABLE ACCESS BY INDEX ROWID | T2 | | 3 | NESTED LOOPS | |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 |
|* 5 | INDEX RANGE SCAN | T1_N1 |
|* 6 | INDEX RANGE SCAN | T2_N1 |
------------------------------------------------
------------------------------------------------
| Id | Operation | Name |
------------------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | COUNT STOPKEY | |
| 2 | NESTED LOOPS | |
| 3 | NESTED LOOPS | |
| 4 | TABLE ACCESS BY INDEX ROWID| T1 |
|* 5 | INDEX RANGE SCAN | T1_N1 |
|* 6 | INDEX RANGE SCAN | T2_N1 |
| 7 | TABLE ACCESS BY INDEX ROWID | T2 | ------------------------------------------------
You might note that Oracle 10g and 11g have very different location of the table lookup operation on the table T2. This is a symptom of the nested loops join optimization of Oracle 11g. By using batching NLJ, you might see a decreased logical reads and improved performance.
as
select 1 as c1, mod(level, 4) as c2, level as c3, level as c4, rpad('x',1000) as dummy
from dual
connect by level <= 1000;
as
select 1001-level as c1, level as c2, rpad('x',1000) as dummy
from dual
connect by level <= 100;
create index t2_n1 on t2(c1);
exec dbms_stats.gather_table_stats(user, 't2');
select /*+ leading(t1 t2) use_nl(t2) index_asc(t1) index_asc(t2) */
rownum as rnum,
t2.c1,
t1.c4,
t2.c2
from t1, t2
where
t1.c3 = t2.c1
and t1.c1 = 1
and t1.c2 = 0
and rownum <= 20
;
alter system flush buffer_cache;
select /*+ leading(t1 t2) use_nl(t2) index_asc(t1) index_asc(t2) */
rownum as rnum,
t2.c1,
t1.c4,
t2.c2
from t1, t2
where
t1.c3 = t2.c1
and t1.c1 = 1
and t1.c2 = 0
and rownum <= 20
) where rnum >= 15
;
select * from (
select /*+ leading(t1 t2) use_nl(t2) index_asc(t1) index_asc(t2) */
rownum as rnum,
t2.c1,
t1.c4,
t2.c2
from t1, t2
where
t1.c3 = t2.c1
and t1.c1 = 1
and t1.c2 = 0
and rownum <= 20
) where rnum >= 15
;
alter session set "_nlj_batching_misses_enabled" = 0;
alter system flush buffer_cache;
select /*+ leading(t1 t2) use_nl(t2) index_asc(t1) index_asc(t2) */
rownum as rnum,
t2.c1,
t1.c4,
t2.c2
from t1, t2
where
t1.c3 = t2.c1
and t1.c1 = 1
and t1.c2 = 0
and rownum <= 20
) where rnum >= 15
;
select * from (
select /*+ leading(t1 t2) use_nl(t2) index_asc(t1) index_asc(t2) */
rownum as rnum,
t2.c1,
t1.c4,
t2.c2
from t1, t2
where
t1.c3 = t2.c1
and t1.c1 = 1
and t1.c2 = 0
and rownum <= 20
) where rnum >= 15
;
To save your time, let me show you the result of the above test case with some comments appended.
-- when the query reads from the disk
RNUM C1 C4 C2
---------- ---------- ---------- ----------
15 960 960 41
16 964 964 37
17 980 980 21 18 968 968 33
19 972 972 29
20 976 976 25
RNUM C1 C4 C2
---------- ---------- ---------- ----------
15 960 960 41
16 964 964 37
17 968 968 33
18 972 972 29
19 976 976 25
20 980 980 21
-- when the query reads from the disk
RNUM C1 C4 C2
---------- ---------- ---------- ----------
15 960 960 41
16 964 964 37
17 968 968 33
18 972 972 29
19 976 976 25
20 980 980 21
RNUM C1 C4 C2
---------- ---------- ---------- ----------
15 960 960 41
16 964 964 37
17 968 968 33
18 972 972 29
19 976 976 25
20 980 980 21
The simple explanation is :
“The new optimization code of the nested loops join does not guarantee that the rows would be returned as an order of the outer table, especially when it reads the data from the disk.”
Set parameter – _nlj_batching_enabled = 0;
Append hint – NO_NLJ_BATCHING(t2)
It seems that I need to do further research on the batching NLJ – it’s exact mechanism and the pitfalls.
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22034023/viewspace-703358/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/22034023/viewspace-703358/
本文详细介绍了 Oracle 11g 中引入的 Batching Nested Loops Join (batchingNLJ) 特性,并通过一个测试案例展示了其在实现分页查询时的使用方式,同时探讨了该特性带来的性能改进和潜在的限制。
15

被折叠的 条评论
为什么被折叠?



