Edited at

SELECT文の評価順序の話


はじめに

この投稿はアイスタイル Advent Calendar 2015の25日目の記事です。

最終日の記事になりますが、今回もDBAの@toshifusaが、RDBMS関連の話題を、地味に淡々と書かせていただきます。


SELECT文とは

SQLの構文のうち、データを取得する文がSELECT文になります。

最近はORMがSQLを生成してくれるため、素でSQLを書く機会が減ってきているかと思いますが、ORMのSQL生成は完璧ではありません。

必ずしも効率の良いSQLを生成する訳でも、自動的に必要なインデックスを作成してくれる訳でもありません。

RDBMSをブラックボックスにせず、何をやっているのかを理解して、ORMと付き合っていくのが正しい態度ではないかと思います。


こんな疑問がわいた経験ないですか?


  • LIMITで出力件数を数件に制限しているのに、なんでこのクエリは遅いんだろう

  • ASで別名を定義しているのに、なぜWHEREに書くとエラーになるんだろう

  • JOINのONで条件指定するのと、WHEREで条件指定するのはどちらの方が速いんだろう

それらは、SELECT文の評価順序が分かると納得がいくと思います。


SELECT文の評価順序


  1. FROM

  2. ON

  3. JOIN

  4. WHERE

  5. GROUP BY

  6. HAVING

  7. SELECT

  8. DISTINCT

  9. ORDER BY

  10. TOP(LIMIT)


LIMITで出力件数を数件に制限しているのに、なんでこのクエリは遅いんだろう

LIMIT(TOP)が処理されるのは、最後の最後です。

全ての処理が終わった結果セットからの出力件数を絞っているだけなので、LIMIT(TOP)が速く動作するのは以下の条件の場合になります。


  1. ORDER BYの指定が無い

  2. ORDER BYで指定されたカラムがインデックスに定義されている

必要なレコードをWHEREで十分に絞り込むか、インデックスを作成しないと速くなりませんのでご注意下さい。


ASで別名を定義しているのに、なぜWHEREに書くとエラーになるんだろう

WHEREはSELECTより先に評価されます。

なのでWHEREではSELECTで付けられた別名を参照出来ないのです。

ちなみにSELECTより後に評価されるORDER BYでは参照可能です。


JOINのONで条件指定するのと、WHEREで条件指定するのはどう違うんだろう

ONで指定できるものは、ONで指定した方が取得されるデータ量が少なく出来るので、速くなります。

ただし、JOIN後のカラムの状態に対して条件を指定したい場合などはONに書くと結果が異なるので注意が必要です。

結合条件と検索条件を混同しないように。

クエリを速くするには、とにかく早い段階で取得するデータ量を少なくする必要があります。

サブクエリをたくさん含む複雑なクエリを作成する場合も、最後にまとめてWHEREで絞るのではなく、各サブクエリ内でレコード数を減らしましょう。


まとめ

クエリを速くするには、結果セットをなるべく小さくする。それも早い段階で。ってのがポイントです。

SELECTに関しては評価順序以外にも知って欲しいことがありますが、それはまた別の機会に。


参考文献