SQLチューニング

SQLのチューニングをする際に、チェックする観点を掲載します。
最低限、これだけはチェックして欲しい内容です。
これらをチェックするには、人・工数・決断を必要とします。
開発メンバーの士気は下がり、場合によってはプライドすらも
傷つけます。
時間が無いのに、新たな作業を言い渡される訳ですから・・・
だ・か・ら、納期ギリギリでは「つらい」のです。
※しかし、港は無表情で作業の依頼を指示します。
 (まぁ、殴られたり、刺されたりした事は無いので・・・)

どうぞ参考にして下さい。

【チェック内容】

01.サブクエリを引数に取る場合、IN述語よりもEXISTS述語を
  使っているか

  SELECT name
  FROM Personnel
  WHERE birthday IN (SELECT birthday FROM Celebrities);
        ▼
  SELECT P.name
  FROM Personnel AS P
  WHERE EXISTS
    (SELECT * FROM Clelebrities AS C
           WHERE P.birthday = C.birthday);

02.IN述語やCASEの引数リストの順序を考慮しているか?
  (最もありそうなキーを左から記述)

  SELECT * FROM 住所 WHERE prefecture
               IN ('東京', '大阪', '鳥取', '徳島');
  ※IN は、左から右へ引数を評価し、見つかった時点で
   true を返しそれより後の引数は見ない

03.EXISTS述語のサブクエリ内では、SELECT * を使っているか?

  SELECT …. WHERE EXISTS (SELECT * FROM …)
  ※オプティマイザにどの列を使うのか選択を委ねる

04.3つ以上のテーブルを結合させる時は冗長な結合条件を
  記述しているか

  SELECT *
  FROM Table1 a, Table2 b, Table3 c
  WHERE a.common = b.common
    AND b.common = c.common
    AND c.common = a.common;
  ※テーブルサイズはオプティマイザに判断を任せる

05.行数を数えるときはCOUNT(*)よりもCOUNT(列名)を
  使っているか

 ※但し、列名にインデックスが張られている事が条件!

06.WHERE句の抽出条件は、最も制限の強いもの
  (件数を絞れるもの)から並べているか

 ※WHERE句で絞り込む際に、抽出行が少ない方が効率が良い

07.WHERE句の抽出条件条件指定には件数の少ない表を指定する
  empが2,000万件、dept表が20件とする
  (NG) SELECT * FROM emp e,dept d
        WHERE e.DEPTNO = d.DEPTNO
          AND e.DEPTNO = 40;
  (OK) SELECT * FROM emp e,dept d
        WHERE e.DEPTNO = d.DEPTNO
          AND d.DEPTNO = 40;

08.UNIONを記述している場合、UNION ALLを使っているか
 (重複を気にしなくてよい場合、または重複が発生しないことが
 事前に明らかな場合)UNIONは複数の集合をマージしますので、
 その際にソート処理が内部で発生します。

09.インデックスが使用される構文になっているか
(01)索引列に演算を行なっている
   (NG) SELECT * FROM SomeTable WHERE col_1 * 1.1 > 100
   (OK) SELECT * FROM SomeTable WHERE col_1 > 100/1.1

(02)IS NULL 述語を使っている
   SELECT * FROM SomeTable WHERE col_1 IS NULL;
   ※IndexデータにNULLは存在しない

(03)索引列に対してSQL関数を適用している
   SELECT * FROM SomeTable WHERE SUBSTR(col_1, 1, 1) = 'a';
   ※Indexに存在するデータは、あくまでもCol_1のデータ

(04)否定形を用いている
   <>やNOT INは、インデックスが効かない

(05)ORを用いている
   Or は INへ書き換える。INならば、インデックスが効く
   (NG) Where Col1 = 1 or Col_1 = 3
   (OK) WHERE Col_1 IN ( 1,3 )

(06)後方一致、または中間一致のLIKE述語を使用していないか
   Likeは前方一致であるとインデックスが効く
   (OK) "AAA%"  
   (NG) "%ZZZ" , "%ZZZ%" 

(06)暗黙の型変換を行なっていないか
   Col_1がchar型の場合
   (OK) SELECT * FROM SomeTable
                  WHERE col_1 = '10';               
   (OK) SELECT * FROM SomeTable
                  WHERE col_1 = CAST(10, AS CHAR(2));  
   (NG) SELECT * FROM SomeTable
                  WHERE col_1 = 10

   ※暗黙の型変換は、オーバーヘッドが増えるしインデックスも効かない

(07)複合インデックスの場合に、列の順序を間違えていないか
   col_1, col_2, col_3 に対して複合インデックスが張られているとします。
   その場合、条件指定の順番が重要となる

 (OK)SELECT * FROM SomeTable
          WHERE col_1 = 10 AND col_2 = 100 AND col_3 = 500;
 (OK)SELECT * FROM SomeTable
          WHERE col_1 = 10 AND col_2 = 100 ;
 (NG) SELECT * FROM SomeTable
          WHERE col_1 = 10 AND col_3 = 500 ;
 (NG) SELECT * FROM SomeTable
          WHERE col_2 = 100 AND col_3 = 500 ;
 (NG) SELECT * FROM SomeTable
          WHERE col_2 = 100 AND col_1 = 10 ;

(08)範囲検索時は上限・下限を指定する
   ※上限・下限を指定できる場合は、双方を指定する事で
    インデックスの無駄な読込みを回避できる。
    (データ件数が多い場合、特に有効)

   (NG)SELECT a FROM emp WHERE a <= 2800;
   (OK)SELECT a FROM emp WHERE a BETWEEN 0 AND 2800;

(09)条件指定はリレーションシップに従う
  (NG) SELECT * FROM emp e,dept d,no n
           WHERE e.DEPTNO = d.DEPTNO
             AND e.DEPTNO = n.DEPTNO;
  (OK) SELECT * FROM emp e,dept d,no n
           WHERE e.DEPTNO = d.DEPTNO
             AND d.DEPTNO = n.DEPTNO
             AND n.DEPTNO = e.DEPTNO;

10.SELECTの時、ワイルドカードは使っていないか
  ※列名を指定する

11.表に別名をつけているか
  解析時にどの列がどのテーブルに属するかの判定を省略できる。
  特に複数のテーブルを使う SQL で効果的だが、
  単純な SQL でも大量に発行する場合は有効です。
  (NG) SELECT col_1, col2 FROM SomeTable ;
  (OK) SELECT S.col_1, S.col2 FROM SomeTable S ;

コメント

このブログの人気の投稿

ニュースリーダを使おう!

方向音痴必見!!