• 検索結果がありません。

#odddtky Oracle DBA & Developer Days 2014 for your Skill 使える実践的なノウハウがここにある 津島博士のパフォーマンス講座 SQL チューニングの基礎 日本オラクル株式会社データベース事業統括製品戦略統括本部データベースエンジニアリング本部 担

N/A
N/A
Protected

Academic year: 2021

シェア "#odddtky Oracle DBA & Developer Days 2014 for your Skill 使える実践的なノウハウがここにある 津島博士のパフォーマンス講座 SQL チューニングの基礎 日本オラクル株式会社データベース事業統括製品戦略統括本部データベースエンジニアリング本部 担"

Copied!
97
0
0

読み込み中.... (全文を見る)

全文

(1)
(2)

津島博士のパフォーマンス講座

SQLチューニングの基礎

日本オラクル株式会社

データベース事業統括 製品戦略統括本部

データベースエンジニアリング本部

担当ディレクター

津島 浩樹

Oracle DBA & Developer Days 2014

for your

Skill

使える実践的なノウハウがここにある

(3)

以下の事項は、弊社の一般的な製品の方向性に関する概要を説明する

ものです。また、情報提供を唯一の目的とするものであり、いかなる契約

にも組み込むことはできません。以下の事項は、マテリアルやコード、機

能を提供することをコミットメント(確約)するものではないため、購買決定

を行う際の判断材料になさらないで下さい。オラクル製品に関して記載さ

れている機能の開発、リリースおよび時期については、弊社の裁量により

決定されます。

OracleとJavaは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。 文中の社名、商品名等は各社の商標または登録商標である場合があります。

(4)

はじめに

「津島博士のパフォーマンス講座」の紹介

連載していますのでよろしくお願いいたします。

(5)

アジェンダ

1 2 3

SQLチューニングとは

オプティマイザの概要

実行計画

実行計画のチューニング

Oracle Database 12cの拡張

4 5 2 3

オプティマイザの概要

実行計画

実行計画のチューニング

Oracle Database 12cの拡張

4 5

(6)

1.

問題がある(遅い)SQLの特定と分析

AWRなどから分析する

リソースの問題(キャッシュ・ヒット率、I/O性能)などはインスタンス・チューニング

2.

チューニング(最適な実行計画にする)

手動(実行計画を分析)

自動(SQLチューニング・アドバイザなど)

3.

テスト

効果を確認(SQL*Plusで実行など)

目標に対して評価(未達であれば再度チューニング)

SQLチューニングとは

(7)

オプティマイザが以下の手順で決定する

1.

アクセス方法(索引スキャン、フル・スキャン)

カーディナリティ(述語を適用した行数)を算出して、

それのI/O時間が短いアクセス

単一ブロック・リードとマルチ・ブロック・リードの比較

リード回数とリード性能で決まる

2.

結合順序(表数!(階乗)の組合せ)

カーディナリティの小さいものから

メモリを使用するとき(ハッシュ結合など)はサイズも影響

2表目からは結合のカーディナリティ(結合後の行数)も考慮する

3.

結合方法

それぞれの結合順序で以下の結合方法のコストを算出

SQLチューニングとは

最適な実行計画

1行 2行 3行 1行 2行 3行 ・ ・ ・ 10行 1行 2行 3行 1行 2行 3行 10行 ・ ・ ・

(8)

Nested Loop Join(ネステッド・ループ結合)

基本は索引を使用する結合(表の行数が少ないときは全表スキャンでも)

Hash Join(ハッシュ結合)

索引を使用しない等価結合では最も効果的

Sort Merge Join(ソート・マージ結合)

索引を使用しない等価結合以外など(ソート処理が重いのであまり使用しない)

結合タイプによっては結合順序が決まる場合も

外部結合、セミ結合、アンチ結合

SQLチューニングとは

(9)

表、索引

テーブル構造、パーティション、索引の設計など

これによる性能の違いが大きい

→ すべてを速くすることはできない

SQL文

最適にするには多少の知識が必要

詳細は「オプティマイザの概要」や「実行計画のチューニング」で

初期化パラメータ

メモリ領域サイズ、I/Oサイズなど

オプティマイザ統計

これでカーティナリティ(行数)などが決まる

SQLチューニングとは

最適な実行計画を決める要素

自動メモリ管理など

自動オプティマイザ統計収集

(10)

アジェンダ

1 2 3

SQLチューニングとは

オプティマイザの概要

実行計画

実行計画のチューニング

Oracle Database 12cの拡張

4 5

(11)

オプティマイザの種類

使用可能なアクセスパスを

順序づけるランキングに基づいて

実行計画を作成

統計情報に基づきコストを

見積もり、最もコストの低い

実行計画を作成

コストベース

オプティマイザ

(CBO)

ルールベース

オプティマイザ

(RBO)

※Oracle10gからはCBOのみに

(12)

SQL構文から実行計画を作成

OLTPタイプのような単純なSQLに向いている

SQLの作成が難しい

ルールを覚える必要がある(誰でも作成できる訳ではない)

データの変化に対応できない

同じ条件でも最適な実行計画は異なる(データ分布の違い)

データの増加によって実行計画は変化する

限界がある

新機能には対応できない

オプティマイザの種類

ルールベース・オプティマイザの問題

(13)

問合せトランスフォーマ(問合せ変換)

適切と判断した問合せに変換

(アクセス・パスの候補を追加)

エスティメータ

アクセス・パスのコストを計算

プラン・ジェネレータ

複数のアクセス・パスを計算させて、

最もコストが低い実行計画を生成

アクセス・パス数の制限

オプティマイザの構成要素

パーサー(構文解析)

プランの実行

ディクショナリ

(統計)

CBOのみ

オプティマイザ

プラン・ジェネレータ

エスティメータ

問合せトランスフォーマ

(14)

SQLによっては最適な実行計画にならない

最適なSQLは多少の知識が必要(特に、結合に対する副問合せの活用など)

オプティマイザが代わりに行う

データ(データ分布)によって最適な実行計画が異なる

CBOではコストから変換するか判断する

例えば、

索引を使用するSQL

索引を使用しないSQL

副問合せを使用するSQL

副問合せを使用しないSQL

オプティマイザ統計によって最適でないときもある

知っているとSQLを書き換えるときのヒントになる

問合せ変換

CBOのとき

最適な実行計画に変換

(15)

ORまたはINリストで索引を使用するように

OR Expansion(OR拡張)

UNION ALLに変換(USE_CONCATヒント)

変換しないとき(NO_EXPANDヒント)

問合せ変換

代表的な機能(索引の使用)

SQL> SELECT * FROM tab1 WHERE c1 = 100

2 UNION ALL

3 SELECT * FROM tab1 WHERE c2 = 200 AND LNNVL(c1 = 100)

4 UNION ALL

SQL> SELECT * FROM tab1

2 WHERE c1 = 100 OR c2 = 200 OR c3 = 300;

