DEMO : 1回で2万行参照するバッチ処理
ほんとのバッチはこんなもんじゃないのは知ってますよねw.
SCOTT> @demo1_2 1 declare 2 type t_unique_id is table of tab1.unique_id%type index by pls_integer; 3 type t_non_unique_id is table of tab1.non_unique_id%type index by pls_integer; 4 unique_ids t_unique_id; 5 non_unique_ids t_non_unique_id; 6 begin 7 select 8 unique_id 9 ,non_unique_id 10 bulk collect into 11 unique_ids 12 ,non_unique_ids 13 from 14 tab1 15 where 16 unique_id between 1 and 20000 17 and is_delete = 0 18 and status_code = '00' 19 ; 20 dbms_output.put_line('rows:'||unique_ids.last); 21* end; rows:20000
PL/SQLプロシージャが正常に完了しました。
経過: 00:00:00.75
・・・中略・・・
Plan Statistics DB/Inst: DISCUS/discus Snaps: 208-209 -> % Total DB Time is the Elapsed Time of the SQL statement divided into the Total Database Time multiplied by 100
Stat Name Statement Per Execution % Snap ---------------------------------------- ---------- -------------- ------- Elapsed Time (ms) 699 699.0 22.4 CPU Time (ms) 310 310.0 16.3 Executions 1 N/A N/A Buffer Gets 1,648 1,648.0 7.9 Disk Reads 1,584 1,584.0 65.0 Parse Calls 1 1.0 0.1 Rows 20,000 20,000.0 N/A User I/O Wait Time (ms) 585 N/A N/A Cluster Wait Time (ms) 0 N/A N/A Application Wait Time (ms) 0 N/A N/A Concurrency Wait Time (ms) 0 N/A N/A Invalidations 0 N/A N/A Version Count 1 N/A N/A Sharable Mem(KB) 14 N/A N/A -------------------------------------------------------------
Execution Plan --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1579 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| TAB1 | 20000 | 273K| 1579 (1)| 00:00:19 | | 2 | INDEX RANGE SCAN | TAB1_PK | 20000 | | 39 (0)| 00:00:01 | ---------------------------------------------------------------------------------------
Full SQL Text
SQL ID SQL Text ------------ ----------------------------------------------------------------- cbmpgdpxr6vy SELECT UNIQUE_ID , NON_UNIQUE_ID FROM TAB1 WHERE UNIQUE_ID BETWEE EN 1 AND 20000 AND IS_DELETE = 0 AND STATUS_CODE = '00'
Report written to demo1_2_awrsqrpt.txt SCOTT>
|
DEMO : 1行の参照を2万回グルグル回すバッチ処理
単純な比較だからね。1回 vs. 2万回グルグル系の。
グルグル回す処理方式もいろいろな大人の事情で利用する必要があるのもこともわかっていますが、基本的に性能はでないので、それを想定した対処は必要ですよね :)
SCOTT> @demo1_3 1 declare 2 type t_unique_id is table of tab1.unique_id%type index by pls_integer; 3 type t_non_unique_id is table of tab1.non_unique_id%type index by pls_integer; 4 unique_ids t_unique_id; 5 non_unique_ids t_non_unique_id; 6 cursor c1(p_unique_id tab1.unique_id%TYPE) is 7 select 8 unique_id 9 ,non_unique_id 10 from 11 tab1 12 where 13 unique_id = p_unique_id 14 and is_delete = 0 15 and status_code = '00' 16 ; 17 begin 18 for i in 1..20000 loop 19 for c1_rec in c1(i) loop 20 unique_ids(i) := c1_rec.unique_id; 21 non_unique_ids(i) := c1_rec.non_unique_id; 22 end loop; 23 end loop; 24 dbms_output.put_line('rows:'||unique_ids.last); 25* end; rows:20000
PL/SQLプロシージャが正常に完了しました。
・・・中略・・・
Plan Statistics DB/Inst: DISCUS/discus Snaps: 210-211 -> % Total DB Time is the Elapsed Time of the SQL statement divided into the Total Database Time multiplied by 100
Stat Name Statement Per Execution % Snap ---------------------------------------- ---------- -------------- ------- Elapsed Time (ms) 1,456 0.1 37.4 CPU Time (ms) 1,112 0.1 42.2 Executions 20,000 N/A N/A Buffer Gets 60,047 3.0 95.3 Disk Reads 1,587 0.1 75.6 Parse Calls 1 0.0 0.7 Rows 20,000 1.0 N/A User I/O Wait Time (ms) 866 N/A N/A Cluster Wait Time (ms) 0 N/A N/A Application Wait Time (ms) 0 N/A N/A Concurrency Wait Time (ms) 0 N/A N/A Invalidations 0 N/A N/A Version Count 1 N/A N/A Sharable Mem(KB) 18 N/A N/A -------------------------------------------------------------
Execution Plan --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| TAB1 | 1 | 14 | 2 (0)| 00:00:01 | | 2 | INDEX UNIQUE SCAN | TAB1_PK | 1 | | 1 (0)| 00:00:01 | ---------------------------------------------------------------------------------------
Full SQL Text
SQL ID SQL Text ------------ ----------------------------------------------------------------- dvpjay9p4csj SELECT UNIQUE_ID , NON_UNIQUE_ID FROM TAB1 WHERE UNIQUE_ID = :B1 AND IS_DELETE = 0 AND STATUS_CODE = '00'
Report written to demo1_3_awrsqrpt.txt SCOTT>
|
DEMO : DEMO : 1行の参照を2万回グルグル回すバッチ処理をIndex Only Accessでチューニングしたみたよ:)
アクセスブロック数も減ったし、処理時間も短くなった。 グルグル系のはね、SQL文レベルのチューニング限界でもある。
Index Only Accessでチューニングしても、グルグル回ってる回数は同じだから。
SCOTT> @demo1_3_ix create index tab1_ix_demo1_3 on tab1(unique_id,is_delete,status_code,non_unique_id) nologging;
索引が作成されました。
SCOTT> @demo1_3 1 declare 2 type t_unique_id is table of tab1.unique_id%type index by pls_integer; 3 type t_non_unique_id is table of tab1.non_unique_id%type index by pls_integer; 4 unique_ids t_unique_id; 5 non_unique_ids t_non_unique_id; 6 cursor c1(p_unique_id tab1.unique_id%TYPE) is 7 select 8 unique_id 9 ,non_unique_id 10 from 11 tab1 12 where 13 unique_id = p_unique_id 14 and is_delete = 0 15 and status_code = '00' 16 ; 17 begin 18 for i in 1..20000 loop 19 for c1_rec in c1(i) loop 20 unique_ids(i) := c1_rec.unique_id; 21 non_unique_ids(i) := c1_rec.non_unique_id; 22 end loop; 23 end loop; 24 dbms_output.put_line('rows:'||unique_ids.last); 25* end; rows:20000
PL/SQLプロシージャが正常に完了しました。
・・・中略・・・
Plan Statistics DB/Inst: DISCUS/discus Snaps: 212-213 -> % Total DB Time is the Elapsed Time of the SQL statement divided into the Total Database Time multiplied by 100
Stat Name Statement Per Execution % Snap ---------------------------------------- ---------- -------------- ------- Elapsed Time (ms) 498 0.0 11.1 CPU Time (ms) 453 0.0 13.0 Executions 20,000 N/A N/A Buffer Gets 40,088 2.0 74.9 Disk Reads 72 0.0 8.1 Parse Calls 1 0.0 0.2 Rows 20,000 1.0 N/A User I/O Wait Time (ms) 37 N/A N/A Cluster Wait Time (ms) 0 N/A N/A Application Wait Time (ms) 0 N/A N/A Concurrency Wait Time (ms) 0 N/A N/A Invalidations 0 N/A N/A Version Count 1 N/A N/A Sharable Mem(KB) 18 N/A N/A -------------------------------------------------------------
Execution Plan ------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | | | 1 (100)| | | 1 | INDEX RANGE SCAN| TAB1_IX_DEMO1_3 | 1 | 14 | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------
Full SQL Text
SQL ID SQL Text ------------ ----------------------------------------------------------------- dvpjay9p4csj SELECT UNIQUE_ID , NON_UNIQUE_ID FROM TAB1 WHERE UNIQUE_ID = :B1 AND IS_DELETE = 0 AND STATUS_CODE = '00'
Report written to demo1_3_awrsqrpt.txt SCOTT> SCOTT> @drop_demo1_3_ix drop index tab1_ix_demo1_3;
索引が削除されました。
|
DEMO : 暴走するスカラー副問合せ
SELECTリストにあるスカラー副問合せって、クエリ本体でヒットしたデータ件数分グルグル実行されるんだお。
SCOTT> @demo5 alter system flush buffer_cache;
システムが変更されました。
経過: 00:00:00.26 1 select 2 t1.unique_id, 3 t1.item_code, 4 ( 5 select 6 max(t3.unique_id) 7 from 8 tab31 t2 join tab311 t3 9 on 10 t3.sub_item_code = t2.sub_item_code 11 and t3.is_delete = 0 12 where 13 t2.item_code = t1.item_code 14 and t2.is_delete = 0 15 ) current_item 16 from 17 tab3 t1 18 where 19 t1.unique_id between 1 and 10000 20 and t1.is_delete = 0 21* and t1.status_code = '00'
10000行が選択されました。
経過: 00:00:17.54
実行計画 ---------------------------------------------------------- Plan hash value: 2850625377
------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9998 | 253K| 424 (0)| 00:00:06 | | 1 | SORT AGGREGATE | | 1 | 47 | | | | 2 | NESTED LOOPS | | 2 | 94 | 8 (0)| 00:00:01 | |* 3 | TABLE ACCESS BY INDEX ROWID| TAB31 | 1 | 29 | 3 (0)| 00:00:01 | |* 4 | INDEX UNIQUE SCAN | TAB31_PK | 1 | | 2 (0)| 00:00:01 | |* 5 | TABLE ACCESS BY INDEX ROWID| TAB311 | 2 | 36 | 5 (0)| 00:00:01 | |* 6 | INDEX RANGE SCAN | TAB311_IX | 2 | | 2 (0)| 00:00:01 | |* 7 | TABLE ACCESS BY INDEX ROWID | TAB3 | 9998 | 253K| 424 (0)| 00:00:06 | |* 8 | INDEX RANGE SCAN | TAB3_PK | 10000 | | 23 (0)| 00:00:01 | -------------------------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
3 - filter("T2"."IS_DELETE"=0) 4 - access("T2"."ITEM_CODE"=:B1) 5 - filter("T3"."IS_DELETE"=0) 6 - access("T3"."SUB_ITEM_CODE"="T2"."SUB_ITEM_CODE") 7 - filter("T1"."IS_DELETE"=0 AND "T1"."STATUS_CODE"='00') 8 - access("T1"."UNIQUE_ID">=1 AND "T1"."UNIQUE_ID"<=10000)
統計 ---------------------------------------------------------- 1256 recursive calls 0 db block gets 52747 consistent gets 22557 physical reads 116 redo size 326816 bytes sent via SQL*Net to client 7742 bytes received via SQL*Net from client 668 SQL*Net roundtrips to/from client 35 sorts (memory) 0 sorts (disk) 10000 rows processed
SCOTT>
|
DEMO : 暴走するスカラー副問合せをIndex Only Accessでチューニング!
アクセスブロック数が明らかに減った :) 索引だけ参照させることでね :)
SCOTT> @demo5_ix create index tab31_demo_ix on tab31(item_code, is_delete, sub_item_code) nologging;
索引が作成されました。
経過: 00:00:01.18 create index tab311_demo_ix on tab311(sub_item_code, is_delete, unique_id) nologging;
索引が作成されました。
SCOTT> @demo5 alter systen flush buffer_cache;
システムが変更されました。
経過: 00:00:00.18 1 select 2 t1.unique_id, 3 t1.item_code, 4 ( 5 select 6 max(t3.unique_id) 7 from 8 tab31 t2 join tab311 t3 9 on 10 t3.sub_item_code = t2.sub_item_code 11 and t3.is_delete = 0 12 where 13 t2.item_code = t1.item_code 14 and t2.is_delete = 0 15 ) current_item 16 from 17 tab3 t1 18 where 19 t1.unique_id between 1 and 10000 20 and t1.is_delete = 0 21* and t1.status_code = '00'
10000行が選択されました。
経過: 00:00:03.81
実行計画 ---------------------------------------------------------- Plan hash value: 2957188266
---------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9998 | 253K| 424 (0)| 00:00:06 | | 1 | SORT AGGREGATE | | 1 | 47 | | | | 2 | NESTED LOOPS | | 2 | 94 | 5 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | TAB31_DEMO_IX | 1 | 29 | 3 (0)| 00:00:01 | |* 4 | INDEX RANGE SCAN | TAB311_DEMO_IX | 2 | 36 | 2 (0)| 00:00:01 | |* 5 | TABLE ACCESS BY INDEX ROWID| TAB3 | 9998 | 253K| 424 (0)| 00:00:06 | |* 6 | INDEX RANGE SCAN | TAB3_PK | 10000 | | 23 (0)| 00:00:01 | ----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
3 - access("T2"."ITEM_CODE"=:B1 AND "T2"."IS_DELETE"=0) 4 - access("T3"."SUB_ITEM_CODE"="T2"."SUB_ITEM_CODE" AND "T3"."IS_DELETE"=0) 5 - filter("T1"."IS_DELETE"=0 AND "T1"."STATUS_CODE"='00') 6 - access("T1"."UNIQUE_ID">=1 AND "T1"."UNIQUE_ID"<=10000)
統計 ---------------------------------------------------------- 1 recursive calls 0 db block gets 32839 consistent gets 4655 physical reads 0 redo size 326816 bytes sent via SQL*Net to client 7742 bytes received via SQL*Net from client 668 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 10000 rows processed
SCOTT> SCOTT> @drop_demo5_ix drop index tab31_demo_ix;
索引が削除されました。
経過: 00:00:00.42 drop index tab311_demo_ix;
索引が削除されました。
|
DEMO : NULLとハサミは使いよう。(Index Only Accessがその効果を失う日?!)
※セッション中のデモ時間短縮のため”暴走するスカラー副問合せ”のチューニング後の状態を同一条件の別テーブルで再現してあります。
Index Only Accessでチューニングしたはずの、スカラー副問合せが...再び暴れだした。どゆこと?
処理時間も以前より遅くなってるし、かつ特定の部分のROWSが異常に増加していて、Buffer Getsがすごい事になってます。
Index Only Accessのための索引を作ったものの SCOTT> @demo5_2_ix create index tab31_bk_demo_ix on tab31_bk(item_code, is_delete, sub_item_code) nologging;
索引が作成されました。
経過: 00:00:01.25 create index tab311_bk_demo_ix on tab311_bk(sub_item_code, is_delete, unique_id) nologging;
索引が作成されました。
SCOTT> @demo5_2 alter system flush buffer_cache;
システムが変更されました。
経過: 00:00:00.09 1 select 2 t1.unique_id, 3 t1.item_code, 4 ( 5 select 6 max(t3.unique_id) 7 from 8 tab31_bk t2 join tab311_bk t3 9 on 10 t3.sub_item_code = t2.sub_item_code 11 and t3.is_delete = 0 12 where 13 t2.item_code = t1.item_code 14 and t2.is_delete = 0 15 ) current_item 16 from 17 tab3 t1 18 where 19 t1.unique_id between 1 and 10000 20 and t1.is_delete = 0 21* and t1.status_code = '00'
10000行が選択されました。
経過: 00:00:34.59
実行計画 ---------------------------------------------------------- Plan hash value: 3069420010
------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9998 | 253K| 424 (0)| 00:00:06 | | 1 | SORT AGGREGATE | | 1 | 47 | | | | 2 | NESTED LOOPS | | 35974 | 1651K| 5 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | TAB31_BK_DEMO_IX | 1 | 29 | 3 (0)| 00:00:01 | |* 4 | INDEX RANGE SCAN | TAB311_BK_DEMO_IX | 35978 | 632K| 2 (0)| 00:00:01 | |* 5 | TABLE ACCESS BY INDEX ROWID| TAB3 | 9998 | 253K| 424 (0)| 00:00:06 | |* 6 | INDEX RANGE SCAN | TAB3_PK | 10000 | | 23 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
3 - access("T2"."ITEM_CODE"=:B1 AND "T2"."IS_DELETE"=0) 4 - access("T3"."SUB_ITEM_CODE"="T2"."SUB_ITEM_CODE" AND "T3"."IS_DELETE"=0) 5 - filter("T1"."IS_DELETE"=0 AND "T1"."STATUS_CODE"='00') 6 - access("T1"."UNIQUE_ID">=1 AND "T1"."UNIQUE_ID"<=10000)
統計 ---------------------------------------------------------- 1 recursive calls 0 db block gets 896697 consistent gets 5190 physical reads 0 redo size 326829 bytes sent via SQL*Net to client 7742 bytes received via SQL*Net from client 668 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 10000 rows processed
SCOTT>
|
DEMO : NULLとハサミは使いよう。(Index Only Accessがその効果を失う日?!)
なぜ、Index Only Accessが効果を失ってしまったのか。。。
スカラー副問合せのチューニングでは、Index Range ScanやIndex Unique ScanをNested Loop結合かつIndex Only Access化したのだが、
特定の値に大きな偏りがあり、広範囲のIndex Range ScanがNested Loop結合で繰り返されたのがその理由。
特定の値の意味を調査していくと、実はNULLでも問題ないという意味合いしかないことが発覚。
しか〜〜〜し、大人の事情で、該当列をNULLに更新してしまうことは許されない。さて、どのように対処するか!
閃いた!。 Oracle11g で登場した新機能を使え! (恐る恐るw でも事前にKROWNなど調べまくりましたよv)
特定の値をNULLに置換する仮想列を追加して、その列でIndex Only Accesssを実現する索引を作る。さらに、SQL文の結合条件だけは変更してもらう。
(影響範囲を最小にした対処だと思います. 仮想列が無かったら大変だったと思います)
以下の結果の通り、処理時間も以前チューニングした時間まで改善し、広範囲のIndex Range Scanも消えていることが実行計画からも確認できます。めでたしめでたし。
SCOTT> @demo5_2_virtual alter table tab311_bk add (sub_item_code_virtual CHAR(10) as (replace(sub_item_code,' ',null)) virtual); 表が変更されました。
経過: 00:00:00.57
SCOTT> @demo5_2_ix_2 create index tab311_bk_demo_vix on tab311_bk(sub_item_code_virtual, is_delete, unique_id) nologging;
索引が作成されました。
経過: 00:00:05.38
SCOTT> @demo5_2_2 alter system flush buffer_cache;
システムが変更されました。
経過: 00:00:00.07 1 select 2 t1.unique_id, 3 t1.item_code, 4 ( 5 select 6 max(t3.unique_id) 7 from 8 tab31_bk t2 join tab311_bk t3 9 on 10 t3.sub_item_code_virtual = t2.sub_item_code 11 and t3.is_delete = 0 12 where 13 t2.item_code = t1.item_code 14 and t2.is_delete = 0 15 ) current_item 16 from 17 tab3 t1 18 where 19 t1.unique_id between 1 and 10000 20 and t1.is_delete = 0 21* and t1.status_code = '00'
10000行が選択されました。
経過: 00:00:03.45
実行計画 ---------------------------------------------------------- Plan hash value: 2681694377
-------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9998 | 253K| 424 (0)| 00:00:06 | | 1 | SORT AGGREGATE | | 1 | 48 | | | | 2 | NESTED LOOPS | | 7 | 336 | 5 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | TAB31_BK_DEMO_IX | 1 | 29 | 3 (0)| 00:00:01 | |* 4 | INDEX RANGE SCAN | TAB311_BK_DEMO_VIX | 7 | 133 | 2 (0)| 00:00:01 | |* 5 | TABLE ACCESS BY INDEX ROWID| TAB3 | 9998 | 253K| 424 (0)| 00:00:06 | |* 6 | INDEX RANGE SCAN | TAB3_PK | 10000 | | 23 (0)| 00:00:01 | --------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
3 - access("T2"."ITEM_CODE"=:B1 AND "T2"."IS_DELETE"=0) 4 - access("T3"."SUB_ITEM_CODE_VIRTUAL"="T2"."SUB_ITEM_CODE" AND "T3"."IS_DELETE"=0) 5 - filter("T1"."IS_DELETE"=0 AND "T1"."STATUS_CODE"='00') 6 - access("T1"."UNIQUE_ID">=1 AND "T1"."UNIQUE_ID"<=10000)
統計 ---------------------------------------------------------- 22 recursive calls 0 db block gets 32843 consistent gets 4072 physical reads 0 redo size 322687 bytes sent via SQL*Net to client 7742 bytes received via SQL*Net from client 668 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 10000 rows processed
SCOTT> SCOTT> @drop_demo5_2_ix_2 drop index tab311_bk_demo_vix;
索引が削除されました。
経過: 00:00:00.29 SCOTT> @drop_demo5_2_ix drop index tab31_bk_demo_ix;
索引が削除されました。
経過: 00:00:00.37 drop index tab311_bk_demo_ix;
索引が削除されました。
経過: 00:00:00.05
SCOTT> @drop_demo5_2_virtual alter table tab311_bk drop (sub_item_code_virtual);
表が変更されました。
経過: 00:00:00.48
|
最近のコメント