MySQLテーブルに行が存在するかどうかをテストする最良の方法


336

テーブルに行が存在するかどうかを確認しようとしています。MySQLを使用して、次のようなクエリを実行することをお勧めします。

SELECT COUNT(*) AS total FROM table1 WHERE ...

合計がゼロ以外であるか、または次のようなクエリを実行する方が良いかどうかを確認します。

SELECT * FROM table1 WHERE ... LIMIT 1

行が返されたかどうかを確認しますか?

どちらのクエリでも、WHERE句はインデックスを使用します。

回答:


469

あなたも試すことができますEXISTS

SELECT EXISTS(SELECT * FROM table1 WHERE ...)

ドキュメントごとにSELECT何でもできます。

伝統的に、EXISTSサブクエリはSELECT *で始まりますが、SELECT 5またはSELECT column1などで始まる可能性があります。MySQLはそのようなサブクエリのSELECTリストを無視するため、違いはありません。


30
でテストし...EXISTS( SELECT 1/0 FROM someothertable)ます。SQL ServerとOracleの場合-EXISTSは1+以上のWHERE条件に基づいてブール値をテストするだけなので、*、1、またはNULLを使用しても違いはありません。
OMGポニー

77
みんな、この回答の2番目の段落にリンクされているドキュメントで「伝統的に、EXISTSサブクエリはSELECT *で始まりますが、SELECT 5やSELECT column1などで始まる可能性があります。MySQLはそのようなSELECTリストを無視しますサブクエリなので、違いはありません。」
mpen 2012

12
@ChrisThompson:ステートメントが実行されるとどうなりますか?結果セットには何が含まれているのですか?
アシュウィン

13
@ Ashwin、0(存在しない)または1(存在)のいずれかが含まれます。
fedorqui 'SO stop harming' 2013

10
私はあなたのクエリが不必要だと私はテストしました、そしてこのクエリSELECT 1 FROM table1 WHERE col = $var LIMIT 1はあなたのクエリよりも高速です。では、クエリの利点は何ですか?
Shafizadeh 2015

182

私は最近この問題についていくつかの研究をしました。フィールドがTEXTフィールドであり、一意でないフィールドである場合、それを実装する方法は異なる必要があります。

TEXTフィールドを使用していくつかのテストを行いました。100万のエントリを持つテーブルがあることを考慮してください。37のエントリは「何か」に等しいです。

  • SELECT * FROM test WHERE texte LIKE '%something%' LIMIT 1mysql_num_rows() :0.039061069488525s。(もっと早く)
  • SELECT count(*) as count FROM test WHERE text LIKE '%something% :16.028197050095s。
  • SELECT EXISTS(SELECT 1 FROM test WHERE text LIKE '%something%') :0.87045907974243s。
  • SELECT EXISTS(SELECT 1 FROM test WHERE text LIKE '%something%' LIMIT 1) :0.044898986816406s。

しかし今、BIGINT PKフィールドでは、1つのエントリのみが「321321」に等しくなります。

  • SELECT * FROM test2 WHERE id ='321321' LIMIT 1mysql_num_rows() :0.0089840888977051s。
  • SELECT count(*) as count FROM test2 WHERE id ='321321' :0.00033879280090332s。
  • SELECT EXISTS(SELECT 1 FROM test2 WHERE id ='321321') :0.00023889541625977s。
  • SELECT EXISTS(SELECT 1 FROM test2 WHERE id ='321321' LIMIT 1):0.00020313262939453s。(もっと早く)

2
追加の回答をありがとう。TEXTフィールドの2つの最速オプションの時間の違いがかなり一貫していることに気づきましたか?違いは大きくないようで、SELECT EXISTS(SELECT 1 ... LIMIT 1)を使用することはどちらの場合もかなり良いようです。
バーナードチェン

1
あなたは正しい、違いはテキストフィールドに関する他の結果に関してそれほど重要ではありません。それでも、おそらくクエリを使用した方がよいでしょうSELECT 1 FROM test WHERE texte LIKE '%something%' LIMIT 1
Laurent W.

私はmysqlを試してみましたが、を使用する場合select 1 ... limit 1、selectで囲むのは無意味です
Adrien Horgnies

4
@LittleNoobyには違いがあります。SELECT EXISTS ...は真と偽の値(1または0)を返しますが、SELECT 1 ...は1または空を返します。状況に応じて、false値と空のセットには微妙な違いがあります。
クイックピック2016年

@LittleNoobyは見過ごされやすい優れた点です。上記のタイミングテストで欠落しているのはSELECT 1 FROM test WHERE ...SELECT EXISTSその周りにないものです。おそらくその方法で髪の毛はより速くなります。
ToolmakerSteve

