Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
神谷 雅紀
SQL Server Escalation Engineer
パフォーマンスに優れたクエリを書こうとするのであれば、クエリの WHERE 句や結合句で参照されるテーブルの列を関数などで加工してはいけません。
悪い例
SELECT * FROM Sales WHERE convert(char(10),EntryDate, 111) = ‘2010/12/01’
SELECT * FROM Sales WHERE FistName + Last Name = @name
なぜ?
その列にインデックスがあったとしても、そのインデックスによる行の絞込みが行えないからです。
例えば、上の例の最初のクエリでは、以下の処理が必要です。
- テーブルから行を読み取る。
- 列 EntryDate の値を convert 関数に渡す。
- convert 関数から返された値を定数 ‘2010/12/01’ と比較する。
- 比較の結果、一致すれば、その行をクエリ結果へ入れる。一致しなければ 1 へ戻り次の行を処理。
このように、クエリ条件に一致しているかどうかを判定するためには、値を関数に渡す必要があり、関数に渡すためには必ず行を読み取ることが必要になるため、EntryDate がインデックスの先頭列であったとしても、そのインデックスを使用して、読み取り範囲を ‘2010/12/01’ に限定することができず、テーブルの全行を読み取る必要があります。読み取り量が多いということは、処理するデータ量が多いということであり、処理するデータ量が多ければ、処理完了までには時間がかかることになります。つまり、クエリの実行時間が長くなります。
どうするか?
クエリが同じ結果を生成し、かつ、列の値を加工しない別の方法を検討します。
例えば、上の例であれば、’2010/12/01 00:00:00.000’ 以上、かつ、’2010/12/02 00:00:00.000’ 未満という条件でも同じ結果を得られるのではないでしょうか。
SELECT * FROM Sales WHERE EntryDate >= '2010/12/01 00:00:00.000' and EntryDate < '2010/12/02 00:00:00.000'
EntryDate を文字列型とし、データは年月日のみを持つようにするという方法も考えられます。方法としてはいろいろと考えられるため、システム全体を考慮して、クエリの書き方で対応するのか、あるいはテーブルスキーマを変更するのか、もしくはその他の方法を用いるのかを検討します。