皆さんはSQLでEXISTSを使うとき、取得する項目って何を指定していますか?
よく見かけるのは、「*」を指定して全項目取得しているケースと、「1」を指定しているケースの2つです。
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で重要になるのはパフォーマンスなので、それぞれの実行速度を測ってみましょう。
目次
- 検証環境
- 速度測定
- SELECT *
- SELECT 1
- (おまけ)ここは何でもいいぞ!
- (おまけ2)1, 2, 3, 4, 5, "AAA", "BBB", "CCC", "DDD", "EEE" - 結果
- 今回の検証について
1. 検証環境
★実行環境
・DBエンジン : MySQL
・DBクライアント : A5SQL Mk-2
★DBテーブル
社員ID🔑 | 社員名 |
1 | 大阪たろう |
2 | 東京たろう |
3 | 福岡たろう |
~ | ~ |
社員ID🔑 | 資格ID🔑 | 取得日 |
1 | 1 | 2025-01-01 |
1 | 3 | 2025-02-10 |
2 | 6 | 2025-03-01 |
~ | ~ | ~ |
2. 速度測定
資格を3つ以上保有している社員名を抽出する
こちらの抽出条件にて、それぞれのSQLを10回実行して速度を測ります。
SELECT *
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
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 速いです。本当に「わずか」に速いです。
(おまけ)ここは何でもいいぞ!
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"
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