【SQL】結局EXISTSは「*」と「1」のどっちが正しいの?

マッシュルーム
2025-04-03
2025-04-03

皆さんはSQLでEXISTSを使うとき、取得する項目って何を指定していますか?
よく見かけるのは、「*」を指定して全項目取得しているケースと、「1」を指定しているケースの2つです。

 SELECT  *  FROM  XXXXX A
 WHERE  EXISTS  (SELECT  *  FROM  XXXXX B  WHERE  B.YYYYY  =  A.YYYYY)

 SELECT  *  FROM  XXXXX A
 WHERE  EXISTS  (SELECT  1  FROM  XXXXX B  WHERE  B.YYYYY  =  A.YYYYY)

このような感じ

 SELECT  *  FROM  XXXXX A
 WHERE  EXISTS  (SELECT  "ここは何でもいいぞ!"  FROM  XXXXX B  WHERE  B.YYYYY  =  A.YYYYY)

こんなのもあったり

では、EXISTS内では何を取得するのが正しいのだろうか?
やはりSQLで重要になるのはパフォーマンスなので、それぞれの実行速度を測ってみましょう。

目次

  1. 検証環境
  2. 速度測定
    - SELECT *
    - SELECT 1
    - (おまけ)ここは何でもいいぞ!
    - (おまけ2)1, 2, 3, 4, 5, "AAA", "BBB", "CCC", "DDD", "EEE"
  3. 結果
  4. 今回の検証について


1. 検証環境

★実行環境

・DBエンジン : MySQL
・DBクライアント : A5SQL Mk-2

★DBテーブル
社員テーブル(250件)
社員ID🔑 社員名
1 大阪たろう
2 東京たろう
3 福岡たろう

 

社員資格テーブル(630件)
社員ID🔑 資格ID🔑 取得日
1 1 2025-01-01
1 3 2025-02-10
2 6 2025-03-01

 

2. 速度測定

資格を3つ以上保有している社員名を抽出する

こちらの抽出条件にて、それぞれのSQLを10回実行して速度を測ります。

SELECT *

SELECT  a.社員名  FROM  社員テーブル a
WHERE  EXISTS (
        SELECT  *  FROM  社員資格テーブル b
        WHERE  b.社員ID  =  a.社員ID
        GROUP BY  b.社員ID
        HAVING  COUNT(*)  >  2
)

  1回目:0.313 s
  2回目:0.305 s
  3回目:0.298 s
  4回目:0.305 s
  5回目:0.298 s
  6回目:0.297 s
  7回目:0.302 s
  8回目:0.300 s
  9回目:0.301 s
10回目:0.298 s

平均:0.301 s 

 SELECT 1

SELECT  a.社員名  FROM  社員テーブル a
WHERE  EXISTS (
        SELECT  1  FROM  社員資格テーブル b
        WHERE  b.社員ID  =  a.社員ID
        GROUP BY  b.社員ID
        HAVING  COUNT(*)  >  2
)

  1回目:0.254 s
  2回目:0.259 s
  3回目:0.256 s
  4回目:0.259 s
  5回目:0.258 s
  6回目:0.262 s
  7回目:0.266 s
  8回目:0.263 s
  9回目:0.262 s
10回目:0.264 s

平均:0.260 s 

「*」と比べ、0.04s 速いです。本当に「わずか」に速いです。

(おまけ)ここは何でもいいぞ!

SELECT  a.社員名  FROM  社員テーブル a
WHERE  EXISTS (
        SELECT  "ここは何でもいいぞ!"  FROM  社員資格テーブル b
        WHERE  b.社員ID  =  a.社員ID
        GROUP BY  b.社員ID
        HAVING  COUNT(*)  >  2
)

  1回目:0.258 s
  2回目:0.260 s
  3回目:0.258 s
  4回目:0.262 s
  5回目:0.258 s
  6回目:0.257 s
  7回目:0.260 s
  8回目:0.259 s
  9回目:0.257 s
10回目:0.259 s

平均:0.258 s 

意外にも、「1」と同等の結果となりました。

(おまけ2)1, 2, 3, 4, 5, "AAA", "BBB", "CCC", "DDD", "EEE"

SELECT  a.社員名  FROM  社員テーブル a
WHERE  EXISTS (
        SELECT  1, 2, 3, 4, 5, "AAA", "BBB", "CCC", "DDD", "EEE"  FROM  社員資格テーブル b
        WHERE  b.社員ID  =  a.社員ID
        GROUP BY  b.社員ID
        HAVING  COUNT(*)  >  2
)

  1回目:0.255 s
  2回目:0.258 s
  3回目:0.255 s
  4回目:0.260 s
  5回目:0.262 s
  6回目:0.259 s
  7回目:0.260 s
  8回目:0.254 s
  9回目:0.260 s
10回目:0.254 s

平均:0.257 s 

項目の取得数を増やしてみましたが、こちらも「1」と同等の結果となりました。

3. 結果

「1」や「1, 2, 3」など、固定長の文字列のみを指定したケースの方がわずかに速い結果となりました。
全て固定長の文字列を指定した場合は、取得数を増やしてもそんなに関係はなさそうですね。

「*」の場合はテーブルを参照して全レコードを取得しているので、そこにわずかなボトルネックが存在しているのかな?といった見解です。

.....が、微々たるものなので「*」でも正直問題ないとも思えます。

個人的にはシングルバイト文字列を1文字だけ指定した「1」の方が、なんとなく安心します。

4. 今回の検証について

今回はMySQLでシンプルなクエリを使用した検証でしたが、Oracleなど別のDBを使用した場合や、もっとクエリが複雑であったりテーブル数やレコード件数が膨大となれば、また違った結果となるかもということだけご留意ください。m(_ _)m