実行計画 ---| Id ---| Operation ---| Name ---| ---| 0 ---| SELECT STATEMENT ---| ---| | 1 | CONCATENATION | | | 2 | TABLE ACCESS BY INDEX ROWID| TAB1 | |* 3 | INDEX UNIQUE SCAN | PK_TAB1 | |* 4 | TABLE ACCESS BY INDEX ROWID| TAB1 | |* 5 | INDEX RANGE SCAN | IX_TAB1 | | … |

(16)

副問合せ

ビュー/インライン・ビュー(FROM句の副問合せ)

通常の結合方法になる(使用する/使用しない/作成する)

次頁参照

ネストした副問合せ(WHERE句の副問合せ)

通常の結合方法に変換する(FILTERなどから)

Subquery Unnesting(副問合せのネスト解除)

スカラー副問合せ(SELECTリストの副問合せ)

通常の結合方法に変換する(Oracle Database 12cから)

Scalar Subquery Unnesting(スカラー副問合せのネスト解除)

問合せ変換

(17)

ビュー/インライン・ビュー

ビューを使用しない(結合順を変えたい、索引を使用したい)

View Merging(ビュー・マージ)

ビューをマージできない/しない(Group by 後にネステッド・ループ結合するなど)

Predicate Pushing(述語のプッシュ)

インライン・ビューを作成する(早い段階で重複値を削除するなど)

Group by Placement (Group by の配置の最適化)

補足説明参照

問合せ変換

代表的な機能(結合/副問合せを効果的に)

ビューとは

アクセス制御などに使用

ビューから実行(結合順が決まる)

(18)

表統計

行数、データ・ブロック数、行連鎖・行移行の数、平均行長

索引統計

索引内の個別値数、索引の深さ(BLEVEL)、リーフ・ブロック数、クラスタ化係数

列統計

個別値数、NULL数、平均列データ長、データ分布(最小値と最大値、ヒストグラム)

システム統計(CPUコスト・モデルで使用)

CPU性能、I/O性能(単一ブロック・リード、マルチ・ブロック・リード)

パーティション表には、パーティション、サブ・パーティションごとにも同様の情報を収集する

オプティマイザ統計情報

主な項目(正確にする運用が重要)

表アクセス・コスト

索引アクセス・コスト

カーディナリティ、サイズ

アクセスする行数やブロック数を求め、CPU性能やI/O性能でコストを計算する

この情報には限界がるので、大きく異なる ようなデータは注意が必要(12cから改善)

(19)

オプティマイザ統計を変更しなくても実行計画は変化するので注意

オプティマイザ統計が正しくない

カーディナリティ・フィードバック

カーディナリティが異なる場合は、2回目以降から補正して実行計画を作成

(ただし、メモリ上にカーソルが存在するときだけ)

バインド変数の値が異なる(戻される行数が異なる)

ハード・パース時にハンド変数の値で実行計画を作成(バインド変数の先読み)

等価条件はヒストグラムがないと動作しない

範囲条件(<,>)はヒストグラムがなくても動作

大きな表に複雑なWHERE句でパラレル実行する

動的サンプリングのレベルを自動的に決定(Oracle Database 11gR2から)

実行計画の変化

(20)

ビューを主問合せにマージすることで以下を可能にする

結合順を最適にできない

ビュー実行後には索引が使用できない

問合せ変換

補足説明(View / Complex View Merging)

SQL> SELECT D.loc, avg(sal) FROM dept D, emp E

2 WHERE D.deptno = E.deptno AND D.loc = 'London'

3 GROUP BY E.deptno, D.loc ;

SQL> CREATE VIEW v_avg_salary AS

2 SELECT deptno, avg(sal) avg_sal FROM emp GROUP BY deptno ;

SQL> SELECT D.loc, avg_sal FROM dept D, v_avg_salary V

2 WHERE D.deptno = V.deptno AND D.loc = 'London' ;

(21)

ビューは結合前に行数を削減できるメリットがある

ビューをマージしない場合は述語をビュー内へ

結合述語で索引を使用(ネステッド・ループ結合)

問合せ変換

補足説明(Predicate Pushing)

SQL> CREATE VIEW v_tab01 AS

2 SELECT c02,SUM(c03) FROM tab01 GROUP BY c02 ; SQL> SELECT * FROM tab02 A, v_tab01 B

2 WHERE A.c2 = B.c02 ;

SQL> SELECT * FROM tab02 A,

2 (SELECT c02,SUM(c03) FROM tab01 B 3 WHERE A.c2 = B.c02 GROUP BY c02) ;

実行計画 ---| Id ---| Operation ---| Name ---| ---| 0 ---| SELECT STATEMENT ---| ---| | 1 | NESTED LOOPS | | | 2 | TABLE ACCESS FULL | TAB02 | | 3 | VIEW PUSHED PREDICATE | V_TAB01 | |* 4 | FILTER | | | 5 | SORT AGGREGATE | | | 6 | TABLE ACCESS BY INDEX ROWID| TAB01 | |* 7 | INDEX RANGE SCAN | IX_TAB01 | ---Predicate Information (identified by operation id): ---実行計画(変換しない) ---| Id ---| Operation ---| Name | ---| 0 ---| SELECT STATEMENT ---| | |* 1 | HASH JOIN | | | 2 | TABLE ACCESS FULL | TAB02 | | 3 | VIEW | V_TAB01 | | 4 | HASH GROUP BY | | | 5 | TABLE ACCESS FULL| TAB01 |

(22)

結合前にインライン・ビューを実行(作成)することで行数を削減する

重複値が多いときにGroup byなどをすることで行数を削減

問合せ変換

補足説明(Group by Placement)

SQL> SELECT A,c2, SUM(B.c2), COUNT(*) cnt

2 FROM tab1 A, tab2 B WHERE A.c1 = B.c1 GROUP BY A.c2 ;

SQL> SELECT A,c2, SUM(B.c2), SUM(ct) cnt FROM tab1 A,

2 (SELECT c1, SUM(c2) c2, COUNT(*) ct FROM tab2 GROUP BY) B

3 WHERE A.c1 = B.c1 GROUP BY A.c2 ;

(23)

ネストした副問合せの結合方法を変換

FILTERから通常の結合方法(ハッシュ結合など)に変換

IN条件はインライン・ビュー

EXISTS条件はセミ結合

NOT IN、NOT EXISTS条件はアンチ結合

問合せ変換

補足説明(Subquery Unnesting)

SQL> SELECT * FROM tab1 A WHERE EXISTS (SELECT 0 FROM tab2 B WHERE A.c1 = B.c1); 実行計画 ---| Id ---| Operation ---| Name ---| ---| 0 ---| SELECT STATEMENT ---| ---| |* 1 | FILTER | | | 2 | TABLE ACCESS FULL| TAB1 | |* 3 | TABLE ACCESS FULL| TAB2 |

実行計画

---| Id ---| Operation ---| Name ---| ---| 0 ---| SELECT STATEMENT ---| ---| |* 1 | HASH JOIN SEMI | | | 2 | TABLE ACCESS FULL| TAB1 | | 3 | TABLE ACCESS FULL| TAB2 |

(24)

EXISTSとIN

どのように使い分けるか

EXISTS(相関副問合せ)

ネステッド・ループ結合の駆動表はtab1(tab2.c1の索引を使用する)

IN(非相関副問合せ)

