MySQL tablosunda bir satır olup olmadığını test etmenin en iyi yolu


337

Tabloda bir satır olup olmadığını bulmaya çalışıyorum. MySQL kullanarak, böyle bir sorgu yapmak daha iyidir:

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

ve toplamın sıfırdan farklı olup olmadığını veya bunun gibi bir sorgu yapmanın daha iyi olup olmadığını kontrol edin:

SELECT * FROM table1 WHERE ... LIMIT 1

ve herhangi bir satır döndürülüp döndürülmediğini kontrol edin?

Her iki sorguda da, WHERE deyimi bir dizin kullanır.

Yanıtlar:


470

Ayrıca deneyebilirsiniz EXISTS:

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

ve belgelere göre her SELECTşeyi yapabilirsiniz .

Geleneksel olarak, bir EXISTS alt sorgusu SELECT * ile başlar, ancak SELECT 5 veya SELECT sütun1 veya herhangi bir şeyle başlayabilir. MySQL, böyle bir alt sorgudaki SELECT listesini yok sayar, bu yüzden fark etmez.


30
İle test edin ...EXISTS( SELECT 1/0 FROM someothertable). SQL Server ve Oracle için - *, 1 veya NULL kullanmak fark etmez çünkü EXISTS yalnızca 1 + WHERE ölçüt eşleşmesine dayalı bir boole testi yapar.
OMG Ponies

77
Çocuklar, bu cevabın 2. paragrafında yer alan belgelerde "Geleneksel olarak bir EXISTS alt sorgusu SELECT * ile başlar, ancak SELECT 5 veya SELECT sütun 1 veya herhangi bir şeyle başlayabilir." bir alt sorgu, bu yüzden fark etmez. "
mpen

12
@ChrisThompson: ifade yürütüldüğünde ne olur? Yani sonuç kümesi ne içeriyor?
Ashwin

13
@Ashwin, 0 (mevcut değil) veya 1 (mevcut) içeriyor.
fedorqui 'SO

10
Sorgunuzun gereksiz olduğunu düşünüyorum, test ettim ve bu sorgu sorgunuzdan SELECT 1 FROM table1 WHERE col = $var LIMIT 1daha hızlı. Peki sorgunuzun avantajı nedir?
Shafizadeh

182

Son zamanlarda bu konuda bazı araştırmalar yaptım. Alanın bir METİN alanı, benzersiz olmayan bir alan olması durumunda, uygulamanın yolu farklı olmalıdır.

METİN alanı ile bazı testler yaptım. 1M girişleri içeren bir tablomuz olduğu düşünüldüğünde. 37 kayıt 'bir şeye' eşittir:

  • SELECT * FROM test WHERE texte LIKE '%something%' LIMIT 1ile mysql_num_rows() : 0.039061069488525s. (DAHA HIZLI)
  • 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.

Ama şimdi, bir BIGINT PK alanı ile, sadece bir giriş '321321'e eşittir:

  • SELECT * FROM test2 WHERE id ='321321' LIMIT 1ile mysql_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. (DAHA HIZLI)

2
Ek cevap için teşekkürler. METİN alanı için en hızlı iki seçenek arasındaki zaman farkını oldukça tutarlı buldunuz mu? Fark büyük görünmüyor ve SELECT EXISTS (SELECT 1 ... LIMIT 1) kullanmak her iki durumda da oldukça iyi görünüyor.
Bernard Chen

1
Haklısınız, metin alanı ile ilgili diğer sonuçlarda fark çok önemli değil. Bununla birlikte, belki de sorgu daha iyi olurduSELECT 1 FROM test WHERE texte LIKE '%something%' LIMIT 1
Laurent W.

MySQL üzerinde denedim ve kullandığınız durumda select 1 ... limit 1, select ile çevrelemek işe yaramaz
Adrien Horgnies

4
@LittleNooby fark var. SELECT EXISTS ... doğru ve yanlış değeri (1 veya 0) verirken, SELECT 1 ... 1 veya boş verir. Durumunuza bağlı olarak yanlış değer ve boş küme arasında küçük bir fark vardır.
Quickpick

