JPOUG in 15 minutes #8
三原 健一
自己紹介
• フリーランス
• 現在:大手SIerの性能問題解決チームに従事
• 過去1年数ヶ月は主にSQLチューニングの日々
• ブログ:「サイクル&オラクル」
http://onefact.jp/wp/
• DB Online記事執筆:「Oracle技術者から見た、SAP HANA」
https://enterprisezine.jp/article/corner/440
アジェンダ
• 実行計画ツリーとその見方
• 実行計画を見やすくするTips
• チューニングの実際
SELECT /*+ ONLINE_SQL04S
INDEX(T004 I_TABLE004_8) INDEX(T001 I_TABLE001_2)
USE_NL(T002)
LEADING(T001 T004 T002) */
COUNT(*) AS COUNTNUM
FROM
TABLE_004 T004
INNER JOIN
TABLE_001 T001
ON (T004.COL3091 = T001.COL3091
AND T004.COLA269 = T001.COLA269)
LEFT OUTER JOIN
TABLE_002 T002
ON (T002.COLA215 = T001.COLA215
AND T002.COL3091 = T004.COL3091)
WHERE
..... 以下省略 ..........
COUNTNUM
----------
1
経過: 00:03:27.35
チューニング前SQLと実行結果
← オンラインSQLなので目標レスポンス時間は3秒以内
Plan hash value: 239732999
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts || A-Rows | A-Time ||
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 || 1 |00:03:27.34 ||
| 1 | SORT AGGREGATE | | 1 || 1 |00:03:27.34 ||
|* 2 | COUNT STOPKEY | | 1 || 1 |00:03:27.34 ||
|* 3 | FILTER | | 1 || 1 |00:03:27.34 ||
|* 4 | FILTER | | 1 || 1 |00:03:27.34 ||
| 5 | NESTED LOOPS OUTER | | 1 || 1 |00:03:27.34 ||
| 6 | NESTED LOOPS | | 1 || 1 |00:03:27.33 ||
|* 7 | TABLE ACCESS BY INDEX ROWID BATCHED | TABLE_001 | 1 || 3060 |00:00:03.12 ||
|* 8 | INDEX SKIP SCAN | I_TABLE001_2 | 1 || 3060 |00:00:02.96 ||
| 9 | PARTITION RANGE ITERATOR | | 3060 || 1 |00:03:24.20 ||
|* 10 | TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| TABLE_004 | 3060 || 1 |00:03:24.19 ||
|* 11 | INDEX RANGE SCAN | I_TABLE004_8 | 3060 || 1 |00:03:24.17 ||
|* 12 | INDEX RANGE SCAN | I_TABLE002PK | 1 || 0 |00:00:00.01 ||
----------------------------------------------------------------------------------------------------------
参考:「SQLチューニングに必要な考え方と最新テクニック」by 日本オラクル 柴田 歩氏
https://www.oracle.com/webfolder/technetwork/jp/ondemand/ddd2013/A-1.pdf
実行統計を併記した実行計画の表示方法と読み方のおさらい
Starts: 当該ステップの実行回数 A-Rows: 処理行数 A-Time: 実行時間
実行順:11 -> 10 -> 9 -> 8 -> 7 -> 6 -> 12 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0
⑥ NESTED LOOPS
Rows=1 Time=204.20s
TABLE_001
駆動表(外部表)
TABLE_004
内部表
Starts=1
続く
⑧ INDEX SKIP SCAN
A-Rows=3,060 Time=2.96s
⑦ TABLE ACCESS BY INDEX ROWID BATCHED
A-Rows=3,060 Time=3.12s
+0.16s
⑪ INDEX RANGE SCAN
Rows=1 Time=204.17s
+0.02s
⑩ TABLE ACCESS BY INDEX ROWID BATCHED
Rows=1 Time=204.19s
⑨ PARTITION RANGE ITERATOR
Rows=1 Time=204.20s
+0.01s
Starts=3,060
Nested Loops Joinの動作
ID Operation Name Starts A-Rows A-Time
-- ------------------------------------------------- -------------- ------ ------ ------
8 INDEX SKIP SCAN I_TABLE001_2 1 3,060 2.96
7 TABLE ACCESS BY INDEX ROWID BATCHED TABLE_001 1 3,060 3.12
11 INDEX RANGE SCAN I_TABLE004_8 3,060 1 204.17
10 TABLE ACCESS BY LOCAL INDEX ROWID BATCHED TABLE_004 3,060 1 204.19
9 PARTITION RANGE ITERATOR 3,060 1 204.20
6 NESTED LOOPS 1 1 207.33
12 INDEX RANGE SCAN I_TABLE002PK 1 0 0.00
5 NESTED LOOPS OUTER 1 1 207.34
4 FILTER 1 1 207.34
3 FILTER 1 1 207.34
2 COUNT STOPKEY 1 1 207.34
1 SORT AGGREGATE 1 1 207.34
0 SELECT STATEMENT 1 1 207.34
13行が選択されました。
実行順実行計画の表示
• 上から下に向かって単純にたどっていく
• ID=0のA-Timeが全体の実行時間(< 経過時間)
• A-Timeが最も急激に増加しているステップがボトルネック(ID=11)
• ボトルネックの手前にも問題点がないか確認(ID=8)
⇨ チューニング・ポイント:2つのインデックスを見直す
01 select
02 ID,"Operation","Name","Starts","E-Rows","A-Rows","A-Time","Buffers","Reads","Writes","Srch Cols","Pstart","Pstop","PartID"
03 from
04 (select
05 rownum NO
06 ,ID
07 ,lpad(' ',DEPTH) || OPERATION ||' '|| OPTIONS "Operation"
08 ,OBJECT_NAME "Name" ,LAST_STARTS "Starts"
09 ,nvl(CARDINALITY,1) * LAST_STARTS "E-Rows" -- 1回の操作で処理される見積行数 * 見積処理回数 = 見積処理行数
10 ,LAST_OUTPUT_ROWS "A-Rows" -- 実際の処理行数
11 ,LAST_ELAPSED_TIME/1000000 "A-Time"
12 ,LAST_CR_BUFFER_GETS "Buffers",LAST_DISK_READS "Reads",LAST_DISK_WRITES "Writes"
13 ,SEARCH_COLUMNS "Srch Cols"
14 --,COST
15 ,PARTITION_START "Pstart",PARTITION_STOP "Pstop",PARTITION_ID "PartID"
16 from
17 (select a.* from
18 V$SQL_PLAN_STATISTICS_ALL a
19 where a.SQL_ID = '&1'
20 and a.TIMESTAMP = (select max(b.TIMESTAMP) from V$SQL_PLAN_STATISTICS_ALL b where b.SQL_ID = a.SQL_ID)
21 )
22 start with PARENT_ID is null
23 connect by prior ID = PARENT_ID
24 order siblings by ID desc
25 )
26 order by NO desc
27 ;
「実行順実行計画」表示スクリプト(全体)
15 ,PARTITION_START "Pstart",PARTITION_STOP "Pstop",PARTITION_ID "PartID"
16 from
17 (select a.* from
18 V$SQL_PLAN_STATISTICS_ALL a
19 where a.SQL_ID = '&1'
20 and a.TIMESTAMP = (select max(b.TIMESTAMP) from
V$SQL_PLAN_STATISTICS_ALL b where b.SQL_ID = a.SQL_ID)
21 )
22 start with PARENT_ID is null
23 connect by prior ID = PARENT_ID
24 order siblings by ID desc
25 )
「実行順実行計画」表示スクリプト(詳細1)
• 18行目:DBMS_XPLAN.DISPLAY_CURSORの参照元
• 22〜23行目:階層問い合わせで親IDから順にたどる
• 24行目:SIBLINGS(きょうだい) f.e. sibling node きょうだいノード
• 20行目:(念のため)直近の実行計画に絞る
01 select
02 ID,"Operation","Name","Starts","E-Rows","A-Rows","A-Time","Buffers","Reads","Writes","Srch
Cols","Pstart","Pstop","PartID"
03 from
04 (select
05 rownum NO
06 ,ID
07 ,lpad(' ',DEPTH) || OPERATION ||' '|| OPTIONS "Operation"
08 ,OBJECT_NAME "Name" ,LAST_STARTS "Starts"
09 ,nvl(CARDINALITY,1) * LAST_STARTS "E-Rows" -- 1回の操作で処理される見積行数 * 見積処理回
数 = 見積処理行数
10 ,LAST_OUTPUT_ROWS "A-Rows" -- 実際の処理行数
11 ,LAST_ELAPSED_TIME/1000000 "A-Time"
.............................................................................
25 )
26 order by NO desc
27 ;
「実行順実行計画」表示スクリプト(詳細2)
• 05および26行目:実行順を上から順に表示させるため
• 09行目:(念のため)E-Rowsを使いやすい値に加工する
SELECT /*+ ONLINE_SQL04S
INDEX(T004 I_TABLE004_TEST2) INDEX(T001 I_TABLE001_TEST1)
USE_NL(T002) LEADING(T001 T004 T002) */
COUNT(*) AS COUNTNUM
FROM
TABLE_004 T004
INNER JOIN
TABLE_001 T001
ON (T004.COL3091 = T001.COL3091
AND T004.COLA269 = T001.COLA269)
LEFT OUTER JOIN
TABLE_002 T002
ON (T002.COLA215 = T001.COLA215
AND T002.COL3091 = T004.COL3091)
WHERE
..... 以下省略 ..........
COUNTNUM
----------
1
経過: 00:00:01.04
チューニング後SQLと実行結果
2つの複合インデックスのカラム順を見直し
3:27.35 ⇨ 1.04 に改善
Plan hash value: 1704335308
----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts || A-Rows | A-Time ||
----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 || 1 |00:00:00.09 ||
| 1 | SORT AGGREGATE | | 1 || 1 |00:00:00.09 ||
|* 2 | COUNT STOPKEY | | 1 || 1 |00:00:00.09 ||
|* 3 | FILTER | | 1 || 1 |00:00:00.09 ||
|* 4 | FILTER | | 1 || 1 |00:00:00.09 ||
| 5 | NESTED LOOPS OUTER | | 1 || 1 |00:00:00.09 ||
| 6 | MERGE JOIN | | 1 || 1 |00:00:00.09 ||
|* 7 | TABLE ACCESS BY INDEX ROWID | TABLE_001 | 1 || 3060 |00:00:00.09 ||
|* 8 | INDEX RANGE SCAN | I_TABLE001_TEST1 | 1 || 3060 |00:00:00.01 ||
|* 9 | FILTER | | 3060 || 1 |00:00:00.01 ||
|* 10 | SORT JOIN | | 3060 || 1 |00:00:00.01 ||
| 11 | TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| TABLE_004 | 1 || 1 |00:00:00.01 ||
|* 12 | INDEX RANGE SCAN | I_TABLE004_TEST2 | 1 || 1 |00:00:00.01 ||
|* 13 | INDEX RANGE SCAN | I_TABLE002PK | 1 || 0 |00:00:00.01 ||
----------------------------------------------------------------------------------------------------------------
ID Operation Name Starts E-Rows A-Rows A-Time
-- --------------------------------------------------- ---------------- ------ ------ ------ ------
8 INDEX RANGE SCAN I_TABLE001_TEST1 1 38,050 3,060 0.01
7 TABLE ACCESS BY INDEX ROWID TABLE_001 1 38,046 3,060 0.09
12 INDEX RANGE SCAN I_TABLE004_TEST2 1 1 1 0.00
11 TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED TABLE_004 1 1 1 0.00
10 SORT JOIN 3,060 3,060 1 0.00
9 FILTER 3,060 3,060 1 0.01
6 MERGE JOIN 1 1 1 0.09
13 INDEX RANGE SCAN I_TABLE002PK 1 1 0 0.00
5 NESTED LOOPS OUTER 1 1 1 0.09
4 FILTER 1 1 1 0.09
3 FILTER 1 1 1 0.09
2 COUNT STOPKEY 1 1 1 0.09
1 SORT AGGREGATE 1 1 1 0.09
0 SELECT STATEMENT 1 1 1 0.09
チューニング後実行計画
まとめ
• 実行統計(10gR2〜)はOracle技術者にとっての大きな飛躍
• 実行順表示でボトルネックはさらにわかりやすく
• ボトルネック解消策
• SCAN / ACCESS : インデックス等I/O負荷削減検討
• JOIN : 結合方式検討(USE_HASHヒント等)、結合順序検
討(LEADINGヒント等)
• 詳しくはブログで。。。