27

@ChrisThompsonの回答の短い例

例:

mysql> SELECT * FROM table_1;
+----+--------+
| id | col1   |
+----+--------+
|  1 | foo    |
|  2 | bar    |
|  3 | foobar |
+----+--------+
3 rows in set (0.00 sec)

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 1);
+--------------------------------------------+
| EXISTS(SELECT 1 FROM table_1 WHERE id = 1) |
+--------------------------------------------+
|                                          1 |
+--------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 9);
+--------------------------------------------+
| EXISTS(SELECT 1 FROM table_1 WHERE id = 9) |
+--------------------------------------------+
|                                          0 |
+--------------------------------------------+
1 row in set (0.00 sec)

エイリアスを使用する:

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 1) AS mycheck;
+---------+
| mycheck |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)

18

私の研究では、次のスピードで結果が出ていることがわかります。

select * from table where condition=value
(1 total, Query took 0.0052 sec)

select exists(select * from table where condition=value)
(1 total, Query took 0.0008 sec)

select count(*) from table where condition=value limit 1) 
(1 total, Query took 0.0007 sec)

select exists(select * from table where condition=value limit 1)
(1 total, Query took 0.0006 sec) 

12

コメントで触れましたが、このような状況では、指摘する価値があります。

SELECT 1 FROM my_table WHERE *indexed_condition* LIMIT 1

優れている:

SELECT * FROM my_table WHERE *indexed_condition* LIMIT 1

これは、最初のクエリはインデックスで満たすことができるため、2番目のクエリでは行のルックアップが必要になるためです(使用されるインデックスにテーブルの列がすべて含まれている場合を除く)。

LIMIT句を追加すると、行を見つけた後にエンジンを停止できます。

最初のクエリは次のようになります。

SELECT EXISTS(SELECT * FROM my_table WHERE *indexed_condition*)

これは同じ信号をエンジンに送信します(1 / *はここでは違いはありません)が、使用時に習慣を強化するために1を書きますEXISTS

SELECT EXISTS(SELECT 1 FROM my_table WHERE *indexed_condition*)

EXISTS行が一致しないときに明示的な戻りが必要な場合は、ラッピングを追加することは意味があります。


4

あなたが使用していない提案Countカウントは常にデシベルの使用のために余分な負荷を作るのでSELECT 1、それが返す1を右そこにあなたの記録は、それ以外の場合はNULLを戻しますと、あなたがそれを処理することができます。


2

COUNTのかもしれません著しく、しかし限り、望ましい結果を得るように、両者が十分でなければなりませんが、クエリは、高速です。


4
ただし、これはDB固有です。COUNT(*)はPostgreSQLでは遅いことがわかっています。PK列を選択し、行が返されるかどうかを確認することをお勧めします。
BalusC 2009年

3
COUNT(*)はいえInnoDB内遅いです
ウィル

2

id行の自動インクリメント主キー()が存在する場合と存在0しない場合の取得が非常に便利な場合があります。

これを単一のクエリで実行する方法は次のとおりです。

SELECT IFNULL(`id`, COUNT(*)) FROM WHERE ...

IFNULL(id, 0)代わりにここで使用しないのはなぜCOUNT(*)ですか?
イーサンホーエンゼー2017


-1

と一緒に行きCOUNT(1)ます。その行の少なくとも1つの列が!= NULLであるかどうかをテストするCOUNT(*)ためのCOUNT(*)テストよりも高速です。特に条件(WHERE節)が既に整っているため、これは必要ありません。COUNT(1)代わりにの有効性1をテストします。これは常に有効であり、テストにかかる時間が大幅に短縮されます。


8
-1これは誤りです。COUNT(*)は列の値を調べません。行の数を数えるだけです。ここに私の答えを参照してください:stackoverflow.com/questions/2876909/...
マーク・バイヤーズ

6
COUNT()は、EXISTSが行を最初に見つけたときに戻ることができるため、EXISTSよりもはるかに遅くなります
Will

-1

または、生のSQLパーツを条件に挿入して、 'conditions' => array( 'Member.id NOT IN(SELECT Membership.member_id FROM memberships AS Membership))とすることができます。


-2

COUNT(*) MySQLで最適化されているため、一般的に言えば、前のクエリはより高速になる可能性があります。


2
テーブル全体の数を選択するためにMyISAMが持っている最適化について言及していますか?WHERE条件があったとしても、それは役に立たないと思いました。
Bernard Chen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.