ネステッド・ループ結合の駆動表はtab2(tab1.c1の索引を使用する)

インライン・ビュー

問合せ変換

補足説明(Subquery Unnesting)

SQL> SELECT c1 FROM tab1 A, (SELECT DISTINCT c1 FROM tab2) B WHERE A.c1 = B.c1 ; SQL> SELECT c1 FROM tab01 WHERE c1 IN (SELECT c1 FROM tab2) ;

索引や重複値な

どによって

SQL> SELECT c1 FROM tab1 A WHERE EXISTS (SELECT 0 FROM tab2 B WHERE A.c1 = B.c1) ;

セミ結合

同じ意味(重複値を排除して結合)なので、 インライン・ビュー(通常の表結合)に変換

(現在は、どちらを使用しても変換してくれる)

(25)

アジェンダ

1 2 3

SQLチューニングとは

オプティマイザの概要

実行計画

実行計画のチューニング

Oracle Database 12cの拡張

4 5

(26)

Explain plan for <SQL>

実際にはSQLは実行されない

SQL*PlusのAUTOTRACEコマンド

set autotrace traceonly explain以外は実際にSQLを実行

SQLトレース

SQLのトレースを取得

Tkprofコマンドによりトレースファイルからプランを取得

実行計画の確認方法

• 再実行が必要

• plan_tableが必要

• 負荷が高い

(27)

V$SQL及びV$SQL_PLAN(Oracle9iから)

共有プールのSQL

の実行計画をV$SQL_PLANビューを使用して検索

DBMS_XPLAN.DISPLAY_CURSOR関数(Oracle Database 10gから)

実行時の統計も出力

リアルタイムSQL監視(Oracle Database 11gから)

実行中の実行計画も出力

AWR(Oracle Database 10gから) / STATSPACK(Oracle9iから)からの出力

レベルによってスナップショットにSQLの実行計画が含まれる

AWR(STATISTICS_LEVEL=TYPICAL) ⇒ $ORACLE_HOME/rdbms/admin/awrsqrpt.sql

STATSPACK(スナップショットLEVELが6以上) ⇒ $ORACLE_HOME/rdbms/admin/sprepsql.sql

実行計画の確認方法

(28)

実行計画の確認方法

DBMS_XPLAN.DISPLAY_CURSOR関数

見積もり以外に実行時の統計も出力できる(STATISTICS_LEVEL=ALLまたはヒント)

SQL> SELECET /*+ GATHER_PLAN_STATISTICS */ … ;

SQL> SELECT * FROM TABLE(dbms_xplan.display_cursor(sql_id=>'<sql_id>',format=>'typical allstats last')); 実行計画

---| Id ---| Operation ---| Name ---| Starts| E-Rows|E-Bytes| Cost (%CPU)| E-Time | A-Rows| A-Time | ---

---Buffers| OMem| 1Mem| Used-Mem| Used-Tmp| ---<実行統計> Starts:実行された回数 Buffers:バッファのアクセス数 A-Rows:処理行数 A-Time:処理時間 Used-Mem:使用されたメモリサイズと処理方法(0:Optimal,1:1-pass,N;Multi-pass) Used-Tmp:使用されたTEMPサイズ 省略すると最後のSQL

(29)

実行計画の確認方法

リアルタイムSQL監視

実行中の実行計画を表示

(デフォルトで5秒以上のSQL、MONITORヒントで強制的に)

時間のかかっているSQLが自動的に監視

されリストされる (経過時間等でソート可能)

このSQL実行

全体の統計

実行計画のステッ

プごとの統計など

ステップごとの待機イベント

(30)

カーディナリティ

述語を適用した行数(Rows、E-Rows、A-Rows)

アクセス方法

索引スキャン、フル・スキャン、ビュー・アクセス

結合方法

ネステッド・ループ結合、ハッシュ結合、ソート・マージ結合、直積

結合タイプ

外部結合、セミ結合、アンチ結合

結合順序

SQLによって決まる場合も

実行計画の解説

注目する項目

(31)

パーティション

パーティション・プルーニング

パラレル実行

データ分散のステップが増える

実行計画の解説

注目する項目

(32)

実行計画の解説

リーフ・ステップ(インデントの一番深いステップ)から実行して、結合(同一インデ

ント)は上位に表示されたものが最初になる

SQL> SELECT … FROM tab1,tab2,tab3 WHERE tab1.c2=tab2.c2 AND tab1.c3=tab3.c3 AND tab1.c1<100

2 GROUP BY … ORDER BY … ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---| … ---| Cost (%CPU)---|

---| 0 ---| SELECT STATEMENT ---| ---| ---| ---| 271 (1)---|

| 1 | SORT GROUP BY | | | | |

|* 2 | HASH JOIN | | | | |

|* 3 | HASH JOIN | | | | |

|* 4 | TABLE ACCESS FULL | TAB1 |

10 | | |

| 5 | TABLE ACCESS FULL | TAB2 | 50 | | |

| 6 | TABLE ACCESS FULL | TAB3 | 100 | | |

(1)

(2)

(3)

| TABLE ACCESS BY INDEX ROWID| TAB1 |

| INDEX RANGE SCAN | IX_TAB1 |

索引アクセス

| VIEW | |

| HASH GROUP BY | |

| TABLE ACCESS FULL | TAB1 |

ビュー・アクセス

カーディナリティ

結合

CPUコスト・モデル

(CPUコストの割合)

(33)

実行計画の解説

後半には、述語の情報とNote部が出力される

実行計画 ---| Id ---| Operation ---| Name ---| ---| 0 ---| SELECT STATEMENT ---| ---| | 1 | SORT GROUP BY | | |* 2 | HASH JOIN | | |* 3 | HASH JOIN | | |* 4 | TABLE ACCESS FULL | TAB1 | | 5 | TABLE ACCESS FULL | TAB2 | …

Predicate Information (identified by operation id): ---2 - access("TAB1"."C---2"="TAB---2"."C---2") 3 – access("TAB1"."C3"="TAB3"."C3") 4 – filter("TAB1"."C1"<100) Note

---述語の情報(どのステップで述語が使用されているか)

Note部(内部的に動作しなものなど)

(34)

索引スキャン(シングル・ブロック・リード)

Index Range Scan(索引範囲スキャン)

Index Unique Scan(索引一意スキャン)

Index Skip Scan(索引スキップ・スキャン)

後方一致(中間一致)条件

フル・スキャン

Table Full Scan(全表スキャン)

テーブルをマルチ・ブロック・リード

Index Full Scan(全索引スキャン)

シングル・ブロック・リード

Index Fast Full Scan(高速全索引スキャン)

リーフ・ノードをマルチ・ブロック・リード

実行計画の解説

アクセス方法

< 50 < 20 30 < 60 70 1 0 11 12 3 0 31 50 51

範囲スキャン/全

索引スキャン

(35)

Index Unique Scan

一意索引の等価条件

Index Range Scan

非一意索引の等価条件

一意索引/非一意索引の範囲条件

実行計画の解説

アクセス方法(Index Range Scan / Index Unique Scan)

SQL> SELECT * FROM tab1 WHERE c1 < 10; 実行計画