@ LittleNooby mükemmel bir noktaya değiniyor, bu da gözden kaçırılması kolay. Yukarıdaki zamanlama testlerinde eksik SELECT 1 FROM test WHERE ..., SELECT EXISTSetrafında olmadan . Muhtemelen bu şekilde daha hızlı bir saçtır.
ToolmakerSteve

27

@ ChrisThompson'un cevabına kısa bir örnek

Misal:

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)

Takma ad kullanma:

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

18

Araştırmamda sonucu takip eden hızda bulabilirim.

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

Yorumlarda değinilse de, bu durumda belirtmeye değer olduğunu düşünüyorum:

SELECT 1 FROM my_table WHERE *indexed_condition* LIMIT 1

Üstündür:

SELECT * FROM my_table WHERE *indexed_condition* LIMIT 1

Bunun nedeni, ilk sorgunun dizin tarafından karşılanabilmesidir, ikincisi ise satır araması gerektirir (muhtemelen tüm tablo sütunları kullanılan dizinde değilse).

Yan LIMITtümce eklenmesi, herhangi bir satır bulduktan sonra motorun durmasını sağlar.

İlk sorgu aşağıdakilerle karşılaştırılabilir olmalıdır:

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

Hangi aynı sinyalleri motora gönderir (1 / * burada fark etmez), ancak kullanırken alışkanlığı güçlendirmek için 1'i yazarım EXISTS:

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

EXISTSHiçbir satır eşleşmediğinde açık bir dönüş gerekiyorsa , sarma eklemek mantıklı olabilir .


4

Kullanmak değil öner Countsayımı her zaman db kullanımı için ekstra yükler yapar çünkü SELECT 1ve döndürdüğü 1 hemen orada kayıt aksi takdirde null döndürür ve bunu işleyebilir eğer.


2

Bir COUNT belki fark, ancak bildiğim kadarıyla istenen sonucu almak gibi, hem yeterli olmalıdır rağmen sorgu, hızlıdır.


4
Ancak bu DB'ye özgüdür. COUNT (*) öğesinin PostgreSQL'de yavaş olduğu bilinmektedir. PK sütununu seçmek ve herhangi bir satır döndürüp döndürmediğini görmek daha iyi olur.
BalusC

3
(*) COUNT olsa InnoDb yavaş
Will

2

Bazen, idvarsa ve 0yoksa , satırın otomatik artış birincil anahtarını ( ) almak oldukça kullanışlıdır .

Bunun tek bir sorguda nasıl yapılabileceği aşağıda açıklanmıştır:

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

Neden sadece IFNULL(id, 0)burada değil COUNT(*)?
Ethan Hohensee


-1

Ben giderdim COUNT(1). Bu satırdaki en az bir sütunun! = NULL olup olmadığını görmek COUNT(*)için COUNT(*)yapılan testlerden daha hızlıdır . Buna ihtiyacınız yok, özellikle zaten yerinde bir koşulunuz olduğu için ( WHEREmadde). COUNT(1)bunun yerine 1her zaman geçerli olan ve test edilmesi çok daha az zaman alan geçerliliğini test eder.


8
-1 Bu yanlış. COUNT (*) sütun değerlerine bakmaz - yalnızca satır sayısını sayar. Cevabımı burada görebilirsiniz: stackoverflow.com/questions/2876909/…
Mark Byers

6
COUNT () çok daha yavaş ilk bir satır bulduğunda dönebilirsiniz MEVCUT olarak MEVCUT daha
Will

-1

Veya koşullara ham sql parçası ekleyebilirsiniz, böylece 'koşullar' => dizi ('Member.id NOT IN (Üyelik AS Üyelik SELİM Üyeliği. üye)


-2

COUNT(*) MySQL'de optimize edildiğinden, eski sorgunun genel olarak daha hızlı olması muhtemeldir.


2
Tüm tablo için sayımı seçmek için MyISAM'ın sahip olduğu optimizasyondan mı bahsediyorsunuz? Bir WHERE durumu varsa bunun yardımcı olduğunu düşünmüyordum.
Bernard Chen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.