EXISTS]は、たいていの場合、全く等しい結果集合を返します。この両者でサブクエリーを作る場合は、EXISTSの方が圧倒的に速い。有名人の誰かと同じ誕生日に生まれた社員を全て探すためのSQLを考えます。以下の2つのSQLは、同じ結果を返しますが、2番目の方が速いです。C.birthday);なぜ、EXISTSの方が速いか?その理由は以下の2点です。結合キー(この場合はbirthday)にインデックスが張られていれば、Celebritiesテーブルの実表は見に行かず、インデックスのみを参照する。Celebritiesテーブルがインデックスを持っていなくても、優れたオプティマイザならば、birthday列をソートした一時テーブルを作り、2分探索することで、全表走査よりも効率的に検索を行なう。サブクエリーを引数に取る場合、IN述語を使うなEXISTSで代用でき、しかもたいてい、その方が圧倒的に速いからです。INの引数にサブクエリーを取る場合、DBは、まずサブクエリーから実行し、その結果を一時的な作業テーブル上に格納します。インライン・ビューを作るのです。その後に、その作業テーブルを全件走査します。これは、多くの場合、非常にコストがかかります。EXISTSを使えば、既に見たように、一時テーブルなど作成されません。ソースコードの可読性という点において、IN述語はEXISTS述語に勝ります。要するに、IN述語で書いた方がぱっと見て意味が分かりやすいコードになります。従って、IN述語を使っても十分短い応答時間が確保されているなら、そのSQL文を敢えてEXISTS述語で書き直す必要はありません。・IN述語の引数リストには、最もありそうなキーを左寄せしろなぜなら、INは、左から右へ引数を評価し、見つかった時点でtrueを返しそれより右の引数は見ないからです。以下の2つのSQLを比較してください。使えサブクエリーのSELECT句を書くには、以下の3つの選択肢があります。...)このうち、最も良いのは1です。この書き方は、オプティマイザにどのカラムを使うべきかの選択を委ねることになります。カラムにインデックスが張られていれば、実表を走査する必要はありません。例外的に2や3の方が1よりも高速な場合もあります。古いSQL製品の場合は2のように列名を指定した方が速いこともあります。...」など、定数を指定すると高速になります。この書き方は、行へのポインタさえ得られれば、実際の行を読む必要がないことを、DBMSに指摘するからです。2は、もはや使う機会はないでしょうし、3の書き方は意味的な混乱を招くので、1を採用するべきです。・3つ以上のテーブルを結合させる時は冗長な結合条件を書けTable1:小さいTable2:大きいTable3:大きい上記のようなサイズの3つのテーブルがあるとします。共通のカラムで3つのテーブルを結合するとき、次のように書けます。Table3.common;あるいは、次のようにも書けます。こちらの方が遅くて非効率です。Table3.common;なぜなら、2番目のSQLは、最初にTable2とTable3という大きなテーブルを結合した大きな結果集合と、Table1とTable3を結合した小さな結果集合でマッチングを行なうからです。結合条件は、小さなテーブルを最初に書くべきです。良い書き方は、テーブルのサイズが変わっても大丈夫なように、オプティマイザ自身にテーブルのサイズを決定させる書き方です。そのためには、次のように結合条件に冗長性を持たせます。Table1.common;もちろん、テーブルのサイズにあまり変化がない場合は、あえて結合条件に冗長性を持たせる必要はありません。・行数を数えるときはCOUNT(*)よりもCOUNT(カラム名)を使えこのトリックは、インデックスを使います。したがって、これがうまく働くためには、COUNT関数の引数となるカラムにインデックスが張られている必要があります。Sales;よりは、次のSQLの方が速いかもしれない。Sales;ここで、sale_idがSalesテーブルの主キーだとすれば、当然、sale_idにはユニークなインデックスが存在します。それを利用するのが、このトリックです。・WHERE句の抽出条件は、最も制限の強いものから並べろ抽出条件がANDでつながっている場合は、制限の強いもの、つまりそれによって選択される行数が少ないものから順に並べる方が、効率がよいです。'male';なぜなら、評価がAの生徒の方が、男子学生よりも少ないから。この学校がハーレムのごとき場所なら話は別ですが。・UNIONは使うな。UNIONは、二つの結果集合をマージします。重複行を排除するためのソート処理にコストがかかります。ALLを使ってください。すればソートは発生しません。・実はインデックスが使用されていないという罠。皆さんが検索するテーブルには、きっとインデックスが張られているでしょう。インデックスは、行数や列数の多い表を短時間で検索するためのテクニックとしては非常にポピュラーです。その原理は、C言語のポインタ配列と同じです。サイズの大きなオブジェクト配列を検索するよりも、サイズの小さなポインタ配列を検索した方が効率がいい、というわけです。2分探索による高速検索が可能なよう工夫されています。Aという列にインデックスが張られているとします。以下のSQLはそのインデックスを使うつもりで、実のところテーブルXXを全件検索してしまっています。100検索条件の右側で式を用いれば、インデックスが使用されます。100/1.1という条件を使えばいいわけです。関数索引を使うという方法もありますが、トリッキーなので推奨しません。NULLなぜなら、インデックスの中にはNULLは存在しないから。NULLは値ではないのです。IN)はインデックスを使用できません。'abc'理由は知らない。しても使いたいならビットマップ索引を張りましょう。'%a'理由は知らない。適当なテーブル名;というSQLを実行してください。ROWID——————AAAF+OAAIAAABmMABIAAAF+OAAIAAABmMABKAAAF+OAAIAAABmMABLなどといった列が選択されるはずです。ROWIDはどのテーブルでも必ず持っている擬似列であり、そこに格納されている値はレコードの物理アドレスです。ROWIDはポインタの役割を果たす。インデックスもROWIDを使用しています。ROWIDは、セッションが終了すると変化するかもしれませんが、ユーザセッション中は不変であり、Oracleでは常に最速のアクセスが保証されます。