More Related Content

PDF
Tanel Poder - Scripts and Tools short
PDF
SQL Monitoring in Oracle Database 12c
PPTX
Introduction to Oracle Data Guard Broker
PDF
TFA Collector - what can one do with it
PDF
Troubleshooting Complex Oracle Performance Problems with Tanel Poder
PDF
Troubleshooting Complex Performance issues - Oracle SEG$ contention
PPTX
AWR and ASH Deep Dive
PDF
Analyzing and Interpreting AWR
Tanel Poder - Scripts and Tools short
SQL Monitoring in Oracle Database 12c
Introduction to Oracle Data Guard Broker
TFA Collector - what can one do with it
Troubleshooting Complex Oracle Performance Problems with Tanel Poder
Troubleshooting Complex Performance issues - Oracle SEG$ contention
AWR and ASH Deep Dive
Analyzing and Interpreting AWR

What's hot (20)

PDF
Oracle Performance Tuning Fundamentals
PPTX
OCI GoldenGate Overview 2021年4月版
PPTX
Part1 of SQL Tuning Workshop - Understanding the Optimizer
PPTX
ActionCableのクライアントはRails外から利用できるのか
PDF
EM12c: Capacity Planning with OEM Metrics
PPT
DataGuard体験記
PDF
Oracle Cloud Infrastructure:2023年2月度サービス・アップデート
PDF
Same plan different performance
PDF
Oracle Database SQL Tuning Concept
PDF
Oracle Database performance tuning using oratop
PDF
[B24] Oracle から SQL Server システム移行の勘所 by Norio Nakamura
PDF
[Oracle DBA & Developer Day 2016] しばちょう先生の特別講義!!ストレージ管理のベストプラクティス ~ASMからExada...
PDF
知っておきたいSpring Batch Tips
PPT
Your tuning arsenal: AWR, ADDM, ASH, Metrics and Advisors
PDF
Deep review of LMS process
PPTX
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
PDF
Snowflakeって実際どうなの?数多のDBを使い倒した猛者が語る
PPT
PDF
Spannerに関する技術メモ
PDF
Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...
Oracle Performance Tuning Fundamentals
OCI GoldenGate Overview 2021年4月版
Part1 of SQL Tuning Workshop - Understanding the Optimizer
ActionCableのクライアントはRails外から利用できるのか
EM12c: Capacity Planning with OEM Metrics
DataGuard体験記
Oracle Cloud Infrastructure:2023年2月度サービス・アップデート
Same plan different performance
Oracle Database SQL Tuning Concept
Oracle Database performance tuning using oratop
[B24] Oracle から SQL Server システム移行の勘所 by Norio Nakamura
[Oracle DBA & Developer Day 2016] しばちょう先生の特別講義!!ストレージ管理のベストプラクティス ~ASMからExada...
知っておきたいSpring Batch Tips
Your tuning arsenal: AWR, ADDM, ASH, Metrics and Advisors
Deep review of LMS process
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
Snowflakeって実際どうなの?数多のDBを使い倒した猛者が語る
Spannerに関する技術メモ
Exploring Oracle Database Performance Tuning Best Practices for DBAs and Deve...
Ad