---| Id ---| Operation ---| Name ---| ---| 0 ---| SELECT STATEMENT ---| ---| | 1 | TABLE ACCESS BY INDEX ROWID| TAB1 | SQL> SELECT * FROM tab1 WHERE c1 = 10;

実行計画

---| Id ---| Operation ---| Name ---| ---| 0 ---| SELECT STATEMENT ---| ---| | 1 | TABLE ACCESS BY INDEX ROWID| TAB1 |

(36)

後方一致(中間一致)条件での索引スキャン(Oracle9iから)

全表スキャンより効果的なとき(c1の個別値が少ないときなど)

実行計画の解説

アクセス方法(Index Skip Scan)

SQL> CREATE INDEX ix2_tab1 ON tab1 (c1,c2);

SQL> SELECT * FROM tab1 WHERE c2 = 10;

実行計画

---| Id ---| Operation ---| Name ---|

---| 0 ---| SELECT STATEMENT ---| ---|

| 1 | TABLE ACCESS BY INDEX ROWID| TAB1

|

|* 2 |

INDEX SKIP SCAN

| IX2_TAB1 |

c1 c2 1 1 ・・・ 1 1 2 ・・・ 10 2 2 ・・・ 2 1 2 ・・・ 10 3 3 ・・・ 1 2 ・・・ 10 3 ・・・ ・・・

テーブル

索引

c1の値ごとにc2=10を行う

c1=1 AND c2=10

c1=2 AND c2=10

c1=3 AND c2=10

・・・

(37)

索引範囲スキャンはできないが(索引に対する条件はないが)

ソート処理が必要なときなど

実行計画の解説

アクセス方法(Index Full Scan)

SQL> CREATE INDEX ix2_tab1 ON tab1 (c1,c2);

SQL> SELECT * FROM tab1 WHERE c2 > 10 ORDER BY c1;

実行計画

---| Id ---| Operation ---| Name ---|

---| 0 ---| SELECT STATEMENT ---| ---|

| 1 | TABLE ACCESS BY INDEX ROWID| TAB1

|

|* 2 | INDEX FULL SCAN | IX2_TAB1 |

(38)

テーブルをアクセスする必要がないとき

テーブルより索引の方がサイズが小さい

実行計画の解説

アクセス方法(Index Fast Full Scan / Table Full Scan)

SQL> CREATE INDEX ix2_tab1 ON tab1 (c1,c2);

SQL> SELECT c1,c2 FROM tab1 WHERE c1 > 10;

実行計画

---| Id ---| Operation ---| Name ---|

---| 0 ---| SELECT STATEMENT ---| ---|

|* 1 | INDEX FAST FULL SCAN| IX2_TAB1 |

SQL> SELECT * FROM tab1 WHERE c1 > 10;

実行計画(全表スキャン)

---| Id ---| Operation ---| Name ---|

---| 0 ---| SELECT STATEMENT---| ---|

|* 1 | TABLE FULL SCAN| TAB1 |

(39)

ビュー/インライン・ビューをマージしないとき(”VIEW”が出力される)

内部的に作成されたときでも出力される

実行計画の解説

アクセス方法(ビュー・アクセス)

SQL> SELECT … FROM tab2,

(SELECT c1,sum(c2) FROM tab1 GROUP BY c1)

A WHERE A.c1 = tab2.c1 ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 | HASH JOIN | | xxx |

| 2 |

VIEW

| | 50 |

| 3 | HASH GROUP BY | | 50 |

| 4 | TABLE ACCESS FULL| TAB1 | 100K|

| 5 | TABLE ACCESS FULL | TAB2 | 100 |

SQL> SELECT … FROM tab1,tab2

2 WHERE tab1.c1 = tab2.c1 GROUP BY c1 ;

実行計画(ビュー・マージすると)

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 | HASH GROUP BY | | |

| 2 | HASH JOIN | | xxx |

| 3 | TABLE ACCESS FULL| TAB2 | 100 |

(40)

Nested Loop Join(ネステッド・ループ結合)

索引を使用する結合のためアクセス行数が多いと性能が悪くなる

索引アクセスのI/Oを改善

Multi Join Key Pre-fetching(Oracle9iから)

Nested Loops Join Batching(Oracle Database 11gから)

Hash Join(ハッシュ結合)

索引を使用しない等価結合

Sort Merge Join(ソート・マージ結合)

索引を使用しない等価結合以外など

Cross Join(直積)

結合条件がない(負荷が高いのでできるだけ使用しないように)

実行計画の解説

(41)

基本は内部表の索引を使用して結合する

駆動表は絞り込み条件があるときに索引スキャン

実行計画の解説

結合方法(ネステッド・ループ結合)

SQL> SELECT … FROM tab1,tab2 WHERE tab1.c1 = tab2.c1 GROUP BY … ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 | HASH GROUP BY | | |

| 2 |

NESTED LOOPS

| | xxx |

| 3 | TABLE ACCESS FULL | TAB2 | 100 | <- 駆動表

| 4 | TABLE ACCESS BY INDEX ROWID| TAB1 | xxx | <- 内部表

|* 5 | INDEX RANGE SCAN | IX_TAB1 | xxx |

(42)

Multi Join Key Pre-fetching(Oracle 9iから)

索引レンジ・スキャンのデータ・ブロックの先読み

実行計画の解説

結合方法(ネステッド・ループ結合)

SQL> SELECT … FROM tab1,tab2 WHERE tab1.c1 = tab2.c1 GROUP BY … ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 | HASH GROUP BY | | |

| 2 | TABLE ACCESS BY INDEX ROWID| TAB1 | xxx | 内部表をPer-fetchする(Id=5のROWIDから)

| 3 |

NESTED LOOPS

| | xxx |

| 4 | TABLE ACCESS FULL | TAB2 | 100 | 駆動表

(43)

Nested Loops Join Batching(Oracle Database 11gから)

索引で結合後にROWIDを並べ替えてテーブルにアクセス(索引一意スキャンも可)

実行計画の解説

結合方法(ネステッド・ループ結合)

SQL> SELECT … FROM tab1,tab2 WHERE tab1.c1 = tab2.c1 GROUP BY … ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 | HASH GROUP BY | | |

| 2 | NESTED LOOPS | | xxx | Nested Loops Join(2)

| 3 |

NESTED LOOPS

| | xxx | Nested Loops Join(1) => 結果を駆動表(2)

| 4 | TABLE ACCESS FULL | TAB2 | 100 | 駆動表(1)

|* 5 | INDEX RANGE SCAN | IX_TAB1 | xxx | 内部表(1)(索引のみにアクセス)

