ClubDB2、SQLパフォーマンス改善にいってきた

第152回 実例から学ぶ! DB2のSQLパフォーマンス改善MacBookDB2で試しながらと思ったけど、
db2expllnコマンドの引数指定がやたらめったら
多くていきなり挫折...
db2exfmtコマンドの方を試してみよう。
どのみちこっちの方が細かく実行計画が見られるみたい。

まずは EXPLAIN のためのテーブルを作成する。
$HOME/sqllib/misc/EXPLAIN.DDLにCREATE文がある。
とりあえず MacBookDB2 で以下のコマンドを実行。

$ db2 -tf EXPLAIN.DDL

The SQL command completed successfully.
が大量に表示されて、なんとなく成功したかな。
OSユーザーが既にDB2管理者なのでこの辺はさすが簡単ですね。
続けてコマンドラインで、SQLの実行計画を収集。

$ db2 set current explain mode explain
$ db2 select \* from DFEXDB.MEMBER where MEMBER_NAME like ?
$ db2 set current explain mode no

コマンドライン経由なのでエスケープがちょっと必要ですね。
ここでは、アスタリスク "*" をバックスラッシュでエスケープ。
そして、そのSQLの実行計画をテキストファイルに出力!

$ db2exfmt -d DFEXDB -1 -o explain-output.txt

でたー
Access Plan:
                    • -
Total Cost: 3.78956 Query Degree: 1 Rows RETURN ( 1) Cost I/O | 0.5 FETCH ( 2) 3.78956 0.5 /----+---\ 0.5 5 IXSCAN TABLE: DFEXDB ( 3) MEMBER 0.00807303 Q1 0 | 5 INDEX: DFEXDB IX_MEMBER_MEMBER_NAME Q1
テキストで頑張ってるのがキュンっときますね。

バインド変数とリテラルとの挙動の違い、
分散統計、ジャンプスキャンなど、
色々な要素を学ぶことができました。

実例を題材にして仕組みを説明してもらえたので、
とてもわかりやすかったですね。これはよかった。

しかしながら、DB2に慣れてないからでしょうか、
ホスト変数、パラメーターマーカー、述部とか、
聞き慣れない言葉がたくさんだったのでした(^^
とある方の質問が印象的でした、
遅いSQLがあって、インデックスアドバイザー(!?)が
何も言ってくれない、どうすればいい?と。

SQLのパフォーマンスチューニングって、
現場で色々と見てきたり、自分も携わったりしましたが、
半分以上は「SQLというかなんというか」という問題が
実は多かったです。

というか、無駄なデータを取り過ぎでしょ
というか、ぐるぐる回し過ぎでしょ
というか、SQLがまわりくどいでしょ
というか、やり方変えればその処理いらないでしょ
というか、そもそもその業務(仕様)あんまり意味なくない?

などなど

インデックスを付けたり書き方調整したり統計情報が...
っていう「いかにもSQLチューニング」まで辿り着かないことって、
意外に多いのです。

ふと思ったのは、特に大規模・大組織のシステムだと、
SQLのチューニングをする人が、アプリの実装やその仕組み、
ましてや業務とかまで精通しているかといったら、
必ずしもそうではないかもしれないなぁと。
精通してるかどうかっていうより、そこに口出しできる立場や
環境があるかどうかってところが大きいかな。
「とにかくこのSQLが遅いのでなんとかして」って頼まれる。
まあそれはそれで職人って感じでかっこいい面もあるけど、
ケースによっては不毛な依頼が来たりもするんだろうなぁと。

実際に見たことのあるケース。
「業務的にはどうでもよかったんだけど、まあ決めでこの並び順で」
ってノリで決められたソート仕様でめっちゃSQL大変なことになって、
パフォーマンスに四苦八苦してるパターンを見たことがあります。
それと似たようなことがわりとあります。
仕様決めた人とプログラミングする人が距離が遠くてお話にならない。

さらに多いのは、
プログラマーのアプリケーション部分の実装がへんてこりんで、
SQLにしわ寄せが来ちゃってるとかで、SQLをどうのこうのする前に、
ロジック部分の組み立てを整理整頓すべきでしょって。
SQL自体も、基点テーブルがいきなり間違ってるとかで、
つじつま合わせ的な distinct や join があったりとか。

自分は、アプリ側に距離が近い立場のことの方が多いので、
パフォーマンス相談されたら、まずはそこから分析し始めます。
(それはもうソースコード追っかけますよー、じっくりね)
ある意味、SQLを速くするのは最後のフェーズと言えるかも。
ただ逆に言うと、だいたいそうやって解決しちゃうから、
じっくりコアな仕組みまで追ったSQLチューニングの経験を
なかなか得ることができないので、こういう勉強会で学びたいと。

「SQLチューニングと思ったら、そもそも論で解決事例」
なんてテーマのセッションやったらおもしろいかな(^^
(そういうネタ整理やっておこうかなぁ...)

とはいえ、最後の砦のSQLチューニング、
DBMSのコアな仕組みまで考慮にいれたチューニング、
これはこれでプロフェッショナルなスキルだなぁと。
正直、「片手間ではなかなか体得できない」ですよね。
SQLチューニングに多く携わる仕事や立場でなければ、
自主トレするしかないですが、これまたDBMSごとに
仕組みが違うから、一つのDBMSになかなか絞れない。

ぶっちゃけ、ついていくの大変だったのですが、
(特にインフラ的な話が入ってきちゃうわームズかしぃーって)
でも色々なことを考えるきっかけになって、
こうやってブログを書くきっかけを与えられたってことは、
学ぶことがあったという証拠なので、ClubDB2に感謝感謝です。
optimize for N rows

これが気になるぜぇー
取得件数が決定してるなら(小さい件数であれば)、
その件数をオプティマイザに教えてあげることで、

(ClubDB2資料引用)
o 一時表の生成やSORT、ハッシュ結合など控える
o 外部表の件数や検索述部のフィルターファクターが
 大きい場合にも索引スキャンを選択しやすい

とのこと。
fetch first N rows と合わせると良いとのこと。
(fetch first したら必ず optimize for も一緒にみたいな)

しかしながら、事例のSQLは order by がなかったけど、
先頭のn件を取得するようなときって、必ず order by が
仕様的にもくっ付いてくるものだけど、ソートしても有効かな...
(ソートカラムもインデックスに含まれてればOKかなぁ...)

とにもかくにも気になったのがとにかくこれ。
ページング検索のときの row_number() over() と併用しても、
効果があるのか?もしくは、効果があるパターンが存在するか?
講師の方に質問してみましたが、やったことないのでなんともだが、
効果ありそうですねとのこと。

勘の良いDBFluteユーザであれば、
DBFluteが何を企んでるか想像が付くかもですね。

DBFluteがさらに現場フィットなものとして発展するためにも、
フィットネタを追い求め駆け回っていきたいですね。
ある意味、DBFluteのビジネスチャンスを探す旅と言えるかも。