Similar to 実行統計による実践的SQLチューニング (20)

PPT
20090107 Postgre Sqlチューニング(Sql編)
PDF
Oracleの実行計画を読んでみよう! #dbts2017
PDF
PostgreSQL:行数推定を読み解く
PDF
PostgreSQL実行計画入門@関西PostgreSQL勉強会
PDF
YugabyteDBの実行計画を眺める(NewSQL/分散SQLデータベースよろず勉強会 #3 発表資料)
PDF
まだ統計固定で消耗してるの? - Bind Peek をもっと使おうぜ! 2015 Edition -
PDF
より深く知るオプティマイザとそのチューニング
PDF
Introduction of Oracle Database Architecture
PPT
SQLチューニング勉強会資料
PDF
プロとしてのOracleアーキテクチャ入門 ~番外編~ @ Developers Summit 2009
PDF
PostgreSQL SQLチューニング入門 実践編(pgcon14j)
PDF
Bind Peek をもっと使おうぜ!(柴田 歩) - JPOUG Advent Calendar 2014(Day 5) -
PPTX
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PDF
2018年度 若手技術者向け講座 実行計画
PPTX
SQLチューニング入門 入門編
PDF
PostgreSQL18新機能紹介(db tech showcase 2025 発表資料)
PDF
JPUGしくみ+アプリケーション勉強会(第20回)
PPT
プロとしてのOracleアーキテクチャ入門 ~番外編~
PDF
An overview of query optimization in relational systems 論文紹介
PDF
2018年度 若手技術者向け講座 大量データの扱い・ストアド・メモリ管理
20090107 Postgre Sqlチューニング(Sql編)
Oracleの実行計画を読んでみよう! #dbts2017
PostgreSQL:行数推定を読み解く
PostgreSQL実行計画入門@関西PostgreSQL勉強会
YugabyteDBの実行計画を眺める(NewSQL/分散SQLデータベースよろず勉強会 #3 発表資料)
まだ統計固定で消耗してるの? - Bind Peek をもっと使おうぜ! 2015 Edition -
より深く知るオプティマイザとそのチューニング
Introduction of Oracle Database Architecture
SQLチューニング勉強会資料
プロとしてのOracleアーキテクチャ入門 ~番外編~ @ Developers Summit 2009
PostgreSQL SQLチューニング入門 実践編(pgcon14j)
Bind Peek をもっと使おうぜ!(柴田 歩) - JPOUG Advent Calendar 2014(Day 5) -
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
2018年度 若手技術者向け講座 実行計画
SQLチューニング入門 入門編
PostgreSQL18新機能紹介(db tech showcase 2025 発表資料)
JPUGしくみ+アプリケーション勉強会(第20回)
プロとしてのOracleアーキテクチャ入門 ~番外編~
An overview of query optimization in relational systems 論文紹介
2018年度 若手技術者向け講座 大量データの扱い・ストアド・メモリ管理
Ad

実行統計による実践的SQLチューニング

  • 1. JPOUG in 15 minutes #8 三原 健一
  • 2. 自己紹介 • フリーランス • 現在:大手SIerの性能問題解決チームに従事 • 過去1年数ヶ月は主にSQLチューニングの日々 • ブログ:「サイクル&オラクル」 http://onefact.jp/wp/ • DB Online記事執筆:「Oracle技術者から見た、SAP HANA」 https://enterprisezine.jp/article/corner/440
  • 4. SELECT /*+ ONLINE_SQL04S INDEX(T004 I_TABLE004_8) INDEX(T001 I_TABLE001_2) USE_NL(T002) LEADING(T001 T004 T002) */ COUNT(*) AS COUNTNUM FROM TABLE_004 T004 INNER JOIN TABLE_001 T001 ON (T004.COL3091 = T001.COL3091 AND T004.COLA269 = T001.COLA269) LEFT OUTER JOIN TABLE_002 T002 ON (T002.COLA215 = T001.COLA215 AND T002.COL3091 = T004.COL3091) WHERE ..... 以下省略 .......... COUNTNUM ---------- 1 経過: 00:03:27.35 チューニング前SQLと実行結果 ← オンラインSQLなので目標レスポンス時間は3秒以内
  • 5. Plan hash value: 239732999 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts || A-Rows | A-Time || ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 || 1 |00:03:27.34 || | 1 | SORT AGGREGATE | | 1 || 1 |00:03:27.34 || |* 2 | COUNT STOPKEY | | 1 || 1 |00:03:27.34 || |* 3 | FILTER | | 1 || 1 |00:03:27.34 || |* 4 | FILTER | | 1 || 1 |00:03:27.34 || | 5 | NESTED LOOPS OUTER | | 1 || 1 |00:03:27.34 || | 6 | NESTED LOOPS | | 1 || 1 |00:03:27.33 || |* 7 | TABLE ACCESS BY INDEX ROWID BATCHED | TABLE_001 | 1 || 3060 |00:00:03.12 || |* 8 | INDEX SKIP SCAN | I_TABLE001_2 | 1 || 3060 |00:00:02.96 || | 9 | PARTITION RANGE ITERATOR | | 3060 || 1 |00:03:24.20 || |* 10 | TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| TABLE_004 | 3060 || 1 |00:03:24.19 || |* 11 | INDEX RANGE SCAN | I_TABLE004_8 | 3060 || 1 |00:03:24.17 || |* 12 | INDEX RANGE SCAN | I_TABLE002PK | 1 || 0 |00:00:00.01 || ---------------------------------------------------------------------------------------------------------- 参考:「SQLチューニングに必要な考え方と最新テクニック」by 日本オラクル 柴田 歩氏 https://www.oracle.com/webfolder/technetwork/jp/ondemand/ddd2013/A-1.pdf 実行統計を併記した実行計画の表示方法と読み方のおさらい Starts: 当該ステップの実行回数 A-Rows: 処理行数 A-Time: 実行時間 実行順:11 -> 10 -> 9 -> 8 -> 7 -> 6 -> 12 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0
  • 6. ⑥ NESTED LOOPS Rows=1 Time=204.20s TABLE_001 駆動表(外部表) TABLE_004 内部表 Starts=1 続く ⑧ INDEX SKIP SCAN A-Rows=3,060 Time=2.96s ⑦ TABLE ACCESS BY INDEX ROWID BATCHED A-Rows=3,060 Time=3.12s +0.16s ⑪ INDEX RANGE SCAN Rows=1 Time=204.17s +0.02s ⑩ TABLE ACCESS BY INDEX ROWID BATCHED Rows=1 Time=204.19s ⑨ PARTITION RANGE ITERATOR Rows=1 Time=204.20s +0.01s Starts=3,060 Nested Loops Joinの動作
  • 7. ID Operation Name Starts A-Rows A-Time -- ------------------------------------------------- -------------- ------ ------ ------ 8 INDEX SKIP SCAN I_TABLE001_2 1 3,060 2.96 7 TABLE ACCESS BY INDEX ROWID BATCHED TABLE_001 1 3,060 3.12 11 INDEX RANGE SCAN I_TABLE004_8 3,060 1 204.17 10 TABLE ACCESS BY LOCAL INDEX ROWID BATCHED TABLE_004 3,060 1 204.19 9 PARTITION RANGE ITERATOR 3,060 1 204.20 6 NESTED LOOPS 1 1 207.33 12 INDEX RANGE SCAN I_TABLE002PK 1 0 0.00 5 NESTED LOOPS OUTER 1 1 207.34 4 FILTER 1 1 207.34 3 FILTER 1 1 207.34 2 COUNT STOPKEY 1 1 207.34 1 SORT AGGREGATE 1 1 207.34 0 SELECT STATEMENT 1 1 207.34 13行が選択されました。 実行順実行計画の表示 • 上から下に向かって単純にたどっていく • ID=0のA-Timeが全体の実行時間(< 経過時間) • A-Timeが最も急激に増加しているステップがボトルネック(ID=11) • ボトルネックの手前にも問題点がないか確認(ID=8) ⇨ チューニング・ポイント:2つのインデックスを見直す
  • 8. 01 select 02 ID,"Operation","Name","Starts","E-Rows","A-Rows","A-Time","Buffers","Reads","Writes","Srch Cols","Pstart","Pstop","PartID" 03 from 04 (select 05 rownum NO 06 ,ID 07 ,lpad(' ',DEPTH) || OPERATION ||' '|| OPTIONS "Operation" 08 ,OBJECT_NAME "Name" ,LAST_STARTS "Starts" 09 ,nvl(CARDINALITY,1) * LAST_STARTS "E-Rows" -- 1回の操作で処理される見積行数 * 見積処理回数 = 見積処理行数 10 ,LAST_OUTPUT_ROWS "A-Rows" -- 実際の処理行数 11 ,LAST_ELAPSED_TIME/1000000 "A-Time" 12 ,LAST_CR_BUFFER_GETS "Buffers",LAST_DISK_READS "Reads",LAST_DISK_WRITES "Writes" 13 ,SEARCH_COLUMNS "Srch Cols" 14 --,COST 15 ,PARTITION_START "Pstart",PARTITION_STOP "Pstop",PARTITION_ID "PartID" 16 from 17 (select a.* from 18 V$SQL_PLAN_STATISTICS_ALL a 19 where a.SQL_ID = '&1' 20 and a.TIMESTAMP = (select max(b.TIMESTAMP) from V$SQL_PLAN_STATISTICS_ALL b where b.SQL_ID = a.SQL_ID) 21 ) 22 start with PARENT_ID is null 23 connect by prior ID = PARENT_ID 24 order siblings by ID desc 25 ) 26 order by NO desc 27 ; 「実行順実行計画」表示スクリプト(全体)
  • 9. 15 ,PARTITION_START "Pstart",PARTITION_STOP "Pstop",PARTITION_ID "PartID" 16 from 17 (select a.* from 18 V$SQL_PLAN_STATISTICS_ALL a 19 where a.SQL_ID = '&1' 20 and a.TIMESTAMP = (select max(b.TIMESTAMP) from V$SQL_PLAN_STATISTICS_ALL b where b.SQL_ID = a.SQL_ID) 21 ) 22 start with PARENT_ID is null 23 connect by prior ID = PARENT_ID 24 order siblings by ID desc 25 ) 「実行順実行計画」表示スクリプト(詳細1) • 18行目:DBMS_XPLAN.DISPLAY_CURSORの参照元 • 22〜23行目:階層問い合わせで親IDから順にたどる • 24行目:SIBLINGS(きょうだい) f.e. sibling node きょうだいノード • 20行目:(念のため)直近の実行計画に絞る
  • 10. 01 select 02 ID,"Operation","Name","Starts","E-Rows","A-Rows","A-Time","Buffers","Reads","Writes","Srch Cols","Pstart","Pstop","PartID" 03 from 04 (select 05 rownum NO 06 ,ID 07 ,lpad(' ',DEPTH) || OPERATION ||' '|| OPTIONS "Operation" 08 ,OBJECT_NAME "Name" ,LAST_STARTS "Starts" 09 ,nvl(CARDINALITY,1) * LAST_STARTS "E-Rows" -- 1回の操作で処理される見積行数 * 見積処理回 数 = 見積処理行数 10 ,LAST_OUTPUT_ROWS "A-Rows" -- 実際の処理行数 11 ,LAST_ELAPSED_TIME/1000000 "A-Time" ............................................................................. 25 ) 26 order by NO desc 27 ; 「実行順実行計画」表示スクリプト(詳細2) • 05および26行目:実行順を上から順に表示させるため • 09行目:(念のため)E-Rowsを使いやすい値に加工する
  • 11. SELECT /*+ ONLINE_SQL04S INDEX(T004 I_TABLE004_TEST2) INDEX(T001 I_TABLE001_TEST1) USE_NL(T002) LEADING(T001 T004 T002) */ COUNT(*) AS COUNTNUM FROM TABLE_004 T004 INNER JOIN TABLE_001 T001 ON (T004.COL3091 = T001.COL3091 AND T004.COLA269 = T001.COLA269) LEFT OUTER JOIN TABLE_002 T002 ON (T002.COLA215 = T001.COLA215 AND T002.COL3091 = T004.COL3091) WHERE ..... 以下省略 .......... COUNTNUM ---------- 1 経過: 00:00:01.04 チューニング後SQLと実行結果 2つの複合インデックスのカラム順を見直し 3:27.35 ⇨ 1.04 に改善
  • 12. Plan hash value: 1704335308 ---------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts || A-Rows | A-Time || ---------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 || 1 |00:00:00.09 || | 1 | SORT AGGREGATE | | 1 || 1 |00:00:00.09 || |* 2 | COUNT STOPKEY | | 1 || 1 |00:00:00.09 || |* 3 | FILTER | | 1 || 1 |00:00:00.09 || |* 4 | FILTER | | 1 || 1 |00:00:00.09 || | 5 | NESTED LOOPS OUTER | | 1 || 1 |00:00:00.09 || | 6 | MERGE JOIN | | 1 || 1 |00:00:00.09 || |* 7 | TABLE ACCESS BY INDEX ROWID | TABLE_001 | 1 || 3060 |00:00:00.09 || |* 8 | INDEX RANGE SCAN | I_TABLE001_TEST1 | 1 || 3060 |00:00:00.01 || |* 9 | FILTER | | 3060 || 1 |00:00:00.01 || |* 10 | SORT JOIN | | 3060 || 1 |00:00:00.01 || | 11 | TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED| TABLE_004 | 1 || 1 |00:00:00.01 || |* 12 | INDEX RANGE SCAN | I_TABLE004_TEST2 | 1 || 1 |00:00:00.01 || |* 13 | INDEX RANGE SCAN | I_TABLE002PK | 1 || 0 |00:00:00.01 || ---------------------------------------------------------------------------------------------------------------- ID Operation Name Starts E-Rows A-Rows A-Time -- --------------------------------------------------- ---------------- ------ ------ ------ ------ 8 INDEX RANGE SCAN I_TABLE001_TEST1 1 38,050 3,060 0.01 7 TABLE ACCESS BY INDEX ROWID TABLE_001 1 38,046 3,060 0.09 12 INDEX RANGE SCAN I_TABLE004_TEST2 1 1 1 0.00 11 TABLE ACCESS BY GLOBAL INDEX ROWID BATCHED TABLE_004 1 1 1 0.00 10 SORT JOIN 3,060 3,060 1 0.00 9 FILTER 3,060 3,060 1 0.01 6 MERGE JOIN 1 1 1 0.09 13 INDEX RANGE SCAN I_TABLE002PK 1 1 0 0.00 5 NESTED LOOPS OUTER 1 1 1 0.09 4 FILTER 1 1 1 0.09 3 FILTER 1 1 1 0.09 2 COUNT STOPKEY 1 1 1 0.09 1 SORT AGGREGATE 1 1 1 0.09 0 SELECT STATEMENT 1 1 1 0.09 チューニング後実行計画
  • 13. まとめ • 実行統計(10gR2〜)はOracle技術者にとっての大きな飛躍 • 実行順表示でボトルネックはさらにわかりやすく • ボトルネック解消策 • SCAN / ACCESS : インデックス等I/O負荷削減検討 • JOIN : 結合方式検討(USE_HASHヒント等)、結合順序検 討(LEADINGヒント等) • 詳しくはブログで。。。