| 6 | TABLE ACCESS BY INDEX ROWID| TAB1 | xxx | 内部表(2)(

ここのI/Oを最適化

ROWIDを

並べ替えて

(44)

索引の代わりにメモリ上にハッシュ・テーブルを作成

(最初にアクセスするテーブル)

片方のテーブル(アクセスするデータ)が小さいと効果的

等価結合のみ

結合列以外で絞り込み条件があるときに索引スキャン

実行計画の解説

結合方法(ハッシュ結合)

SQL> SELECT … FROM tab1,tab2 WHERE tab1.c1 = tab2.c1 GROUP BY … ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---| ---| 0 ---| SELECT STATEMENT ---| ---| ---| | 1 | HASH GROUP BY | | | | 2 | HASH JOIN | | xxx |

| 3 | TABLE ACCESS FULL| TAB2 | 100 |←ハッシュ・テーブルを作成

(45)

索引の代わりにソートして結合

等価結合以外など

絞り込み条件があるときに索引スキャン

実行計画の解説

結合方法(ソート・マージ結合)

SQL> SELECT … FROM tab1,tab2 WHERE tab1.c1 > tab2.c1 GROUP BY … ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---| ---| 0 ---| SELECT STATEMENT ---| ---| ---| | 1 | HASH GROUP BY | | | | 2 | MERGE JOIN | | xxx | | 3 | SORT JOIN | | 100 | | 4 | TABLE ACCESS FULL| TAB2 | 100 | |* 5 | SORT JOIN | | 100K|

(46)

できるだけ行わない

結合条件がないので効率が悪い

実行計画の解説

結合方法(直積)

SQL> SELECT … FROM tab1,tab2 GROUP BY … ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 | HASH GROUP BY | | |

| 2 |

MERGE JOIN CARTESIAN

| | |

| 3 | TABLE ACCESS FULL | TAB2 | 100 |

| 4 | BUFFER SORT | | 100K|

←ソートする(メモリにバッファリングするため)

(47)

Outer Join(外部結合)

OUTER JOIN

Semi Join(セミ結合)

EXISTS, IN

Anti Join(アンチ結合)

NOT EXISTS, NOT IN

このような特殊な結合タイプは結合順が決まっている

Oracle Database 10gでハッシュ結合の結合順を改善

実行計画の解説

結合タイプ

アンチ結合

主問合せ 副問合せ

セミ結合

主問合せ 副問合せ

(48)

左外部結合、右外部結合

Oracle Database 10gからハッシュ結合で核でないテーブルを先にアクセス可能に

実行計画の解説

結合タイプ(外部結合)

SQL> SELECT … FROM tab1 LEFT OUTER JOIN tab2 USING (c1) GROUP BY … ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 | HASH GROUP BY | | |

| 2 |

HASH JOIN OUTER

| | |

| 3 | TABLE ACCESS FULL| TAB1 | 100K|

| 4 | TABLE ACCESS FULL| TAB2 | 100 |

実行計画(Oracle Database 10gから)

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 | HASH GROUP BY | | |

| 2 |

HASH JOIN RIGHT OUTER

| | |

| 3 | TABLE ACCESS FULL | TAB2 | 100 |

| 4 | TABLE ACCESS FULL | TAB1 | 100K|

(49)

完全外部結合

Native Full Outer Join(Oracle Database 11gから)

以前はFull Outer Joinを二つのブランチのUNION ALLで(Left Outer JoinとNOT EXISTS)

実行計画の解説

結合タイプ(外部結合)

SQL> SELECT * FROM tab1 A FULL OUTER JOIN tab2 B USING (c1) ;

実行計画

---| Id ---| Operation ---| Name ---|

---| 0 ---| SELECT STATEMENT ---| ---|

| 1 | VIEW | VW_FOJ_0 |

|* 2 |

HASH JOIN FULL OUTER

| |

| 3 | TABLE ACCESS FULL | TAB1 |

| 4 | TABLE ACCESS FULL | TAB2 |

<以前は以下のSQLを実行>

SQL> SELECT *

2 FROM tab1 LEFT OUTER JOIN tab2 USING (c1)

3 UINON ALL

4 SELECT * FROM tab2 B WHERE NOT EXISTS

(50)

EXISTS、IN条件の副問合せ

Oracle Database 10gからセミ・ハッシュ結合で副問合せのテーブルを先にアクセス可能

実行計画の解説

結合タイプ(セミ結合)

SQL> SELECT … FROM tab1 WHERE

EXISTS

(SELECT 0 FROM tab2 WHERE tab1.c1 = tab2.c1) ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 |

HASH JOIN SEMI

| | |

| 2 | TABLE ACCESS FULL| TAB1 | 100K|

| 3 | TABLE ACCESS FULL| TAB2 | 100 |

実行計画(Oracle Database 10gから)

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 |

HASH JOIN RIGHT SEMI

| | |

| 2 | TABLE ACCESS FULL | TAB2 | 100 |

| 3 | TABLE ACCESS FULL | TAB1 | 100K|

(51)

NOT EXISTS、NOT IN条件の副問合せ

Oracle Database 10gからアンチ・ハッシュ結合で副問合せのテーブルを先にアクセス可能

実行計画の解説

結合タイプ(アンチ結合)

SQL> SELECT … FROM tab1 WHERE

NOT EXISTS

(SELECT 0 FROM tab2 WHERE tab1.c1 = tab2.c1) ;

実行計画

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 |

HASH JOIN ANTI

| | |

| 2 | TABLE ACCESS FULL| TAB1 | 100K|

| 3 | TABLE ACCESS FULL| TAB2 | 100 |

実行計画(Oracle Database 10gから)

---| Id ---| Operation ---| Name ---| Rows ---|

---| 0 ---| SELECT STATEMENT ---| ---| ---|

| 1 |

HASH JOIN RIGHT ANTI

| | |

| 2 | TABLE ACCESS FULL | TAB2 | 100 |

| 3 | TABLE ACCESS FULL | TAB1 | 100K|

(52)

パーティション・プルーニング

静的プルーニングと動的プルーニング(バインド変数、データ型の暗黙変換など)

パーティションの開始と終了の項目が増える

Pstart:アクセス開始のパーティション(静的:数字、動的:KEY)

Pstop:アクセス終了のパーティション(静的:数字、動的:KEY)

ジェイン・フィルター(ブルーム・フィルタリング)

結合列のパーティション・プルーニング

パーティション化された明細表をマスタ表の条件で検索するなど

このSQLのときなどに’明細表.c1’でパーティション・プルーニングを行う

実行計画の解説

パーティション

(53)

実行計画の解説

パーティション(パーティション・プルーニング)

SQL> SELECT * FROM tab01 WHERE sdate = TO_DATE('2012/08/01','YYYY/MM/DD'); 実行計画(静的パーティション・プルーニング)

---<途中省略>---| Id ---<途中省略>---| Operation ---<途中省略>---| Name ---<途中省略>---| ---<途中省略>---| Pstart---<途中省略>---| Pstop ---<途中省略>---| ---<途中省略>---| 0 ---<途中省略>---| SELECT STATEMENT ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| | 1 | PARTITION RANGE SINGLE | | | 8 | 8 | |* 2 | TABLE ACCESS FULL | TAB01 | | 8 | 8 |

実行計画(動的パーティション・プルーニング)

---<途中省略>---| Id ---<途中省略>---| Operation ---<途中省略>---| Name ---<途中省略>---| ---<途中省略>---| Pstart---<途中省略>---| Pstop ---<途中省略>---| ---<途中省略>---| 0 ---<途中省略>---| SELECT STATEMENT ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| | 1 | PARTITION RANGE SINGLE | | | KEY | KEY | |* 2 | TABLE ACCESS FULL | TAB01 | | KEY | KEY |

• バインド変数

• データ型の暗黙変換 • など

(54)

結合時に効果的にフィルタリングする(結合列でフィルタリングする)

ymでフィルターされたtime_cdのビットマップを作成する

実行計画の解説

パーティション(ジョイン・フィルター/ブルーム・フィルタリング)

SQL>

SELECT * FROM sales_h S, time T

2 WHERE S.time_cd = T.time_cd AND T.ym = TO_DATE('201201','YYYYMM') ;

実行計画

---<途中省略>---| Id ---<途中省略>---| Operation ---<途中省略>---| Name ---<途中省略>---| ---<途中省略>---| Pstart---<途中省略>---| Pstop ---<途中省略>---|

---<途中省略>---| 0 ---<途中省略>---| SELECT STATEMENT ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---|

|* 1 | HASH JOIN | | | | |

| 2 | PART JOIN FILTER CREATE | :BF0000 | | | |

| 3 | PARTITION RANGE SINGLE | | | 1 | 1 |

|* 4 | TABLE ACCESS FULL | time | | 1 | 1 |

| 5 |

PARTITION RANGE JOIN-FILTER

| | |

:BF0000

|

:BF0000

|

| 6 | TABLE ACCESS FULL | sales_h | |

:BF0000

|

:BF0000

|

(55)

スキャンのデータ分散

ブロック単位(PX BLOCK ITERATOR)

パーティション単位(PX PARTITION RANGE ALLなど)

データ分散しない(片方の読込みデータが少ないとき)

それぞれのPQプロセスで全てのデータ

スキャン以外でのデータ再分散

PX SEND HASH / RANGE / BROADCAST / PARTITION

基本はHASH(重複データが多いときに注意)

PX RECEIVE

実行計画の解説

パラレル実行(データ分散)

PQ スキャン 表 PQ PQ PQ 結合 PQ PQ PQ PQ QC PQ PQ PQ PQ OrderBy スキャン以外でのデータ再分散 スキャンのデータ分散

(56)

Block-based granules

ブロック単位で分割してアクセス

PX BLOCK ITERATOR

Partition-based granules

パーティション単位に分割してアクセス

パーティション・ワイズ結合など

PX PARTITION RANGE ALL

PX PARTITION HASH ALL

など

実行計画の解説

パラレル実行(スキャンのデータ分散)

PQ スキャン PQ PQ PQ QC

P1

P2

P3

P4

PQ スキャン PQ PQ PQ QC

(57)

操作内パラレル化のデータ分散(偏りが発生すると効果が低下する)

HASH(基本はこれを使用する)

重複データが多いときに注意

RANGE(ソートなど)

BROADCAST(結合の片方が小さい)

同じデータをすべてのプロセスに

PARTITION(パーティション・ワイズ結合)

パーティション分割(片方がパーティション表のとき)

NONE(データ分散しない/データ通信しない)

PX SEND xxxxとPX RECEIVEがない

PARTITIONやBROADCASTなどと使用

実行計画の解説

パラレル実行(スキャン以外でのデータ再分散)

PQ スキャン 表 操 作 間 パ ラ レ ル 化 操作内パラレル化 PQ PQ PQ 結合 PQ PQ PQ PQ QC PQ PQ PQ PQ OrderBy ① ② ③ PX SEND xxxx PX RECEIVE

(58)

結合の片方をデータ分散しない(スキャンと結合が同じプロセス)

実行計画の解説

パラレル実行(BROADCAST分散とPARTITION分散)

スキャン +結合

P2

P3

P4

PQ スキャン PQ PQ PQ 結合 PQ PQ PQ PQ tab1 tab2

P1

PARTITION分割 (パーシャル・パーティション・ワイズ結合) 結合 tab1 BROADCAST分割 スキャン PQ PQ PQ PQ tab2 PQ PQ PQ PQ スキャンと結合が同じプロセス スキャン +結合 同じデータを 全プロセスに tab2の パーティション に合わせる フル・パーティション・ワイズ結合は、どちらでもデータ分散しない

(59)

実行計画の解説

パラレル実行

SQL> SELECT * FROM tab01,tab02 WHERE tab01.c1 = tab02.c1 ORDER BY c0;

実行計画

---<途中省略>---| Id ---<途中省略>---| Operation ---<途中省略>---| Name ---<途中省略>---| ---<途中省略>---| TQ ---<途中省略>---|IN-OUT---<途中省略>---| PQ Distrib ---<途中省略>---| ---<途中省略>---| 0 ---<途中省略>---| SELECT STATEMENT ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| | 1 | PX COORDINATOR | | | | | | | 2 | PX SEND QC (ORDER) | :TQ10003 | | Q1,03 | P->S | QC (ORDER) | | 3 | SORT ORDER BY | | | Q1,03 | PCWP | | | 4 | PX RECEIVE | | | Q1,03 | PCWP | | | 5 | PX SEND RANGE | :TQ10002 | | Q1,02 | P->P | RANGE | | 6 | HASH JOIN BUFFERED | | | Q1,02 | PCWP | | | 7 | PX RECEIVE | | | Q1,02 | PCWP | | | 8 | PX SEND HASH | :TQ10000 | | Q1,00 | P->P | HASH | | 9 | PX BLOCK ITERATOR | | | Q1,00 | PCWC | | | 10 | TABLE ACCESS FULL| TAB01 | | Q1,00 | PCWP | | | 11 | PX RECEIVE | | | Q1,02 | PCWP | | | 12 | PX SEND HASH | :TQ10001 | | Q1,01 | P->P | HASH | | 13 | PX BLOCK ITERATOR | | | Q1,01 | PCWC | |

結合プロセス(データをチェッ クするので同じプロセス)

PX PARTITION RANGE ALL

スキャンの データ分散

PX SEND PARTITION PX SEND BROADCAST

(60)

片方の読込みデータが少ないときはBROADCASTも行わない

それぞれのプロセスで全てのデータをスキャンする(スキャンのデータ分散もしない)

実行計画の解説

パラレル実行(データ分散なし)

SQL> SELECT COUNT(*) FROM (SELECT * FROM t3,t1 WHERE t3.col1 = t1.col1);

実行計画

---| Id ---| Operation ---| Name ---| Starts ---| E-Rows ---| ---| TQ ---|IN-OUT---| PQ Distrib ---| A-Rows ---| ---| 0 ---| SELECT STATEMENT ---| ---| 1 ---| ---| ---| ---| ---| ---| 1 ---| | 1 | SORT AGGREGATE | | 1 | 1 | | | | | 1 | | 2 | PX COORDINATOR | | 1 | | | | | | 4 | | 3 | PX SEND QC (RANDOM) | :TQ10000 | 0 | 1 | | Q1,00 | P->S | QC (RAND) | 0 | | 4 | SORT AGGREGATE | | 4 | 1 | | Q1,00 | PCWP | | 4 | |* 5 | HASH JOIN | | 4 | 50000 | | Q1,00 | PCWP | | 100K| | 6 | TABLE ACCESS FULL | T3 | 4 | 5 | | Q1,00 | PCWP | | 20 | | 7 | PX BLOCK ITERATOR | | 3 | 100K| | Q1,00 | PCWC | | 100K| |* 8 | TABLE ACCESS FULL| T1 | 52 | 100K| | Q1,00 | PCWP | | 100K|

パラレル度が4なので、4つのPQプロセスで5行 リードしている(A-Rowsは20行になっている) すべて同一プロセス

(61)

アジェンダ

1 2 3

SQLチューニングとは

オプティマイザの概要

実行計画

実行計画のチューニング

Oracle Database 12cの拡張

4 5

(62)

索引(最適な索引)を使用していない

結合行数が多い

重複値が多い場合は要注意

結合方法や結合順が悪い

副問合せが効果的に使用されていない

TEMP領域を使用している

実行計画のチューニング

SQLが遅くなる主な原因

(63)

AWR / EM(Enterprise Manager)から特定する

Top 5 Timed Events

どこに時間が掛っているか

SQL統計

問題のSQLを探す

SQL ordered by Elapsed Time

• パラレル実行ではすべてのプロセスの合計時間になる

SQL ordered by CPU Time

SQL ordered by User I/O Wait Tim

など

PL/SQLはPL/SQLとその中のSQLの両方が出力される

すべての実行の合計になる(実行回数に注意)

実行計画のチューニング

(64)

CPUが多いのかI/Oが多いのか(またはその他の待機が多いか)

• db file sequential read(索引スキャンの待機)

• db file scattered read(フル・スキャンの待機) / direct path read(バッファ・キャッシュを経由しないフル・スキャンの待機)

• db file parallel read(リカバリ、プリフェッチの読込みの待機)

• direct path read temp(Tempからの読込みの待機)

実行計画のチューニング

(65)

実行計画のチューニング

(66)

実行計画のチューニング

(67)

実行計画のチューニング

(68)

チューニングの手順(この順番で改善できるか検討する)

1.

オプティマイザ統計の再収集

2.

索引の作成(索引のチューニング)

3.

SQLの変更(ヒントの追加)

SQL計画ベースラインの設定(SQL Plan Management)

SQLの変更ができない

SQLチューニング・アドバイザ

問題を特定できない

実行計画のチューニング

(69)

行数の見積もりが正しくない(実行時と大きく異なるとき)

実行計画の見積もり行数(E-Rows)と実行行数(A-Rows)を比較

実行計画のチューニング

オプティマイザ統計の再収集

SQL> SELECT /*+ GATHER_PLAN_STATISTICS */ c1,c2,c3 FROM tab01 WHERE c1 = 11 ;

レコードが選択されませんでした。

SQL> SELECT * FROM TABLE(dbms_xplan.display_cursor(format=>'typical allstats last'));

実行計画

---| Id ---| Operation ---| Name ---| Starts ---| E-Rows ---|E-Bytes---| … ---| A-Rows ---| … ---|

---| 0 ---| SELECT STATEMENT ---| ---| 1 ---| ---| ---| … ---| 0 ---| … ---|

| 1 | TABLE ACCESS BY INDEX ROWID| TAB01 | 1 | 21 | 189| … | 0 | … |

|* 2 | INDEX RANGE SCAN | IX_TAB01 | 1 | 21 | | … | 0 | … |

(70)

全表スキャンを行っているテーブルは索引スキャンした方が良くないか

実行計画のRowsなどを確認

索引スキャンの効率が悪くないか

索引の列の組合せ、索引の列の順番などを確認

例えば、以下のようなSQL

優先順位を明確にして作成する

これが難しい(そのため、フル・スキャンでも高速なExadataが効果的)

作り過ぎないように使用しない索引は削除する(次頁参照)

実行計画のチューニング

索引の作成(索引のチューニング)

SQL> SELECT … WHERE c1=xx AND c2=xx AND c3=xx; ①

SQL> SELECT … WHERE c1=xx AND c3=xx;

SQL> SELECT … WHERE c1=xx AND c2=xx AND c4=xx; ③

列(c3,c1)の索引が作成されているとすると

①と②はIndex Range Scanになる(②の方が

より効果的な索引スキャンになる)

③はIndex Skip Scanになる(c3の条件がない)

(71)

『使われていない索引を削除したい』

索引のMONITORING属性を設定することにより、V$OBJECT_USAGEビューを検索

することにより監視できます(Oracle9i ~)

SQL> ALTER INDEX PK_EMP

MONITORING USAGE;

SQL> SELECT * FROM v$object_usage WHERE INDEX_NAME='PK_EMP' ;

INDEX_NAME TABLE_NAME MON USE START_MONITORING END_MONITORING

--- --- --- ---- ---

---PK_EMP EMP YES NO 01/16/2014 08:29:03

実行計画のチューニング

(72)

オプティマイザの判断を調整する

問合せ変換が最適でない

結合方法や結合順が最適でない

効率の悪いアクセスを改善する

索引が使用できない

同じテーブルに複数回アクセスしている

Redoログを出力しないように

TEMP領域の使用を改善する

プロセスで使用するデータ・サイズを小さくする

パラレル度を上げる、プログラムを分割/並列化する

索引を使用する(結合とソートなど)

実行計画のチューニング

SQLの変更/ヒントの追加(主なチューニング)

TEMP領域を使用しないときでも

性能を向上させるためには重要

(73)

索引を使用しない条件を変更する(可能であれば)

演算している、NULL比較、NOT(!=)、OR、後方一致(中間一致)条件

インライン・ビューを作成する(問合せ変換しないとき)

結合前に行数を削減する(Group by Placementなどを明示的に)

結合するUPDATE文をMERGE文にする(UPDATE のみでも可)

UPDATE文で結合するには副問合せが必要(効率が悪い)

SQLを分割する(WITH句を使用する)

同じ副問合せを複数回使用するなど

実行計画のチューニング

SQLの変更(主なSQLの変更)

(74)

ダイレクト・インサートにする(UPDATE、DELETEなども)

NOLOGGING属性でRedoログが出力されない

同じテーブルにアクセスするSQLを一つにする

CASE式(条件の異なるSELECTから)

マルチ・テーブル・インサート(同じテーブルにも使用できる)

MERGE文(UPDATE & INSERTから)

補足説明参照

実行計画のチューニング

(75)

結合順を変える

ORDERED(FROM句の順番に結合する)、LEADING(指定した順番に結合する)

ビュー・マージを行わない

NO_MERGE(指定ビューをマージしない)

索引を使用する

INDEX(索引スキャン)、INDEX_FFS(高速全索引スキャン)

索引を使用しない

FULL(全表スキャン)、NO_INDEX(指定索引を使用しない)

結合方法を変える

実行計画のチューニング

SQLの変更(主に使用するヒント)

(76)

ヒントを入れた実行計画をベースラインとして登録する

索引スキャンを全表スキャンに変更

実行計画のチューニング

SQL計画ベースラインの設定

SELECT * FROM tab01 WHERE c1 = 1;

SELECT /*+ FULL(tab01) */ * FROM tab01 WHERE c1 = 1; SQL計画ベースライン プランA プランB 常にSQL計画ベースラインに ある実行計画が使用される プランB 変更(A → B) 実行

(77)

問題のSQLを特定できないときはOracleデータベースに任せる

実行計画のチューニング

SQLチューニング・アドバイザ

・統計の分析 ・アクセス・パスの分析 ・SQLプロファイリング ・SQL構造分析 ・代替計画分析(11gR2から) 分析 ・統計の再収集 ・索引の作成/SQLアクセス・アドバイザの実行 ・SQLプロファイルの作成 ・SQLのリライト ・SQL計画ベースラインの作成 推奨事項 高負荷の SQL文 自動チューニング・オプティマイザ SQLチューニング ・アドバイザ

(78)

Group byなどで重複値をなくす

慣れないと難しいですが

結合列’tab2.c1’でGROUP BYを行う

最終的にSUM関数を行う

SQLの変更

補足説明(インライン・ビューを作成する)

SQL> SELECT A.c2, count(*) FROM tab1 A, tab2 B

2 WHERE A.c1 = B.c1 AND B.c2 = 10 GROUP BY A.c2;

SQL> SELECT A.c2,

sum(ct)

FROM tab1 A,

2 (SELECT c1,count(*) ct FROM tab2 WHERE c2 = 10

GROUP BY c1

) B

3 WHERE A.c1 =

B.c1

GROUP BY A.c2;

(79)

あるテーブルのデータでUPDATEするなど

テーブルのアクセスが2回になる

SQLの変更

補足説明(結合するUPDATE文をMERGE文にする)

SQL> UPDATE t01 A SET A.c3 = A.c3 + (SELECT c2 FROM t02 B WHERE A.c1 = B.c1) 2 WHERE EXISTS (SELECT 0 FROM t02 B WHERE A.c1 = B.c1);

実行計画 ---| Id ---| Operation ---| Name ---| ---| 0 ---| UPDATE STATEMENT ---| ---| | 1 | UPDATE | T01 | |* 2 | HASH JOIN SEMI | | | 3 | TABLE ACCESS FULL| T01 | | 4 | TABLE ACCESS FULL| T02 | |* 5 | TABLE ACCESS FULL | T02 |

---Predicate Information (identified by operation id):

---2 - access("A"."C1"="B"."C1")

SQL> MERGE INTO t01 A

2 USING (SELECT c1,c2 FROM t02) B 3 ON (A.c1 = B.c1)

4 WHEN MATCHED THEN UPDATE SET A.c3 = A.c3 + B.c2; 実行計画 ---| Id ---| Operation ---| Name ---| ---| 0 ---| MERGE STATEMENT ---| ---| | 1 | MERGE | T01 | | 2 | VIEW | | |* 3 | HASH JOIN | | | 4 | TABLE ACCESS FULL| T02 |

(80)

繰り返し副問合せはWITH句で

SQLの変更

補足説明(WITH句を使用する)

SQL> SELECT * FROM

2 (

SELECT 部門,sum(売上) 部門売上 FROM 売上表 GROUP BY 部門

) w_abc

3 WHERE 部門売上 < (SELECT avg(部門売上) FROM

4 (

SELECT 部門,sum(売上) 部門売上 FROM 売上表 GROUP BY 部門

));

SQL> WITH w_abc AS (SELECT 部門, sum(売上) FROM 売上表 GROUP BY 部門)

2 SELECT * FROM w_abc

(81)

UPDATEやDELETEはダイレクト・インサートする

特にパラレル実行には効果的(Redoログのネックになりやすい)

SQLの変更

補足説明(ダイレクト・インサートにする)

SQL> DELETE FROM tab000

2 WHERE 日付 < TO_DATE(‘20101001’,’YYYYMMDD’) ;

SQL> CREATE TABLE tab001 NOLOGGING PARALLEL AS

2 SELECT * FROM tab000

3 WHERE 日付

>=

TO_DATE(‘20101001’,’YYYYMMDD’) ;

SQL> DROP TABLE tab000 ;

(82)

大量行のGroup byなどではメモリ不足になりやすい

指定日付の売上に対して過去の売上最新日時を求めるなど

SQLの変更

補足説明(TEMP領域を使用しない/索引を使用)

SQL> SELECT * FROM (SELECT * FROM sales WHERE dtime = TO_DATE('140401','YYMMDD')) A LEFT JOIN 2 (SELECT tenpo, prod, cust, MAX(dtime) dtime1 FROM sales

3 WHERE dtime < TO_DATE('140401','YYMMDD') GROUP BY tenpo, prod, cust) B 4 USING(tenpo, prod, cust) ;

実行計画

---<途中省略>---| Id ---<途中省略>---| Operation ---<途中省略>---| Name ---<途中省略>---| ---<途中省略>---| Used-Mem ---<途中省略>---| ---<途中省略>---| 0 ---<途中省略>---| SELECT STATEMENT ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| ---<途中省略>---| |* 1 | HASH JOIN OUTER | | | xxxxx (n)| |* 2 | TABLE ACCESS FULL | SALES | | | | 3 | VIEW | | | | | 4 | HASH GROUP BY | | | xxxxx (n)| |* 5 | TABLE ACCESS FULL | SALES | | |

(83)

索引を使用することでGroup byのメモリ使用を回避する

TEMP領域へのマルチ・パスI/Oより中間テーブル作成の方が効果的など

SQLの変更

補足説明(TEMP領域を使用しない/索引を使用)

SQL> CREATE INDEX ix_sale01 ON sales (tenpo, prod, cust, dtime); SQL> CREATE TABLE w_sal01 AS

2 SELECT tenpo, prod, cust, MAX(dtime) FROM sales

3 WHERE dtime < TO_DATE('140401','YYMMDD‘) GROUP BY tenpo, prod, cust; 実行計画

---| 0 ---| CREATE TABLE STATEMENT ---| ---| | 1 | LOAD AS SELECT | | | 2 | SORT GROUP BY NOSORT | | |* 3 | INDEX FULL SCAN | IX_SALE01 | …<省略>…

SQL> SELECT * FROM (SELECT * FROM sales WHERE dtime = TO_DATE('140401','YYMMDD')) A この列の順番で索引を作成することで Group byのソートを回避する

参照

関連したドキュメント

睡眠を十分とらないと身体にこたえる 社会的な人とのつき合いは大切にしている

ここで融合とは,バンカーが伝統的なエリートである土地貴族のライフスタ

非自明な和として分解できない結び目を 素な結び目 と いう... 定理 (

Secondly, the enumeration of finite group actions is a principal component of the analysis of singularities of the moduli space of conformal equivalence classes of Riemann surfaces of

1-regular pentavalent graph (that is, the full automorphism group acts regularly on its arc set) of square-free order is presented in [12], and all the possibilities of

We use the Eisenstein ideal of the Hecke algebra of the Drinfeld modular curve X 0 (pq) to compare the rational torsion subgroup of the Jacobian J 0 (pq) with its subgroup generated

ㅡ故障の内容によりまして、弊社の都合により「一部代替部品を使わ

市民的その他のあらゆる分野において、他の 者との平等を基礎として全ての人権及び基本