メモ帳

Sep 14 2009

SQL文を最速にする11のポイント

 たとえ最終的な結果が同じでも,SQL文は書き方一つでパフォーマンスがずいぶんと変わってきます。ここでは,速いSQL文を記述するためのポイントや注意点をいくつか紹介しておきましょう。
●WHEREの左辺で算術演算子や関数を使わない

 WHERE句の左辺に算術演算や関数を指定すると,インデックスが使われません。例えば,
SELECT NAME FROM CUSTOMERS
WHERE SAL - TAX > 1000

とすると,たとえSALフィールドにインデックスが定義されていてもテーブル全体を走査してしまいます。こうした場合は,
SELECT NAME FROM CUSTOMERS
WHERE SAL > TAX + 1000

のように記述すれば良いでしょう。
●「後方一致」検索はなるべく避ける

 インデックスが付加されているフィールドであっても,LIKE ‘%AAA’ のような「後方一致」を指定すると,インデックスを検索せずにデータ部の全表走査が行われます。したがって「後方一致」の使用はなるべく避けるようにしましょう。どうしても必要であるなら,

・何らかの,少量まで絞り込める条件とAND条件で組み合わせる
・複数のフィールドに分割し,少しでも前方・完全一致できる範囲を広げる

といった方法を検討して下さい。
●IS NULL,IS NOT NULLを単独で使わない

 条件を表すWHERE句にIS NULL/IS NOT NULLを指定したときは,インデックスを定義したフィールドであっても,全表走査が行われます。したがって,これらの条件を指定するときは,単独で指定するのではなく,何らかのかなり絞り込める条件を合わせて指定してください。例えば,問い合わせの結果を変更せずに「B = 10」の条件を付加できるなら
…WHERE A IS NULL

とする代わりに
…WHERE A IS NULL AND B = 10

とします。
●SELECT文で「*」を使わない

 レコード長が長いときや,フィールド数が多いときには,すべてのフィールドを表す「*」を指定するのはできるだけ避けて,使用するフィールドだけを指定するようにします。「*」を指定すると,参照系のSQL文では,すべてのフィールドを繰り返してコピーするため,リソースを無駄に使うことになります。最低限度必要なフィールドだけを指定するのが基本です。
●ORはある程度絞り込んでから使う

 論理演算子ORを使用した場合,一応インデックスが使用されるものの,個々の条件が抽出する件数が少ない(数%程度)状態でないと,あまり効果がありません。
●DISTINCTの代りにEXISTSを使う

 SELECT文にDISTINCT*Aを指定すると処理に非常に時間がかかります。DISTINCTを使用するのは極力避けましょう。DISTINCTと同等の結果を得ることのできるSQL文にEXISTSがあります。例えば,
SELECT DISTINCT a.ID1, a.NAME1 FROM
TABLE1 a, TABLE2 b WHERE a.ID1 = b.ID2

のSQL文は,副問い合わせの条件としてEXISTSを指定して
SELECT a.ID1, a.NAME1 FROM TABLE1 a
WHERE EXISTS ( SELECT ‘X’ FROM
TABLE2 b WHERE a.ID1 = b.ID2)

と書き換えることができます。同様に,NOT INからNOT EXISTSに代替することによってパフォーマンスが向上することもあるので,これも検討してみてください。
●GROUP BY,ORDER BY,HAVINGは注意する

 GROUP BY句,ORDER BY句,HAVING句は,余分なディスク入出力が発生したりディスク領域を使うので,自分もしくはほかのプログラムのパフォーマンスに悪影響を及ぼします。このことを念頭において,使わずに済むならなるべく使わないようにしましょう。
●演算子の組み合わせで速度が変わる

 検索条件に,「>」「<」「=」をANDで組み合わせるときは,指定の仕方によってインデックスの使われ方が異なります。等号と不等号の組み合わせは,等号のみインデックスが使われます。例えば,
SELECT NAME FROM CUSTOMERS
WHERE JOB = ‘MANAGER’
AND SAL > 1000

とすると,「JOB = ‘MANAGER’」にはインデックスが使われますが,「SAL > 1000」には使われません。また,不等号同士の組み合わせでは,先に指定した条件だけにインデックスが使われます。つまり
SELECT NAME FROM CUSTOMERS
WHERE TAX > 100
AND SAL > 1000

のSQL文では,RDBMSは「TAX > 100」だけにインデックスを使い「SAL > 1000」には使いません。
●テーブルの別名を利用する

 テーブルに別名をつけて,フィールド名にはその別名をつけると,SQL文の解析処理を減らすことができます。例えば,
SELECT ID, NAME FROM CUSTOMERS
WHERE SAL < 1000
よりも,
SELECT a.ID, a.NAME FROM CUSTOMERS a
WHERE SAL < 1000
のほうが高速になります。
●SQL文の表現を統一する

 本文中で述べたように,RDBMSは実行計画をキャッシュに保存しておいて再利用します。ところが,SQL文に定数を直接記述してしまうと,RDBMSは定数値だけが異なるSQL文を別のものと解釈するため,再利用されません*B。バインド変数を使用して,できる限りSQL文を統一するようにします。また,文字の大小や記述の仕方なども統一しておかないと別のSQL文だと認識されてしまうので,気を付けてください。
●SQL文を簡潔に記述する

 SQL文はなるべく簡潔に記述するようにします。そうすることで,SQL文の処理時間を短縮することができます。

138 notes

  1. tokujoushibire reblogged this from gkojay
  2. hinoharu reblogged this from sesuna
  3. colonelmuska reblogged this from k32ru
  4. bettergin reblogged this from s-hsmt
  5. fiorizen reblogged this from metaphorize
  6. metaphorize reblogged this from bucket
  7. satoshi2000 reblogged this from bucket
  8. bucket reblogged this from petapeta
  9. korimax reblogged this from petapeta
  10. gate218 reblogged this from s-hsmt
  11. tora1014 reblogged this from s-hsmt
  12. s-hsmt reblogged this from yuichibass
  13. achacolate reblogged this from maepon
  14. maepon reblogged this from mendokusai
  15. hironon reblogged this from mendokusai
  16. stupidgeek reblogged this from gkojay
  17. mendokusai reblogged this from naapon
  18. yoshimuratorataro reblogged this from teramoto
  19. mobits reblogged this from teramoto
  20. teramoto reblogged this from rngsnow
  21. yysy reblogged this from petapeta
  22. nodoi reblogged this from gkojay
  23. rngsnow reblogged this from naapon
  24. tkpn reblogged this from naapon
  25. naapon reblogged this from gkojay
  26. rtaf reblogged this from petapeta
  27. darimaru reblogged this from gkojay
  28. nakano1996 reblogged this from petapeta
  29. boostpc reblogged this from gkojay
  30. sai10t reblogged this from gkojay
  31. passionflower reblogged this from gkojay
  32. es-s-etc reblogged this from petapeta
Page 1 of 1