株式会社 日立製作所 情報・通信システム社 ITプラットフォーム事業本部 DB部
2015/06
HiRDB SQLコーディングガイドライン
© Hitachi, Ltd. 2013 , 2015. All rights reserved. 1. はじめに 2. インデクスを有効に使う記述 3. 副問合せに関する記述
Contents
1 4. 結合検索に関する記述 5. 表の分割に関する記述 6. DBの件数を考慮した記述 7. 排他に関する記述 8. 更新に関する記述 9. アプリケーション上での記述 10. 保守性を向上させるための記述 11. おわりに© Hitachi, Ltd. 2013 , 2015. All rights reserved.
1-1 本資料について
3 ■ 目的 データベース(以下本ドキュメントではDBと略す)へのアクセス性能は、SQL文の コーディング方法により左右されることがあります。本ガイドラインでは、DBへのアクセ ス性能を良くするための推奨のSQLコーディング方法を示します。本ガイドラインを 各プロジェクトのSQLコーディング規約を制定する際に活用していただくことで、DBに アクセスするアプリケーションの性能トラブルを、未然に防ぐことを目的とします。 なお、内容は一般的な推奨であり、必要であれば異なるSQLコーディング方法をとる ことを妨げるものではありません。 ■ 対象バーション 本ドキュメントは、HiRDB Version 8 以降を対象としています。 ■ 留意事項 本ドキュメントの例題にて、対比しているSQLは、必ずしも等価なSQLでないため、 SQL文を変形するときは、十分注意してください。 ■ コーディング例の凡例 本ドキュメントの例題にて、コーディングの推奨度合を記号表記しています。記号と意 味を以下に示します。 ◎:特に推奨 ○:推奨 △:改善の余地あり ×:推奨しない。改善が必要。 以下のURLより、HiRDBの基礎知識を理解しておくと、本資料の理解が深まります。 http://www.hitachi.co.jp/soft/hirdb/info/tech_info.html HiRDB技術資料のURL1-2 アプリケーション開発の流れ
・ ・ 1.スキーマ設計 2.プロジェクト内の SQLコーディング規約制定 3.アプリケーション開発 4.単体テスト 5.SI 性能とのトレードオフで正規化のレベルを考える 「ジョインは4表まで」など、プロジェクトで性能も含めた品質 を確保するための標準を定める ← 本ガイドラインを活用 コーディング規約に従って、アプリケーションを開発する SQLのアクセスパスを確認して、アプリケーション開発へ フィードバック© Hitachi, Ltd. 2013 , 2015. All rights reserved.
1-3
SQLのアクセスパスの評価
5 クライアント環境定義に以下を追加し、UAP統計レポートの中で取得します。 アクセスパスの取得 No. クライアント環境定義 統計情報の内容 1 PDCLTPATH 情報出力先。省略時は、カレントディレクトリが仮定されます。 2 PDSQLTRACE トレースのファイルサイズ(byte)を指定。0を指定した場合は、ファイルの最大のサイ ズとなります。省略をした場合は、情報を出力しない。 3 PDUAPREPLVL UAP統計レポートの出力情報を指定します。出力には、アクセスパス情報、SQL単 位の情報、UAP単位の情報、SQL実行時の中間結果情報があります。アクセスパス の解析時は、aを指定し全ての情報を出力することをお勧めします。 4 PDREPPATH UAP統計レポートファイルをPDCLTPATHで指定したディレクトリとは別の場所に格 納したい場合に指定する。指定すると、CONNECT単位にファイルが分かれる。 アクセスパスのチェック 以下のキーワードで示されるアクセスパスは、定性的に負荷の高い処理であるためチェックアウトします。 ' TABLE SCAN ' …(データページ全参照[テーブルスキャン])' AND PLURAL INDEXES SCAN ' …(AND複数インデクス利用) ' MERGE JOIN ' …(マージジョイン)
' CROSS JOIN ' …(直積)
' FULL SCAN ' …(インデクスリーフページのフルスキャン)
' WORK TABLE SUBQ ' …(副問合せ結果の作業表への繰り返しスキャン) ' NESTED LOOPS WORK TABLE SUBQ ' …(副問合せの繰り返し実行と作業表へのスキャン)
本ドキュメントを利用しSQLコーディング後、インデクスの使用有無、結合方法などが意図した通りにな っているか、効率の良いアクセスパスになっているかをSQLトレースのUAP統計レポート機能にて確認 することを心がけてください。
2.
インデクスを有効に使う記述
容量の多いDBを高速にアクセスする手段としてインデクスがあります。 しかし、インデクスを定義したにもかかわらず、インデクスが有効に使用され ないことがあります。
© Hitachi, Ltd. 2013 , 2015. All rights reserved. 7
コーディング方法を説明する前に、まず、インデクスを
どのように使ってアクセスするデータを絞り込んでいるか、
ご説明します。
2-1-1 検索方式
解説 各検索方式の特徴について解説します。 インデクスを有効に使う記述 キースキャン インデクスを参照してインデクス中の データ(インデクス構成列の値または 行識別子)にアクセスする方式です。 インデクスであまり絞り込めない場合 でも、データページの入出力がなく、 インデクスページを参照するだけな ので、高速に検索できます。 インデクススキャン インデクスを参照して条件に該当す るデータを絞り込んでから、テーブル のデータをアクセスする方法です。 インデクスであまり絞り込めない場合 は、データページに対するランダム な入出力が増え、性能が悪くなりま す。特にインデクスの全範囲が検索 対象になるケースをフルスキャンと 呼びます。 テーブルスキャン 検索条件の内容にかかわらず、検索 対象表の全行をシーケンシャルにア クセスする方法です。 条件によって検索結果を絞り込める 場合でも、すべてのデータページを 参照するため、データ量が多いと性 能は悪くなります。 インデクス インデクス 表データ 表データ© Hitachi, Ltd. 2013 , 2015. All rights reserved. 591S 671M
2-1-2 インデクスの基本構造
9 リーフページ 412M 671M 101L ・・・ 202M 302S ・・・ 412M 591L ・・・ 591S 671L ・・・ 671M 202M 412M 論理単位 説明 ルートページ B-tree構造中の最上位のインデクスページ。 下段のページを指しています。 中間ページ B-tree構造中の中間のインデクスページ。 下段のページを指しています。 リーフページ B-tree構造中の最下位のインデクスページ。 各インデクスページのキー値とそのアドレス を持っています。 中間ページ ルートページ 解説 インデクスは、キーとキー値から構成されます。列の内容を示した列名のことをキーといい ます。また、列の値のことをキー値といいます。表を検索するときの探索条件で使用する列 にインデクスを作成しておくと、表の検索性能が向上します。 : インデクスページ インデクスのB-tree構造 インデクスを有効に使う記述2-1-3 表検索時の条件の分類
サーチ条件:インデクスをサーチするための条件で、 インデクスのサーチ範囲が決定 キー条件:インデクス構成列のキー値で評価する条件で、 データページ中のアクセス行を削減 その他の条件:データページ中の 行データを参照して、条件を評価 サーチ条件+キー条件: データページのアクセス行が決定行の取出し
サーチ条件なしでのインデクス利用: インデクスリーフページのフルスキャン インデクス データ 解説 SQLの探索条件は、すべてサーチ条件にて評価できるのが望ましいです。 そして、それは、SQLの記述により変わります。 インデクスを有効に使う記述© Hitachi, Ltd. 2013 , 2015. All rights reserved. 11
次にインデクスを有効に使用するためのSQLコーディング
について示します。
なお、設計段階ではインデクスを定義しない予定であって
も、後のチューニングによりインデクスを定義することが考
えられるため、インデクス定義のみでインデクスが有効とな
るようなSQLにしておく必要があります。
インデクスを有効に使う記述2-2 条件指定によるインデクス効果(1)
条件指定(WHERE句)の"AND" 、"OR"指定の記述によって、指定項目が同じ場合でも インデクスの効果が低い場合があります。=条件の項目はインデクスの構成列の先頭か ら連続している項目をANDで指定すると効率が良いです。例を図 2-2-1、2-2-2に示しま す。 Point WHERE句のAND条件の指定順は、性能に影響しない すべてand条件の場合 項目の順番が入れ替わる ~ where C1 = 10 and C2 = 20 and C3 = 30○
~ where C1 = 10 and C3 = 30 and C2 = 20 ~ where C3 = 30 and C2 = 20 and C1 = 10 C1、C2、C3の順番には 関係なく、すべてのケース でインデクスが有効となる。 図 2-2-1 "AND"、"OR"指定 その1 複数列インデクスAを C1、C2、C3の順で定義。 インデクスを有効に使う記述 インデクスは以下の複数列インデクス A(C1,C2,C3)© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-2-1 条件指定によるインデクス効果(2)
13 すべてand条件の場合 インデクス未定義項目あり△
~ where C1 = 10 and C4 = 40 and C3 = 30 インデクスの先頭項目なし×
~ where C2 = 20 and C4 = 40 and C3 = 30 and条件とor条件の場合○
~ where ( C1 = 10 ) or ( C1 = 11 and C2 = 22 )×
~ where ( C1 = 10 and C2 = 20 ) or ( C3 = 30 ) 一致する先頭のC1のみ インデクスのサーチ条件が 有効となる。 先頭のC1が一致しないため インデクスが無効となる (リーフページのフルスキャン)。 andが優先されるが、orの それぞれにC1があるので、 インデクスは有効になる (インデクス検索をorの 両辺で2回行う)。 andが優先され、C3がorで独立 していると、C3はインデクスの 先頭でないのでインデクスが 無効となる (リーフページのフルスキャン)。 図 2-2-2 "AND"、"OR"指定 その2 インデクスを有効に使う記述 インデクスは以下の複数列インデクス A(C1,C2,C3)2-2-2 条件指定によるインデクス効果(例外的な事例)
インデクスを有効に使う記述 SELECT C1 ,・・・・・ FROM TBL1 WHERE C1 = ? AND C3 = ? AND CFLG = ? インデクスは以下の構成列の主キー(PK)のみ 定義されていた。 TBL1(C1,C2,C3) インデクスの第2構成列C2は、条件で 未使用のため、検索範囲の絞り込みは、 第1構成列でのみ実施した。 PK TBL1 図 2-2-3 例外的な事例 主キーによる検索を実施。 しかし、性能が出なかった。原因は? 第1構成列C1は、値がすべて同じだったため、 インデクス全範囲を検索となり遅かった。 インデクスを有効に使用するSQLコーディングをしていても性能が出なかった事例を示しま す。データの値がすべて同じ列は、基本的にインデクスから削除してください。業務等の都 合で当該列をインデクスから削除が出来ない場合は、後方の構成列としてください。 解説 値がすべて同じ列(C1)が インデクス構成列の先頭© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-2-3 探索条件と複数列インデクスのサーチ範囲
15 インデクス ア ア ア A 1 A A 2 3 ア ア ア A 4 B B 1 2 ア ア B B 3 4 ア ア C C 1 2 ア ア C C 3 4 イ イ イ A 1 A A 2 3 イ イ イ A 4 B B 1 2 イ イ B B 3 4 イ イ C C 1 2 イ イ C C 3 4 ウ ウ ウ A 1 A A 2 3 ウ ウ ウ A 4 B B 1 2 ウ ウ B B 3 4 ウ ウ C C 1 2 ウ ウ C C 3 4 エ エ A A 1 2 エ エ A A 3 4 C1= ’イ’ AND C2= ’B’ AND C3= 2 C1= ’イ’ AND C2= ’B’ C1= ’イ’ C1= ’イ’ AND C2= ’B’ AND C3>=2 C1= ’イ’ AND C2>=’B’ AND C3>=2 C1= ’イ’ AND C2>=’B’ AND C3= 2 C1= ’イ’ AND C2>=’B’ C1= ’イ’ AND C2>=’B’ AND C3<=2 C1>= ’イ’ AND C2= ’B’ AND C3= 2 C1>= ’イ’ AND C2= ’B’ AND C3>=2 C1>= ’イ’ AND C2= ’B’ C1>= ’イ’ AND C2= ’B’ AND C3<=2 C1>= ’イ’ C2= ’B’ AND C3= 2 C2= ’B’ C3= 2 C1 (C1, C2, C3) インデクスのサーチ範囲 探索条件を満たす範囲 上段と下段の差が大きい→ 効率悪 (注) 表の下3つは、リーフページのフルスキャンになり、特に効率が悪いです。 上段 下段 C2 C3 インデクスを有効に使う記述2-3 条件式での列演算の使用上の注意(1)
16 スカラ演算した条件はインデクスで評価されません、またはSQL最適化オプションに 「スカラ演算を含むキー条件の適用」を指定した場合は、インデクスのキー条件で評価 しますが効率的に絞り込めません。例を図 2-3-1、2-3-2に示します。 Point FROM句のON、WHERE句の探索条件において、列をスカラ演算しない(列を計 算式の中に組み入れない)条件式に変換可能な場合、列をスカラ演算しないこと 例1○
~ WHERE TANKA > 950 – 105×
~ WHERE TANKA + 105 > 950 例2○
~ WHERE JDATE1 = '2002' AND JDATE2 = '0301'○
~ WHERE (JDATE1, JDATE2) = ('2002','0301')×
~ WHERE JDATE1 || JDATE2 = '20020301'列を直接演算しない。 図 2-3-1 スカラ演算の例 その1 列を連結して判定しない。 行値構成子で記述 すれば効率よく インデクスを使用 できる。 インデクスを有効に使う記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-3-1 条件式での列演算の使用上の注意(2)
17
例3
○
~ WHERE SNAME LIKE 'TOKYOU%'×
~ WHERE SUBSTR(SNAME, 1, 6) = 'TOKYOU' 例4○
~ WHERE TANKA = 5×
~ WHERE TANKA * 12 = 60例5
○
~ (SNAME = 'xxx' AND ZSURYO = 1) OR (SNAME = 'yyy' AND ZSURYO <> 1)×
~ SNAME = CASE WHEN ZSURYO = 1 THEN 'xxx' ELSE 'yyy' END 先頭文字比較はLIKE を使用する。 列を直接演算しない。 CASE式を使用しない。 図 2-3-2 スカラ演算の例 その2 インデクスを有効に使う記述2-4
条件式での変数/定数へのスカラ演算の使用上の注意
変数をスカラ演算した条件はインデクスで評価されません、またはSQL最適化オプショ ンに「スカラ演算を含むキー条件の適用」を指定した場合は、インデクスのキー条件で 評価しますが効率的に絞り込めません。 定数をシステム定義スカラ関数、ユーザ定義関数の引数に指定した場合は、一切イン デクスが使用されません。 例を図 2-4-1に示します。 Point FROM句のON、WHERE句の探索条件において、 変数をスカラ演算しない(変数を計算式の中に組み入れない) 定数をシステム定義スカラ関数、ユーザ定義関数の引数に指定しない 変数のスカラ演算○
~ WHERE SNAME = ?×
~ WHERE SNAME = CAST(? AS CHAR(5))
定数のシステム定義スカラ関数
○
~ WHERE SNAME = 'ABC'×
~ WHERE SNAME = RTRIM('ABC ')変数をスカラ演算しない。 RTRIMは、システム定義スカラ関数。 あらかじめ必要な演算を実施した 定数を指定する。 ?パラメタに値を渡す埋込み変数は、 あらかじめCHAR(5)のデータとしておく。 図 2-4-1 変数/定数へのスカラ演算の例 インデクスを有効に使う記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-5 中間一致の回避
19 LIKE '%c%' でも、インデクスを使用しますが(場合によっては使用しない)、インデクス のリーフページをフルスキャンします。LIKEは、LIKE 'c%'やLIKE 'c_'のように前方一致 を指定すればインデクスの参照範囲を絞り込むことができるため、処理性能が向上する ことが多いです。例を図 2-5-1に示します。 Point LIKE述語は 中間一致('%xx%')、後方一致('%xxx')を避け、極力前方一致 ('xxx%')になるように記述すること○
~ WHERE SNAME LIKE 'TOKYOU%'
○
~ WHERE SNAME LIKE 'TOK%OU'
○
~ WHERE SNAME LIKE 'TOK___'×
~ WHERE SNAME LIKE '%KYO%'×
~ WHERE SNAME LIKE '%KYOU'×
~ WHERE SNAME LIKE '___YOU'×
~ WHERE SNAME LIKE '_O_Y_U_'LIKE述語のパターン文字列として?パラメタや埋込み変数を指定した場合も、上記の例 のように、設定するパターン文字列を前方一致になるようにすると良いです。 図 2-5-1 LIKEの例 中間一致、後方一致は避ける。 前方一致を用いる。 インデクスを有効に使う記述
2-6 複数列インデクスでの前方不一致検索の回避
複数列インデクスで前方不一致検索(インデクス構成列の前方の列を指定しない)を 行うと、インデクスのリーフページをフルスキャンします。例を図 2-6-1に示します。 Point 複数列インデクスの先頭構成列の条件を指定せず、第2構成列以降の条件を 指定することは避ける○
~ WHERE ZSURYO = 20 AND COL = 'blue'○
~ WHERE COL = 'blue' AND ZSURYO = 20○
~ WHERE ZSURYO = 20×
~ WHERE COL = 'blue'インデクス構成列の順と探索条件 指定順は一致しなくて良い。 図 2-6-1 複数列インデクス例 インデクスは以下の複数列インデクス X01(ZSURYO,COL) インデクスの先頭構成列のみ指定 でも良い。 インデクスの後方構成列のみ指定 (リーフページのフルスキャン)。 インデクスを有効に使う記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-7 インデクス列のみ選択の使用
21 問合せ指定でインデクス列のみを選択すると、インデクス列の値は表からではなく、 直接インデクスから読み込まれるため、非常に高速に処理できます。(インデクスページ のみの読み取りで、データページは読みません。これをキースキャンと呼びます。) 例を図 2-7-1に示します。 Point 選択式に指定する列は、必要最小限にし、さらにインデクス構成列のみ指定する と高速化できる○
SELECT ZSURYO, COL FROM ZAIKO WHERE ZSURYO < 100 ; 選択式も、探索条件もインデクス構 成列のみ指定すると非常に高速。 図 2-7-1 インデクス列のみ選択の例 インデクスは以下の複数列インデクス X01(ZSURYO,COL) インデクスを有効に使う記述 このことにより、探索条件に通常は指定しない列であっても、複数列インデクスに追加 することによってパフォーマンスが向上する場合があります。ただし、列サイズが小さく 頻繁に使用される場合のみ使用し、更新性能に十分注意してください。© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-8 行値構成子の利用(1)
22 複数列の大小比較をする場合、以下のような指定を行うとインデクスの使用効率が悪く なります。行値構成子を用いれば、インデクスを効率よく利用することができます。 複数列を組み合わせての大小比較は、andとorの条件を組み合わせることにより 記述できますが、インデクスの使用効率が悪くなり性能上不利になります。 例を図 2-8-1に示します。 連結演算を用いた大小比較が可能であった場合でも、インデクスの使用効率が悪く なり性能上不利になります。例を図 2-8-2に示します。 Point 複数列の組み合わせにて大小比較する場合は行値構成子を用いる CODE、SUBCODEの組み合わせにて大小比較する場合○
~ WHERE (CODE, SUBCODE) > (100, 50)×
~ WHERE CODE > 100 OR (CODE = 100 AND SUBCODE > 50) (100, 50)よりも大きいものを検 索する。行値構成子を使用する と、複数列インデクスで直接評 価ができ効率が良い。 図 2-8-1 行値構成子の使用例 その1 以下の複数列インデクスは定義済み X01(CODE, SUBCODE) インデクスを有効に使う記述© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-8-1 行値構成子の利用(2)
23
XDATE、XTIMEの組み合わせにて大小比較する場合
○
~ WHERE (XDATE, XTIME) > ('20070301', '223000')
×
~ WHERE XDATE || XTIME > '20070301223000'連結演算などのスカラ演算を含むと インデクスの使用効率が悪い。 図 2-8-2 行値構成子の使用例 その2 以下の複数列インデクスは定義済み X02(XDATE, XTIME) ('20070301', '223000')よりも大きいものを検索する。 行値構成子を使用すると、複数列インデクスで直接評価 ができ効率が良い。 インデクスを有効に使う記述
2-9 完全一致に
LIKEは用いない
LIKE述語にて完全一致の検索を行う場合は固定長文字列でもデータ長が等しいもの しか一致しない(空白を補完しない)ことも認識してください。例を図 2-9-1に示します。 Point 完全一致の検索の場合は、LIKE述語でなく =述語を用いる○
~ WHERE SNAME = 'ABCD' ;×
~ WHERE SNAME LIKE 'ABCD' ; 固定長文字列SNAMEの長さとLIKE述語 に指定した文字列の長さが不一致の場合、 検索できない。 図 2-9-1 LIKEの完全一致は用いない =述語の場合、列長に合わせて変数の 値に空白を補完するため、長さが異なっ ても検索できる。 列定義は以下 SNAME CHAR(30) インデクスを有効に使う記述© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-10
任意の複数条件を組み合わせた自由検索の注意
25 LIKEのパターン文字列を変数として、実行時に変数に完全一致の文字列または'%'を 与えることにより一つのSQLにて任意の複数条件を組み合わせた自由検索が実現可能 ですが、インデクスの使用効率が悪くなり性能劣化となるので、このような指定は避けて ください。このような場合は、条件ごとにそれぞれのSQLを記述したり、動的SQLを組み 立てたりして、UAPにて使用するSQLを選択してください。 例を図 2-10-1、 2-10-2に示します。 Point 任意の複数条件を組み合わせた検索で、LIKE述語を使用して検索条件に 汎用性を持たせない インデクスを有効に使う記述 検索を有効にしたい列を事前に判定し、条件に有効にしたい列だけを指定した SQLで、検索を行う。 SNAMEの条件とSCODEの条件のアドホックな検索において: SNAMEの条件だけを有効にしたい場合○
~ WHERE SNAME = :X1 ; SCODEの条件だけを有効にしたい場合○
~ WHERE SCODE = :X2 ; =述語として不要な条件(SCODEの条件) を指定しない。 なお、SQLオブジェクトキャッシュのヒット率 を上げるために定数でなく変数を用いる。 図 2-10-1 複数のLIKE条件を組み合せて使用しない その12-10-1
任意の複数条件を組み合わせた自由検索の注意
インデクスを有効に使う記述検索を有効にしたい列に定数を、有効にしない列に%を設定し、LIKEを使用した SQLを発行している。有効にしない列も検索対象となるため、インデクスの使用 効率が悪くなる。
×
~ WHERE SNAME LIKE :X1 AND SCODE LIKE :X2 ;SNAMEの条件だけを有効にしたい場合 X1 = 'ABCD' X2 = '%' SCODEの条件だけを有効にしたい場合 X1 = '%' X2 = '1234' 図 2-10-2 複数のLIKE条件を組み合せて使用しない その2
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-11
NOT(!=)のインデクスの使用上の注意
27 インデクスで範囲を絞り込めるように条件の指定ができるならば、NOT(!=)を指定しな いでください。NOT(!=)を使用すると、インデクスを使用した検索を行わないことが多い です。 インデクスを使用するためのNOT(!=)に関する例を図 2-11-1に示します。 Point インデクスを使用して範囲が絞り込めるならば、NOT(!=)は使用しない○
~ WHERE DNO > 0×
~ WHERE DNO != 0 DNOに負数がない場合。 図 2-11-1 インデクス定義列でのNOT(!=)の変形例 インデクスを有効に使う記述 インデクスを使用して範囲をあまり絞り込めないなど、インデクスを用いたくない場合に、 NOT(!=)を用いてください。2-12 インデクスソートキャンセル(1)
ORDER BY句の順序性は、インデクスを使用することでソート処理を行わずに保証できるため、性 能向上が期待できます。また、GROUP BY句に対しても、インデクスを使用しソート処理/ハッシュ 処理を行わずにグループ化できるため、性能向上が期待できます。これをインデクスソートキャンセ ルと呼びます。 インデクスソートキャンセルにするために、以下のすべての条件を満たすようにしてください。①ORDER BY句/GROUP BY句に指定する列のすべてが、同じ順序で一つのインデクスの第1構 成列から連続しているかまたは連続しない場合には、インデクス構成列の連続しない列に、=述 語(列=値指定)またはIS NULL条件列を探索条件に指定している。 ②ORDER BY句のASC/DESC指定と、インデクス定義時の構成列のASC/DESC指定が同じか、 まったく逆。(本項目はGROUP BYには該当しない) ③インデクスが複数のRDエリアに分割されていない(HiRDB/パラレルサーバの場合は、1つのサー バ(BES内)で複数のRDエリアに分割されていない)。
Point ORDER BY句、GROUP BY句は、インデクスを利用できるように工夫する
探索条件中にインデクス構成列に対する絞り込みがあるか、または選択式がインデクス構成列の みで構成されている場合は、よりインデクスソートキャンセルを適用できます。
<補足事項>
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-12-1 インデクスソートキャンセル(2)
29
インデクスが複数のRDエリアに分割されていない場合
○
SELECT ZSURYO, DNO FROM ZAIKOWHERE SNAME = 'A'
ORDER BY ZSURYO DESC, DNO ASC;
○
SELECT ZSURYO, DNO FROM ZAIKOORDER BY SNAME ASC, ZSURYO DESC, DNO ASC;
○
SELECT ZSURYO, DNO FROM ZAIKOORDER BY SNAME DESC, ZSURYO ASC, DNO DESC; =述語はインデクスの第1構成列を指定。 ORDER BYはインデクスの第2構成列 から連続して指定している。 図 2-12-1 インデクスソートキャンセルの例 インデクスは以下の複数列インデクス
X01(SNAME ASC, ZSURYO DESC, DNO ASC)
選択式はインデクス構成列のみ。 ORDER BY指定列がインデクスの 第1構成列から連続して指定する。 ASC/DESCがすべて逆。 インデクスを有効に使う記述 インデクスソートキャンセルとなる例を図 2-12-1に示します。 ORDER BY句、GROUP BY句の
2-12-2 インデクスソートキャンセル(3)
インデクスが複数のRDエリアに分割されていない場合
×
SELECT ZSURYO, DNOFROM ZAIKO
WHERE SNAME = 'A’
ORDER BY ZSURYO ASC, DNO ASC;
×
SELECT ZSURYO, DNOFROM ZAIKO
WHERE SNAME = 'A’
ORDER BY DNO ASC, ZSURYO ASC;
×
SELECT ZSURYO, DNOFROM ZAIKO
WHERE SNAME = 'A’ ORDER BY DNO ASC;
×
SELECT ZSURYO, DNOFROM ZAIKO
ORDER BY SNAME ASC, ZSURYO DESC, DNO ASC, COL ASC ;
ASC/DESCが一致しない。 ②の条件にあてはまらない例 図 2-12-2 インデクスソートキャンセルの不可の例 その1 ORDER BY指定順序とインデ クス構成列順が異なる。 ①の条件にあてはまらない例 ORDER BY指定列がインデク スの第1構成列から連続せず、 欠落列の=述語指定もない。 ①の条件にあてはまらない例 ORDER BY指定列にインデク スで定義されてない列がある。 ①の条件にあてはまらない例 インデクスを有効に使う記述 インデクスは以下の複数列インデクス X01(SNAME ASC, ZSURYO DESC, DNO ASC)
インデクスソートキャンセル不可となる例を図 2-12-2、2-12-3に示します。 ORDER BY句、GROUP BY句の
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
2-12-3 インデクスソートキャンセル(4)
31
一つのサーバ内でインデクスが複数のRDエリアに分割されている場合
×
SELECT SURYO, DNO FROM ZAIKOORDER BY SNAME ASC, ZSURYO DESC, DNO ASC; インデクスが複数のRDエリア に分割されている。 ③の条件にあてはまらない例 図 2-12-3 インデクスソートキャンセルの不可の例 その2 インデクスは、以下
X01(SNAME ASC, ZSURYO DESC, DNO ASC) IN(RDA1, RDA2, RDA3);
インデクスを有効に使う記述
2-13 集合関数
MAX/MINの引数の注意
ひとつのSQLに異なる列を引数とする集合関数MAX、 MINを同時に指定すると、 インデクスを使用せずMAX、 MINの値を求めるため性能が悪くなります。違う引数の MAX、 MINはSQLを分け、引数にインデクスの第1構成列を指定してください。
例を図 2-13-1に示します。
Point 一つのSQLに、異なる列を引数とするMAX、 MINを同時に指定しない
SELECT MAX(ZA.ZSURYO) FROM ZAIKO ZA;
○
SELECT MIN(ZA.DNO) FROM ZAIKO ZA;
×
SELECT MAX(ZA.ZSURYO), MIN(ZA.DNO)FROM ZAIKO ZA; 一つのSQLにて、MAXとMINの引数 に異なる列を指定している。 図 2-13-1 インデクスの構成列をMAX,MINの引数に指定した例 インデクスは、 X01(ZSURYO, DNO) X02(DNO) 異なる列のMAXとMINのSQL文を 分けて指定する。 なお、各列は第1構成列となるように インデクスを定義する。 インデクスを有効に使う記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
3.
副問合せに関する記述
33 副問合せは、SQLの構文ベースでアクセスパス(処理手順)がほぼ決まる ため、副問合せを使用する場合は書き方によって大きく性能が異なります。 よって、適切に使用するように心掛けてください。3-1 副問合せの使用方針
# 方針 メリット 1 ジョインで記述可能なSQLは副 問合せを使用せず、ジョインで 記述する。 検索順序、データの突合せ方法をHiRDB が最適化できるので、SQL構文をあまり考 えなくて良い。 2 FROM句の副問合せは使用しな い。 検索順序、データの突合せ方法、絞り込み のインデクスをHiRDBが最適化できるので、 SQL構文をあまり考えなくて良い。 3 IN副問合せ(=ANY副問合せ) とEXISTS副問合せは、絞り込み によって使い分ける。 絞り込みを伝播できるようになりデータの処 理量が削減できる。 4 IN副問合せ(=ANY副問合せ) と=副問合せは、副問合せの ヒット件数が1件かどうかで使い 分ける。 インデクスを効率よく使用できるようになり、 データの処理量が削減できる。 5 NOT IN副問合せ(<>ALL副問 合せ)はなるべく使用しない。 NOTを含むとデータ処理量が多くなるが、 NOT INは特に重いので避ける。 副問合せを使用する場合は、以下の順に考慮して使用すると良いです。 副問合せに関する記述© Hitachi, Ltd. 2013 , 2015. All rights reserved.
3-2 副問合せよりもジョインを使用する(1)
35 IN副問合せ、ANY副問合せ、ALL副問合せでは作業表を作成します。また、副問合せ だと表の検索順序が限られるため、最も効率の良い順序で表を検索することができず、 表の結合で記述したほうが処理の性能が向上することが多いです。IN副問合せ、=ANY 副問合せは、結合で記述できます。図 3-2-1、図 3-2-2に、副問合せを解消できる例を 示します。 Point 副問合せを用いないSQL文に変更可能な場合、なるべく副問合せを使用しない○
SELECT ZA.SNAME FROM JUTYU DE, ZAIKO ZAWHERE DE.DNO = ZA.DNO AND ZA.ZSURYO = 20 ;
×
SELECT ZA.SNAMEFROM ZAIKO ZA WHERE DNO IN (
SELECT DE.DNO
FROM JUTYU DE) AND ZA.ZSURYO = 20 ; 副問合せを使用すると、作業表 オーバヘッド、さらにインデクスが 使えなければ直積相当の負荷が かかる。 ZAIKO表を先に検索して絞り込みを 伝播させた方が良いが、JUTYU表 を絞り込まずに先に検索してしまう。 図 3-2-1 副問合せを使用しないSQL例 その1 副問合せを使用しないで、表結合 で実現。 (DE.DNOの値に重複がある場合 は注意が必要) 副問合せに関する記述
3-2-1 副問合せよりもジョインを使用する(2)
○
SELECT ZA.SNAME FROM JUTYU DE, ZAIKO ZAWHERE DE.DNO = ZA.DNO AND DE.TCODE = 'A' ;
×
SELECT ZA.SNAMEFROM ZAIKO ZA WHERE EXISTS ( SELECT *
FROM JUTYU DE
WHERE DE.DNO = ZA.DNO AND DE.TCODE = 'A') ; 外への参照あり副問合せでは、 外側問合せを先に検索する。 ゆえに、外側問合せにデータの 絞り込みが無ければ、表の全件 の突合せが実施され負荷が高い。 図 3-2-2 副問合せを使用しないSQL例 その2 副問合せを使用しないで、表結合 で実現。 (DE.DNOの値に重複がある場合 は注意が必要) 副問合せに関する記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
3-3
FROM句の副問合せの使用上の注意(1)
37 FROM句の副問合せを指定すると、内部導出表を作成することが多くなります。内部導 出表を作成した場合、以下のような点で性能が悪くなるため、FROM句の副問合せはな るべく用いないでください。例を図 3-3-1に示します。 内部導出表は、FROM句の副問合せ結果で作成する作業表であるため、作業表へ のI/Oが発生する。 内部導出表を作成すると、外側問合せに指定した探索条件は、FROM句の副問合せ 結果で作成する作業表の作成後に評価するため、インデクスが用いられない。 Point FROM句の副問合せはなるべく用いない○
SELECT B.SNAME FROM JUTYU A, ZAIKO BWHERE A.DNO = B.DNO AND A.TCODE = 'A' ;
×
SELECT B.SNAMEFROM (SELECT DNO, TCODE FROM JUTYU WHERE TCODE='A') A,
(SELECT DNO, SNAME FROM ZAIKO) B WHERE A.DNO = B.DNO ;
内部導出表を作成する。 図 3-3-1 FROM句に副問合せを使用しないSQL例 DNOにインデクスを定義し ていても使用しない。 DNOのインデクスを用いた ネストループジョインとなる。 副問合せに関する記述
3-3-1
FROM句の副問合せの使用上の注意(2)
×
SELECT P.* FROM TBL2 T2, (SELECT T1.* , VALUE(T1.C1S, T1.C1L, 0) C1 FROM TBL1 T1 ) PWHERE T2.TBL1ID = P.ID
AND P.C1 BETWEEN T2.C2 AND T2.C3 AND T2.TBL2ID = ? 図 3-3-2 FROM句の副問合せの書き換えでの性能向上例 FROM句の 副問合せ。
○
SELECT T1.* , VALUE(T1.C1S, T1.C1L, 0) C1 FROM TBL2 T2, TBL1 T1WHERE T2.TBL1ID = T1.ID
AND VALUE(T1.C1S, T1.C1L, 0) BETWEEN T2.C2 AND T2.C3 AND T2.TBL2ID = ? マージジョイン 作業表相手だと マージジョイン のみ。 TBL2ID = ?で絞り込 んだが絞り込みを伝 播できず性能劣化。 絞り込まれ ず全件検索 ネストループジョイン TBL2ID = ?で絞り込 んだ絞り込みを伝播。 実表の検索であれば、 結合条件のインデクス で絞り込んで検索。 TBL2 TBL1 TBL2 作業表 P TBL1 内部導出表 FROM句の副問合せの書き換えで性能向上した例を図 3-3-2に示します。 副問合せに関する記述 演算は展開 する
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
3-4
IN副問合せとEXISTSの使い分け
39 副問合せで記述する場合には、外への参照あり/なしによって、外側問合せと副問合せのどちらを 先に検索するかが変わります。外への参照ありは外側問合せを先に、外への参照なしは副問合せを 先に検索します。そのため、絞り込める問合せを先に検索するように、外への参照あり/なしを考え る必要があります。外への参照ありで記述する場合は、EXISTS述語の副問合せを使用してください。 外への参照なしで記述する場合は、IN述語の副問合せを使用してください。 例を図 3-4-1に示します。 Point 副問合せ内を絞り込める場合は、外への参照なしIN 副問合せを使用する 副問合せより外側問合せが絞り込める場合は、外への参照ありEXISTSを使用する ○ SELECT ZA.SNAME FROM ZAIKO ZA WHERE ZA.DNO IN (SELECT DE.DNO FROM JUTYU DE WHERE DE.TCODE = 'A') ;
○ SELECT ZA.SNAME FROM ZAIKO ZA WHERE EXISTS (
SELECT * FROM JUTYU DE WHERE DE.DNO = ZA.DNO) AND ZA.SNAME = 'A' ;
外への参照無しINの場合は、ZA.DNOに インデクスを定義して、副問合せから外側 問合せへ突き合わせる。 図 3-4-1 外への参照なしIN と、外への参照ありEXISTSの使い分け 副問合せ内が絞り込める場合は、 外への参照なしINにて、副問合せを 先に検索したほうが良い。 外側問合せが絞り込める場合は、 外への参照ありEXISTSにて、外側 問合せを先に検索したほうが良い。 DE.DNOにインデクスを定義して、外側 問合せから副問合せへ突き合わせる。 副問合せに関する記述
3-4-1
IN副問合せとEXISTSの使い分け(解説)
外への参照無し IN副問合せ 解説 外への参照有無により、先に検索する表が変わります。絞り込める表から検索で きるように、外への参照有無を使い分けます。 SELECT ZA.SNAME FROM ZAIKO ZA WHERE ZA.DNO IN ( SELECT DE.DNO FROM JUTYU DEWHERE DE.TCODE = 'A' ) ;
SELECT ZA.SNAME FROM ZAIKO ZA WHERE EXISTS ( SELECT *
FROM JUTYU DE
WHERE DE.DNO = ZA.DNO) AND ZA.SNAME = 'A' ;
ZAIKO JUTYU TCODE DNO 作業表 TCODE='A' ①副問合せ検索 ②外側問合せ検索 ZAIKO JUTYU DNO SNAME SNAME='A' ②副問合せ検索 ①外側問合せ検索 外への参照あり EXISTS副問合せ 副問合せに関する記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
3-5
IN副問合せと=副問合せの使い分け
41 Point 副問合せ内で1件しかヒットしない場合は、=副問合せを使用する○
SELECT ZA.SNAME FROM ZAIKO ZA WHERE ZA.DNO = (SELECT DE.DNO FROM JUTYU DE WHERE DE.TCODE = 'A' ) ;
×
SELECT ZA.SNAME FROM ZAIKO ZAWHERE ZA.DNO IN (
SELECT DE.DNO FROM JUTYU DE WHERE DE.TCODE = 'A' ) ; 副問合せが1件しかヒットしないときは、 INを使用せず=を使用する。 図 3-5-1 IN副問合せと=副問合せの使い分け 主キーであるので、1件 しかヒットしない。 ZA.DNOにインデクスを定義して、副問 合せから外側問合せへ突き合わせる。 JUTYU表の主キー:JUTYU(TCODE) 主キーを探索条件の=条件で指定する場合など、副問合せ結果が1件であることが自 明な場合は、IN副問合せ(=ANY副問合せも同様)を使用せず=副問合せを使用してくだ さい。=副問合せであれば、作業表の作成が不要なこととインデクスが自由に使用できる ことから、高速化できます。例を図 3-5-1に示します。 副問合せに関する記述
3-5-1
IN副問合せと=副問合せの使い分け(例)
図 3-5-2 IN副問合せと=副問合せの使い分け例
○
CREATE VIEW VIEW1 AS SELECT * FROM TBL1WHERE CCODE2 = (SELECT CCODE2 FROM TBL2
WHERE CNAME = 'NAME1') ;
×
CREATE VIEW VIEW1 AS SELECT * FROM TBL1WHERE CCODE2 IN (SELECT CCODE2 FROM TBL2
WHERE CNAME = 'NAME1') ; SELECT T3.CID AS C1_
・・・・・・
FROM TBL3 T3
INNER JOIN VIEW1 T1
ON T3.CCODE1 = T1.CCODE1 WHERE ( T3.CID = 'A01' ・・・・・ ) ; 主キー TBL3 TBL1 ネストループジョイン TBL1(CCODE1, CCODE2) のインデクス IN副問合せではネストループジョイン と同時に評価できず、探索範囲が 広がる。 インデクスで大量データ がヒットし性能劣化 ビュー表定義を=副問合せに変更して、 インデクスでの絞り込みができるようにした。 副問合せに関する記述 1件しかヒットしな いので=でよい 主キー
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
3-6
NOT INの代用としてのNOT EXISTSの使用
43 表の結合では表現できないものは、副問合せで記述します。副問合せを使用するときは、なるべく 外への参照を行わないようにするのが望ましいですが、外への参照を行わなくてもNOT INの場合 は内部的な直積が発生するため注意が必要です。処理性能の向上のためには、NOT INを用いるよ りも、外への参照をしてでもNOT EXISTSで置き換えた方が良いことが多いです。 基本的にはNOT INを使用しないようにしますが、下記例でSNAME='A'が絞り込めず、かつ副問合 せの検索行数が極端に少ない場合は、NOT INを用います。絞り込める場合はNOT EXISTSを使用 します。ただし、このような検索は一般的に処理負荷が高いのでなるべく避けるのが望ましいです。
Point なるべくNOT IN副問合せよりもNOT EXISTS副問合せを用いる
△
SELECT ZA.SNAME FROM ZAIKO ZAWHERE NOT EXISTS (
SELECT * FROM JUTYU DE WHERE DE.DNO = ZA.DNO) AND ZA.SNAME = 'A' ;
×
SELECT ZA.SNAME FROM ZAIKO ZAWHERE ZA.DNO NOT IN (
SELECT DE.DNO FROM JUTYU DE) AND ZA.SNAME = 'A' ;
副問合せ検索行数が少ない。
図 3-6-1 外への参照なしNOT INと、外への参照ありNOT EXISTSの使い分け
あまり絞り込めない場合。 小さく絞り込める場合。
4.
結合検索に関する記述
結合検索を使用する場合、書き方によっては処理負荷が高くなります。 処理負荷が高くならないようにするSQLコーディングについて示します。
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
4-1 表の結合(1)
45 表の結合で、処理負荷がかからないように、以下に示すように指定してください。 ①結合処理は、一般的に結合表数が増えるほど処理負荷が高くなるので、結合する表数 は少なくなるように工夫する。 ②表の結合は、ネストループジョインになるように設計する。あまり絞り込まないで結合を 行うことが必要な場合は、ハッシュジョインになるよう設計する。極力直積、マージジョ インにならないようにする。これらは、外結合(LEFT OUTER JOIN)にも該当する。 ③結合条件にはデータを絞り込めるように、=(等号)条件を指定する。 ④結合条件にスカラ演算等の演算を使用しないようにする。スカラ演算等は直積で処理 するため処理負荷が高くなる。 ⑤結合条件をOR論理演算しないようにする。OR論理演算すると直積で処理するため、 処理負荷が高くなる。 ⑥絞り込める条件の列と、対する表の結合条件の列にインデクスを定義する。 ⑦HiRDB/パラレルサーバで外結合を行う場合は、表の分割列を結合条件に指定するよ うにする。分割列を結合条件に指定しないと、ネストループジョインにならなくなる (HiRDB/シングルサーバ、およびHiRDB/パラレルサーバでも非分割表の場合は問題 ない)。 Point 表の結合は、次の点に注意してください。 ・ 不必要な表を結合しない ・ 結合条件は=(等号)条件を指定する ・ 結合条件にスカラ演算等の演算を使用しない ・ 結合条件をOR論理演算しない ・ HiRDB/パラレルサーバの外結合は、表の分割列を結合条件に指定するようにする 結合検索に関する記述4-1-1 表の結合(2)
結合条件をOR論理演算しないようにする例を図 4-1-1に示します。図 4-1-1に示す 方法が適用できない場合は、集合演算(UNION ALL)を用いる方法も検討する。
○
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.DNO = ZA.DNO AND (ZA.ZSURYO = 0
OR ZA.SNAME = 'A') ;
×
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE (JU.DNO = ZA.DNO AND ZA.ZSURYO = 0) OR (JU.DNO = ZA.DNO
AND ZA.SNAME = 'A') ; 結合条件をOR論理演算している。
図 4-1-1 直積を回避するために結合条件をORの外へ括り出す例
結合条件をOR論理演算の外へ括り出す。
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
4-2 外結合と内結合の混在
SQLでの注意(1)
47
Point 外結合と内結合を混在する場合には内結合はINNER JOIN構文で記述する かつ
探索条件にて最も絞り込める表をFROM句の最初に指定する
外結合と内結合の混在SQLで以下を指定した場合、データが効率的に絞り込めません。 FROMにカンマで区切り表を書き並べて結合するものと、LEFT OUTER JOINを混在 して指定した場合、LEFT OUTER JOINが先に処理される。
探索条件にて絞り込む表がLEFT OUTER JOINの外表以外であった場合、LEFT
OUTER JOINの外表を最初に検索するため、表のデータが絞り込めない状態でLEFT OUTER JOIN処理を行うので遅くなる。
上記の場合、内結合をINNER JOIN構文で記述し、探索条件にて絞り込む表をFROM句 の最初に指定します。絞り込んだ表を最初に検索し、少ない行数で結合処理を行うため高 速に処理できます。なお、INNER JOIN構文、LEFT OUTER JOIN構文では、FROM句の 指定順に結合します。
4-2-1 外結合と内結合の混在
SQLでの注意(2)
○
SELECT A.SURYO, B.SNAME, C.ZSURYO FROM JUTYU AINNER JOIN SYOHIN B
ON A.DNO = B.DNO LEFT OUTER JOIN ZAIKO C
ON B.DNO = C.DNO WHERE A.TCODE = 'A' ;
×
SELECT A.SURYO, B.SNAME, C.ZSURYO FROM JUTYU A ,SYOHIN B
LEFT OUTER JOIN ZAIKO C
ON B.DNO = C.DNO WHERE A.DNO = B.DNO
AND A.TCODE= 'A' ;
カンマで書き並べたJUTYU表は LEFT OUTER JOINの後に結合す る。
図 4-2-1 外結合と内結合の混在SQL例
LEFT OUTER JOINを先に処理す るためSYOHIN表を絞り込まない で最初に検索する。 INNER JOINにすることでFROM 句の記述順に結合する。よって、 最初にJUTYU表をTCODE='A'に て絞り込んで検索する。 外結合と内結合の混在SQLでデータを効率的に絞り込める例を図 4-2-1に示します。 結合検索に関する記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
4-3 外結合の使用上の注意
49
LEFT OUTER JOINの内表をWHERE句で絞り込むと(NULL述語は除く)、INNER JOINと同じ結 果になります。また、内表の条件をWHERE句に指定するとインデクスを使用出来ず、性能が悪くな ります。ゆえに、LEFT OUTER JOINの内表はON条件中で絞り込む必要があります。
例を図 4-3-1に示します。
Point LEFT OUTER JOINの内表はON条件中にて絞り込む
○
SELECT A.SNAME, B.SURYOFROM SYOHIN A LEFT OUTER JOIN JUTYU B ON A.DNO = B.DNO AND B.SURYO > 0 WHERE A.SNAME = 'A' ;
×
SELECT A.SNAME, B.SURYOFROM SYOHIN A LEFT OUTER JOIN JUTYU B ON A.DNO = B.DNO
WHERE A.SNAME = 'A' AND B.SURYO > 0 ; SELECT A.SNAME, B.SURYO
FROM SYOHIN A INNER JOIN JUTYU B ON A.DNO = B.DNO
WHERE A.SNAME = 'A' AND B.SURYO > 0 ;
内表をWHERE句で絞り込んで いるインデクスが使用されない。
図 4-3-1 LEFT OUTER JOIN 内表の絞り込み
INNER JOINと同じ結果になる。
等価なSQL
内表はON条件中にて絞り込む インデクスを使用する。
5.
表の分割に関する記述
分割表を使用することで性能向上が図れます。
© Hitachi, Ltd. 2013 , 2015. All rights reserved. 注文日 注文コード 商品コード 数量 ・・・ 2009-01-15 10111011 13425 100 ・ ・ 2010-03-28 12104567 92473 10 ・ ・ 2011-05-30 15012890 51247 50 ・ ・ 2012-07-06 17309684 10496 30 ・ ・ 2013-11-09 19109953 30929 150 ・ ・ 表の分割とは、一つの表を特定の列の値を基に複数の領域へ分割して格納し、管理する方 法です。分割した表を分割表といい、表を分割するときに指定した特定の列を分割キーとい います。SQL実行時は、探索条件に分割キーを指定すると対象となるデータが格納されて いる領域を判定し、必要な領域にのみアクセスします。 解説 アプリケーション側では、表の分割/非分割を 意識しなくてもアクセス可能ですが、分割キーに よるアクセス範囲と(パラレルサーバの)BES間 データ転送方法(5-1-1参照)を意識することで 性能を向上できます。 例) SELECT 商品コード, 数量 FROM 注文履歴表 WHERE 注文日 = '2011-04-01' ⇒ 検索対象のRDエリアはRDAREA3のみとなる。 表の分割の詳細につきましては、マニュアル 「システム導入・設計ガイド」ー「表の設計」を 参照してください。 表の分割に関する記述
5-1 表の分割とは
51 ◆注文日による表の分割の例 注文履歴表 '2010-01-01' ~'2010-12-31' RDAREA2 '2011-01-01' ~'2011-12-31' RDAREA3 '2012-01-01' ~'2012-12-31' RDAREA4 '2013-01-01'~ RDAREA5 ~'2009-12-31' RDAREA1 分割キー5-1-1
BES間データ転送方法(パラレルサーバ)
転送方法の条件 方式 転送元 転送先 パラレルサーバで表の結合する際、BES間のデータの転送をともないます。分割表の結合 では、表の分割キーを結合キーに含むことで、効率よく処理できます。 解説 表の分割に関する記述 サーバ サーバ サーバ サーバ 分割キーによって転送先サーバを決定 サーバ サーバ サーバ サーバ 常に同じ転送先のサーバにデータを転送 サーバ サーバ サーバ サーバ すべての転送先サーバにデータをコピー して転送 1対1転送 ( 1 TO 1 ) 下記の条件をすべて満たす場合。 ・データ転送先の表がキーレンジ 分割表またはハッシュ 分割表。 ・転送先の表の分割キーが結合 キーに含まれている。 下記の条件をすべて満たす場合。 ・両方の表の分割キー、分割の 種類、分割条件、格納先BESが 完全に一致している。 ・両方の表の分割キーが結合 キーに含まれている。 分割キーが、結合キーに含まれ ていない。 注:分割数が多く、転送元のヒット 件数が多いほど、通信および結 合オーバヘッドが大きくなり、性 能が悪くなる。 BES間データ 転送方法の種類 キーレンジ転送 (KEY RANGE) ハッシュ転送 (HASH) ブロードキャスト転送 (BROADCAST)© Hitachi, Ltd. 2013 , 2015. All rights reserved.
5-2 分割した表に対する検索
RDエリアの特定
53 HiRDBは、分割列に対する探索条件が指定された場合には、探索条件に合致する データが格納されたRDエリアを特定して他のRDエリアは検索しないようにすることで 性能向上しています。しかしながら、分割列に対する探索条件がスカラ演算された場合 には、該当表を格納した全RDエリアを検索するようになり性能向上できません。 例を図 5-2-1に示します。 Point 分割列に対する探索条件はスカラ演算しない○
SELECT DNO FROM ZAIKO WHERE SNAME = ? ;×
SELECT DNO FROM ZAIKOWHERE SNAME = CAST(? AS CHAR(5)) ;
×
SELECT DNOFROM ZAIKO
WHERE SUBSTR(SNAME,1,3) = 'ABC' ; 図 5-2-1 分割列に対する探索条件 ?パラメタにはCHAR(5)に変換 した値を入れCAST指定を行わ ない。 ZAIKO表の分割列がSNAMEであった場合 表の分割に関する記述
5-3 結合検索時の検索
RDエリアの特定
一方の表を表の分割列で絞り込み、もう一方の表と表の分割列同士で結合した場合で も、もう一方の表は全RDエリアにアクセスします。もう一方の表も冗長に表の分割列に対 する探索条件を指定することで、両表のアクセスするRDエリアを特定して絞り込むことが できるため性能向上します。例を図 5-3-1に示します。 Point 結合検索時には分割列に対する探索条件は省略しないで冗長に記述する○
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.DNO = ZA.DNO AND JU.DNO = 10 AND ZA.DNO = 10 ;
×
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.DNO = ZA.DNO AND JU.DNO = 10 ; ZAIKO表は定義した全RDエリアを 検索する可能性がある。 図 5-3-1 分割列に対する探索条件 ZA.DNO の条件を冗長に指定する ことで、ZAIKO表は一つのRDエリア だけを検索する。 JUTYU表、ZAIKO表ともにDNOが分割列の場合 表の分割に関する記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
5-4 結合検索での表の分割列と結合条件列の関係
55 HiRDB/パラレルサーバにおいて表の結合検索を行う場合、以下に示すように指定してく ださい。 =述語の結合条件に表の分割列を含むようにする。 各行の結合相手のデータがどのBES*に格納されているか特定できるため高速に 処理できる。 大量データを保持する表は、分割列を揃えるだけでなく、表の分割数と格納BESを 揃える。 結合条件に表の分割列を含まない場合は、以下のような性能低下を招きます。 各行の結合相手のデータがどのBESに格納されているかを特定できないため一つ の行に対する結合処理を結合相手の表を格納した全BESコピー転送(BROAD CASTと呼ぶ)して実行するようになるので、パラレルの効果が得られず分割損が起 きる。 LEFT OUTER JOINの場合は、外表を全行返すというSQLの仕様上、BROAD CASTが行えなくなり、両方の表の結合列での再配置を行うのでBES間のデータ 転送量が増える。さらに両方の表の再配置を行うと結合列でのインデクス検索が行 えないのでネストループジョイン以外の結合方式となり性能低下を招く。
例を図 5-4-1に示します。
Point 結合検索時に表の分割列で結合できるように表を設計する
特に、LEFT OUTER JOINの場合は内表の分割列で結合できるように表を設計する
表の分割に関する記述
* DBアクセスサーバ(Back End Server)。HiRDB/パラレルサーバの構成要素の一つです。 DBへのアクセスや排他制御を実行します。
5-4-1 結合検索での表の分割列と結合条件列の関係
◎
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.DNO = ZA.DNO AND JU.CNO = 10 ;
○
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.CNO = ZA.DNO AND JU.CNO = 10 ;
×
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.DNO = ZA.CNO AND JU.CNO = 10 ;
×
SELECT ZA.NAMEFROM JUTYU JU
LEFT OUTER JOIN ZAIKO ZA ON JU.DNO = ZA.CNO WHERE JU.CNO = 10 ; 転送先の表の結合列に分割列を含まな い。 ⇒JUTYU表データのBROAD CAST 転送が発生し、負荷が高くなる。 図 5-4-1 分割列に対する探索条件 外結合の転送先の表の結合列に分割 列を含まない。 ⇒マージジョインとなり、両表のデータ 転送、ZAIKO表の全件検索、作業表 作成、ソート処理が発生し、負荷が 高くなる。 転送先の表の結合列に分割列を含む。 ⇒JUTYU表のデータをZAIKO表の分割 に合わせてキーレンジ転送、または ハッシュ転送し効率が良い。 分割列同士で結合する。(さらに表の分 割方法が同じなら) ⇒1TO1転送となり最も処理効率が良い 表の分割に関する記述 JUTYU表、ZAIKO表ともにDNOが分割列で、 ZAIKO表のDNOとCNOにインデクスが定義されている場合 <パラレル限定>
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
6.
DBの件数を考慮した記述
57 DBアクセス性能は、検索結果件数および検索中(SQL実行中)にアクセス するデータ件数に大きく依存します。この場合のSQLコーディングについて示 します。6-1 表の件数の取得
表の件数を求めるときは、以下を指定してください。
COUNT(*)を使う。このとき可能な限りWITHOUT LOCK NOWAITを指定する。 条件式にはインデクスの定義された列を指定する。 例を図 6-1-1に示します。 条件式に指定した列がインデクスの第一構成列でない場合、性能が悪くなることがありま す。 Point 表の件数を求めるとき、COUNT(*)を使用すること
○
SELECT COUNT(*) FROM ZAIKO WHERE ZSURYO > 10 WITHOUT LOCK NOWAIT ;件数の取得には
COUNT(*)を使用する。
ZSURYO にインデクスを定義する。
図 6-1-1 件数の取得のSQL例
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
6-2 データの存在有無の取得
59
データの存在チェックを行うときの留意事項を以下に記載します。 LIMIT 1を指定して、1件見つけたら処理を打ち切るようにする。 可能な限りWITHOUT LOCK NOWAITを指定する。
条件式と選択式にはインデクスの定義された列を指定する。 ORDER BY は作業表を作成することがあるため、指定しない。 例を図 6-2-1に示します。 Point データの存在チェックにはLIMITを使用すること
○
SELECT ZA.ZSURYO FROM ZAIKO ZA WHERE ZA.ZSURYO = 0 LIMIT 1WITHOUT LOCK NOWAIT ;
ZSURYO にインデクスを定義する。
図 6-2-1 存在チェックのSQL例
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
6-3 NOT
(!=)の使用上の注意
60 NOT(!=)を使用した条件に対して、HiRDBは、あまり絞り込めないと判断し結合方法、 結合順序を決定します。取り得る値が1か0だけのフラグなど2値しか持たない列は、 条件に指定してもあまり絞り込めないので、NOT(!=)を使用して条件を指定することで、 HiRDBは、絞り込めないことを認識できます。3値以上持つがあまり絞り込めない場合は、 NOT INを用いても良いです。例を図 6-3-1に示します。 Point 絞り込めないとわかっている条件はNOT(!=)を指定する○
~ FROM JUTYU JU,ZAIKO ZA WHERE JU.DNO = ZA.DNO AND JU.FLAG != 1 AND ZA.ZSURYO = 20×
~ FROM JUTYU JU,ZAIKO ZAWHERE JU.DNO = ZA.DNO AND JU.FLAG = 0 AND ZA.ZSURYO = 20 JU.FLAGは、1か0であり、かつ ZA.ZSURYO=20が絞り込める場合 図 6-3-1 結合を伴うSQLでのNOT使用例 JU.FLAG != 1とすることで、 ZA.ZSURYO = 20のインデクスを 確実に使用し、ZAからJUへのネスト ループジョインにて高速に処理する。 DBの件数を考慮した記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
6-4 集合演算の使用上の注意(1)
61 UNION/UNION ALLなどの集合演算を使用したとき、集合演算で区切られた問合せ指 定(SELECT文)は、別々に表アクセスします。また、集合演算を使用すると、作業表を作 成することが多いです(UNION ALLのみの集合演算であれば集合演算のための作業表 は作成しない)。そのため、集合演算を用いないSQL文にすると処理性能が向上すること が多いです。 図 6-4-1に、単純な場合の例を示します。 Point 各問合せ指定の述語に指定する値だけが異なるような場合は、集合演算を 使用しないようにする○
SELECT SNAME FROM ZAIKO WHERE ZSURYO IN (10, 20) ;×
SELECT SNAME FROM ZAIKO WHERE ZSURYO = 10 UNION SELECT SNAME FROM ZAIKO WHERE ZSURYO = 20 ; =条件の値だけが異なる場合は、 UNION等の集合演算を使用しない。 図 6-4-1 集合演算を使用しないSQL文の例 IN述語を使用することにより集合演 算を使用しない。 DBの件数を考慮した記述6-4-1 集合演算の使用上の注意(2)
結合条件をOR論理演算すると、HiRDBは、直積で処理します。直積では、全データの 突合せ処理を伴うため、集合演算に変形し、OR論理演算を不要とすることで直積処理が 無くなり処理性能が向上することが多いです。 例を図 6-4-2、6-4-3に示します。 Point 結合を伴うSQLで、結合条件をOR論理演算する必要がある場合は、集合演算 を使用する○
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.DNO = ZA.DNO UNION ALL
SELECT ZA.NAME
FROM JUTYU JU, ZAIKO ZA WHERE JU.ZNO = ZA.ZNO AND JU.DNO != ZA.DNO ;
×
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE (JU.DNO = ZA.DNO OR JU.ZNO = ZA.ZNO) ; DISTINCT無し。結合条件をOR論理 演算している。 図 6-4-2 直積を回避するためにUNION ALLを利用するSQL文の例 UNION ALLを利用し、結合条件 のORをなくす。 UNION ALLで処理できるように 工夫する。 DBの件数を考慮した記述
© Hitachi, Ltd. 2013 , 2015. All rights reserved.
6-4-2 集合演算の使用上の注意(3)
63
○
SELECT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.TCODE = 'A01' AND JU.DNO = ZA.DNO
UNION
SELECT ZA.NAME
FROM JUTYU JU, ZAIKO ZA WHERE JU.TCODE = 'A01'
AND JU.SURYO = ZA.ZSURYO ;
×
SELECT DISTINCT ZA.NAMEFROM JUTYU JU, ZAIKO ZA WHERE JU.TCODE = 'A01' AND (JU.DNO = ZA.DNO
OR JU.SURYO = ZA.ZSURYO) ; DISTINCT指定有り。 結合条件をOR論理演算している。 図 6-4-3 直積を回避するためにUNIONを利用するSQL文の例 UNIONを利用し、結合条件のOR をなくす。 UNIONでは重複を排除するため、 DISTINCTの指定が不要。 DBの件数を考慮した記述