16bit!

エンジニアじゃなくなっちゃった人が何かを書くブログ

【SQL】EXISTS句の中は"SELECT *" か"SELECT 1"か

備忘を兼ねて。


SQLを実行する際、"IN"を使うよりも"EXISTS"を使う方が速い」
というのは割と周知の事実ですが、
じゃあ、EXISTSを使う場合、
「その中身は"SELECT *"を使うべきなのか"SELECT 1(定数)"を使うべきなのか」
というと、こっちは少々微妙な問題のようです。

//遅い
SELECT *
FROM tbl_A
WHERE tbl_A.col_a IN (SELECT col_b
                      FROM tbl_B);

//速い
SELECT A.*
FROM tbl_A as A
WHERE EXISTS (SELECT *
              FROM tbl_B as B
              WHERE A.col_a = B.col_b);

というのも、DBMSごと(さらに言えばVersionごと)に、どっちが速いかが変わってくるようなんですね。

簡単に調べてみた感じだと、だいたいこんな感じ。

DBMS どちらが速いか
oracle以外 "SELECT *"の方が速い
oracle(9i以前) "SELECT 1"の方が速い
oracle(10g以降) "SELECT *"の方が速い

oracle以外のDBMSでも定数使う方が速いものもあるとは思いますが(特に古いもの)、
その辺は調べきっていないので、上の表はあくまでも「だいたい」です。


正確にはoracleのバージョンと言うよりも、
ルールベースかコストベースかによってどちらが速いかが変わってくるようです。

いずれにせよ、今はoracleもほとんどコストベースで動かしていると思うので、
基本的には"SELECT *"が良いと思われます。
ただし、コストベースは時々意図しない動きをして気持ち悪いので、
対策として敢えてルールベースで動かしている場合などには"SELECT 1"のが速いです。


<参考>
SQLを速くするぞ
2つの副問い合わせの違い


まぁあれです。
古いソースを引き継いだ時に先任が"SELECT 1"って書いていたり、
また先輩から、「oracleは"SELECT 1"の方が速いからそうしろ」とか教えられたとしても、
それは決して嘘ではないので、温かい目と優しい心をもって修正しましょう。


終わり。