LoginSignup
15
18

More than 3 years have passed since last update.

ちょっと細かいSQL論

Last updated at Posted at 2017-08-11

SQL実戦入門を読んだので、ポイントをいくつかまとめておく。

SQLの発行順序

  1. ジョイン処理
  2. Whereによる絞込
  3. GroupByによるグループ化
  4. selectによる計算と集約
  5. havingによる絞込
  6. ウインドウ関数の計算
  7. Orderbyによる並び替え
  8. Limitによる絞込

Group by はホールケーキのカット

 集約とカットを行う。※集約を行わないのがpartition by
 つまり、見方を変えるとその基準がない下記のようなSQLは理論的には成立する。
 select count(*) from address group by ()
 ※ 結果的に省略可なだけ
 GroupByを利用する際は、結合との順番に注意する。

  select C.co_id ,C.district,sum(emp_nbr) as sum_emp
  from Companies C inner join Shops S On C.co_id = S.co_id
  where main_flg = 'U'
  group by C.co_id

 よりも

  select C.co_id,C.districe,sum_emp
  from Copmanies C innder join
   ( select co_id,sum(emp_nbr) as sum_emp
    from Shops S where main_flg = 'U' group by co_id ) CSUM
  where C.co_id = CSUM.co_id

のほうが、結合対象となる行が少なくなるためパフォーマンスが出やすい 。

ビューはselect文をDBに保存しているだけ

 つまり、ビュー発行とは、内部的には2段階SQLを実行している。
 たとえば、vというビューがあったとして
 select * from v としても、
 内部的には下記のように展開されて実行されている。↓
 select * from ( select * from viewmoto) as vv
 よくある多段ビューはさらにその入れ子になるため、パフォーマンスがさらに悪くなる。

union句に注意

 SQLとしては1つだが、実際には複数回テーブルへのアクセスが行われている。
 case式で代用できないか検討すること。
 
  select item_name,year,price_a
 from Items
 where year <= 2001
 union
 select item_name,year,price_b
 from Items
 where year > 2001

 よりも

 select item_name,year,
   case when year <= 2001 then price_a
      when year > 2001 then price_b
 from Items

 のほうが効率は良い場合がある。

アプリ側から何度も小さいSQL vs 少々小難しいSQLで一発

 一般的にはアプリ側からループで小さいSQLを繰り返し実行し、
 小難しい処理はプログラムで対処する。
 ただ、SQLで一発による対応は下記メリットがあるので、比較検討の上実装する。
 ・チューニングポテンシャルが高い(複雑であればあるほど)
 ・SQL実行時のオーバーヘッドが低い(繰り返し発行されないため)
 ・DBの進化によって受けられる恩恵が高い(エンジンの進化によるもの)

サブクエリが遅い理由

・一時的に結果をメモリに保持するためオーバーヘッドが生じる
・実行時のみの発行のため、インデックスや制約の情報がなく、DBエンジンによる最適化が受けられない
・相関サブクエリは結果行数分、実行されるためさらにパフォーマンスが悪い

パフォーマンス向上の為のよくある施策について

・データマートの作成
 ⇒ 予め必要データを保持しておくため計算処理を省略できるが、
   データの鮮度を保つために定期的な同期が必要になる。
- データマートとしては、マテビュー/テンポラリテーブル/ビューの3種類がある

データ鮮度 パフォーマンス データ保持 データの格納領域
ビュー しない -
マテリアライズド・ビュー する データファイル
テンポラリテーブル 一時的 一時ファイル

・検索画面内におけるUI改善
 ⇒ 検索時における項目間の制約(他項目の条件も必須にするなど)
   要はインデックスを効かせやすいようにUI設計する。

・インデックスオンリースキャンの活用
 ⇒ select句やwhere句の項目をまとめたカバリングインデックスを作成することで、
   テーブルへのアクセスを省略する。(レコード志向ではなくカラム志向へ)

行間比較の際に参考になるSQL書き換え

過去の直近を求める、みたいなケースでは行と行を比較する必要がある。
◆相関サブクエリ

  select LS0.sample_date as cur_date,
   (
    select Max(sample_date) from LoadSample LS1
    where LS1.sample_date < LS0.samole_date
   ) as latest
  from LoadSample LS0

◆自己結合

  select LS0.sample_date as cur_date,
     MAX(LS1.sample_date) as latest
  from LoadSample LS0
    left join LoadSample LS1 on LS1.sample_date < LS0.sample_date
  group by LS0.sample_date

いずれも考え方は同じで、カレント(LS0)よりも小さい集合であるLS1から最大の日付を取得する。
※ちなみにウインドウ関数が使えるDBは、結合コストを抑えられる為ウインドウ関数を使うべし。

インデックスが使われない時にクイックチェック5選

  1. その条件ではそもそもそんなに絞り込めない 例)男/女、Yes/No といったもの
  2. 中間一致、後方一致を使っている 例) column like %aaaa%
  3. 索引列で演算している 例) column * 0.1 > 0.3 や length(column) > 3
  4. is nullを使っている。インデックス内にはNULLが存在しないため
  5. 否定型を使っている。 例)column <> 1 や column not in (3) など
15
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
18