Cara terbaik untuk menguji apakah ada baris dalam tabel MySQL


337

Saya mencoba mencari tahu apakah ada baris dalam tabel. Menggunakan MySQL, lebih baik melakukan kueri seperti ini:

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

dan periksa untuk melihat apakah totalnya bukan nol atau lebih baik melakukan kueri seperti ini:

SELECT * FROM table1 WHERE ... LIMIT 1

dan periksa untuk melihat apakah ada baris yang dikembalikan?

Di kedua kueri, klausa WHERE menggunakan indeks.

Jawaban:


470

Anda juga dapat mencoba EXISTS:

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

dan per dokumentasi , Anda bisa SELECTapa saja.

Secara tradisional, subquery EXISTS dimulai dengan SELECT *, tetapi bisa dimulai dengan SELECT 5 atau SELECT kolom1 atau apa pun. MySQL mengabaikan daftar SELECT dalam subquery seperti itu, jadi tidak ada bedanya.


30
Tes dengan ...EXISTS( SELECT 1/0 FROM someothertable). Untuk SQL Server & Oracle - tidak ada bedanya untuk menggunakan *, 1 atau NULL karena ADA hanya menguji boolean berdasarkan 1+ dari pencocokan kriteria WHERE.
OMG Ponies

77
Guys, katanya tepat di dokumentasi yang ditautkan dalam jawaban ini, paragraf ke-2, "Secara tradisional, subquery EXISTS dimulai dengan SELECT *, tetapi bisa dimulai dengan SELECT 5 atau SELECT column1 atau apa pun. MySQL mengabaikan daftar SELECT seperti itu sebuah subquery, jadi tidak ada bedanya. "
mpen

12
@ChrisThompson: apa yang terjadi ketika pernyataan dieksekusi? Maksud saya, apa set hasil berisi?
Ashwin

13
@Ashwin, ini berisi apakah 0 (tidak ada) atau 1 (ada).
fedorqui 'SO stop harming'

10
Saya pikir permintaan Anda berlebihan, saya diuji, dan permintaan SELECT 1 FROM table1 WHERE col = $var LIMIT 1ini lebih cepat dari permintaan Anda. Jadi, apa keunggulan permintaan Anda?
Shafizadeh

182

Saya telah melakukan beberapa penelitian tentang masalah ini baru-baru ini. Cara menerapkannya harus berbeda jika bidangnya adalah bidang TEKS, bidang yang tidak unik.

Saya telah membuat beberapa tes dengan bidang TEKS. Mempertimbangkan fakta bahwa kita memiliki tabel dengan entri 1M. 37 entri sama dengan 'sesuatu':

  • SELECT * FROM test WHERE texte LIKE '%something%' LIMIT 1dengan mysql_num_rows() : 0,039061069488525s. (LEBIH CEPAT)
  • 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.

Tetapi sekarang, dengan bidang BIGINT PK, hanya satu entri yang sama dengan '321321':

  • SELECT * FROM test2 WHERE id ='321321' LIMIT 1dengan 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. (LEBIH CEPAT)

2
Terima kasih atas jawaban tambahannya. Apakah Anda menemukan perbedaan waktu antara dua opsi tercepat untuk bidang TEXT menjadi cukup konsisten? Perbedaannya tidak tampak besar, dan menggunakan SELECT EXISTS (SELECT 1 ... LIMIT 1) tampaknya cukup bagus dalam kedua kasus.
Bernard Chen

1
Anda benar, perbedaannya tidak begitu penting mengenai hasil lainnya mengenai bidang teks. Namun demikian, mungkin kueri akan lebih baik menggunakanSELECT 1 FROM test WHERE texte LIKE '%something%' LIMIT 1
Laurent W.

Saya mencoba mysql dan dalam kasus yang Anda gunakan select 1 ... limit 1, tidak ada gunanya dikelilingi dengan pilih yang ada
Adrien Horgnies

4
@ SedikitNooby ada perbedaan. SELECT EXISTS ... memberikan nilai benar dan salah (1 atau 0), sedangkan SELECT 1 ... memberikan 1 atau kosong. Ada perbedaan halus antara nilai palsu dan set kosong, tergantung pada situasi Anda.
Quickpick

