LoginSignup
0
0

More than 1 year has passed since last update.

SQLチューニングでの確認事項

Posted at

チューニングの際の確認用と、無自覚にボトルネックを生み出さないよう、自戒のため記録しておく。

検索の効率はどうか

同じ結果が得られるのに、効率の悪い検索をしている箇所を撲滅する。
無駄にテーブルを見る回数を減らすこと。

サブクエリ用いるとき、IN,EXISTS(もしくはJOIN)を適切に使えているか

ただし最近のDBでは処理時間が改善されあまり差がなくなっているので、あまり変わらないことが多い。
また、INの方がコードのわかりやすさは勝るので、速度が変わらなければINでもOK。

INを使う場合

絞り込むテーブルの行数が、サブクエリで絞り込まれるレコード数より多い場合

/* table1 > table2 */
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2;)
# table2からレコードを取得してループを回して、table1と紐付ける
# table1はインデックスが効くので、データが多くても良い

EXISTSを使う場合

絞り込むテーブルの行数が、サブクエリで絞り込まれるレコード数より小さい場合

/* table1 < table2 */
SELECT * FROM table1 WHERE EXISTS (SELECT id FROM table2 WHERE table2.id = table1.id);
# table1からレコードを取得してループを回して、table2と紐付ける

※ もし結合キー(上記例ではid)にインデックスがはられていれば、tableBの中身を見にいかず、インデックスだけ見るので、JOINの方が速いこともある。

ソートを回避できているか

ソートがメモリ上で行われるならまだいいが、ストレージが使われるようになると急激に遅くなる。
実行前にWHEREとかで絞り込み、早い段階でデータ量を減らすこと。
もしくは表示件数を減らすとかするのもあり。

DISTINCTEXISTSで代用できないか

DISTINCTもソートを行うため、EXISTSに書き換えることでソートを回避できる。

/* 遅い */
SELECT DISTINCT customer_id
FROM customer
INNER JOIN company
ON company_id = company_id

/* 速い */
SELECT customer_id
FROM customer
WHERE  EXIATS (SELECT * FROM company WHERE company_id = company_d);

HAVINGWHEREで代用できないか

HAVINGは絞り込んだ結果に対して実行されるので、そうではなくWHEREで絞り込んでからソートするべき。

中間テーブルを無駄に作っていないか

  1. 集約した結果に対する条件は、中間テーブルを作らずHAVING句を活用する
  2. 集約と結合を同時に行う場合は、結合を先に行う

SQLの実行回数を減らせないか

実行ごとにサーバー間で通信が発生してしまうので、一回で実行した方が速いことが多い
ループの中で回してるSQLがたまにあるので、ループの外に出してあげる

インデックスを活用できているか

MySQLのインデックスによるチューニング(備忘録)

どうしようもなければ

  1. あえてカラムを増やし(非正規化し)、結合が発生しないようにする。(テーブルのデータ量が増えるのでケースバイケース)
  2. リアルタイムで実行計画が必要ない場合、夜間に実行計画を格納し、集計結果を別テーブルに格納する。
  3. 重いSQLはユーザーが使用しない時間に実行する。
  4. LIMITをつけて実行する。表示する件数を絞る。
0
0
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
0
0