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.

Bernard Chen
sumber

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.

Chris Thompson
sumber
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)
Laurent W.
sumber
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)
jaltek
sumber
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) 
shihab mm
sumber
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.

Arth
sumber
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.

Fatih Karatana
sumber
2

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

Jaywon
sumber
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 ...
Zaxter
sumber
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.

Felix
sumber
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)')

pengguna4193303
sumber
-2

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

Arthur Reutenauer
sumber
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