@LittleNooby membuat poin yang sangat bagus, yang mudah untuk diabaikan. Hilang dalam tes waktu di atas adalah SELECT 1 FROM test WHERE ..., tanpa SELECT EXISTSdi sekitarnya. Agaknya rambut lebih cepat seperti itu.
ToolmakerSteve

27

Contoh singkat jawaban @ ChrisThompson

Contoh:

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)

Menggunakan alias:

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

18

Dalam penelitian saya, saya dapat menemukan hasilnya dengan mengikuti kecepatan.

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

Saya merasa perlu untuk menunjukkan, meskipun tersentuh dalam komentar, bahwa dalam situasi ini:

SELECT 1 FROM my_table WHERE *indexed_condition* LIMIT 1

Lebih unggul dari:

SELECT * FROM my_table WHERE *indexed_condition* LIMIT 1

Ini karena kueri pertama dapat dipenuhi oleh indeks, sedangkan kueri kedua membutuhkan pencarian baris (kecuali mungkin semua kolom tabel dalam indeks yang digunakan).

Menambahkan LIMITklausa memungkinkan mesin berhenti setelah menemukan baris apa pun.

Kueri pertama harus sebanding dengan:

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

Yang mengirimkan sinyal yang sama ke mesin (1 / * tidak ada bedanya di sini), tapi saya masih menulis 1 untuk memperkuat kebiasaan ketika menggunakan EXISTS:

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

Mungkin masuk akal untuk menambahkan EXISTSpembungkus jika Anda membutuhkan pengembalian eksplisit ketika tidak ada baris yang cocok.


4

Sarankan Anda untuk tidak menggunakan Countkarena hitungan selalu membuat beban tambahan untuk penggunaan db SELECT 1dan itu mengembalikan 1 jika catatan Anda di sana jika tidak kembali nol dan Anda dapat menanganinya.


2

Sebuah COUNT query lebih cepat, meskipun mungkin tidak terasa, tapi sejauh mendapatkan hasil yang diinginkan, baik harus memadai.


4
Namun ini khusus untuk DB. COUNT (*) diketahui lambat di PostgreSQL. Lebih baik memilih kolom PK dan melihat apakah ia mengembalikan baris.
BalusC

3
COUNT (*) lambat di InnoDB
Akan

2

Terkadang cukup berguna untuk mendapatkan kunci primer kenaikan otomatis ( id) dari baris jika ada dan 0jika tidak.

Inilah cara ini dapat dilakukan dalam satu permintaan:

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

Mengapa tidak gunakan saja di IFNULL(id, 0)sini saja COUNT(*)?
Ethan Hohensee


-1

Saya akan pergi dengan COUNT(1). Lebih cepat daripada COUNT(*)karena COUNT(*)tes untuk melihat apakah setidaknya satu kolom di baris itu! = NULL. Anda tidak memerlukan itu, terutama karena Anda sudah memiliki kondisi ( WHEREklausa). COUNT(1)alih-alih menguji validitas 1, yang selalu valid dan membutuhkan waktu lebih sedikit untuk menguji.


8
-1 Ini salah. COUNT (*) tidak melihat nilai kolom - itu hanya menghitung jumlah baris. Lihat jawaban saya di sini: stackoverflow.com/questions/2876909/…
Mark Byers

6
COUNT () jauh lebih lambat daripada EXIS karena EXISTS dapat kembali ketika pertama kali menemukan baris
Akan

-1

Atau Anda dapat memasukkan bagian sql mentah ke ketentuan sehingga saya memiliki 'conditions' => array ('Member.id TIDAK DALAM (SELECT Membership.member_id DARI keanggotaan menjadi AS Keanggotaan)')


-2

COUNT(*) dioptimalkan dalam MySQL, sehingga permintaan sebelumnya cenderung lebih cepat, secara umum.


2
Apakah Anda mengacu pada pengoptimalan yang dimiliki MyISAM untuk memilih hitungan untuk seluruh tabel? Saya tidak berpikir itu membantu jika ada kondisi MANA.
Bernard Chen
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.