Cara tercepat untuk menentukan apakah ada catatan

143

Seperti judulnya ... Saya mencoba mencari cara tercepat dengan overhead paling sedikit untuk menentukan apakah ada catatan dalam tabel atau tidak.

Permintaan sampel:

SELECT COUNT(*) FROM products WHERE products.id = ?;

    vs

SELECT COUNT(products.id) FROM products WHERE products.id = ?;

    vs

SELECT products.id FROM products WHERE products.id = ?;

Katakanlah ?bertukar dengan 'TB100'... baik kueri pertama dan kedua akan mengembalikan hasil yang sama persis (katakanlah ... 1untuk percakapan ini). Permintaan terakhir akan kembali 'TB100'seperti yang diharapkan, atau tidak ada jika idtidak ada dalam tabel.

Tujuannya adalah untuk mengetahui apakah idada di dalam tabel atau tidak. Jika tidak, program selanjutnya akan memasukkan catatan, jika ya, program akan melewatkannya atau melakukan kueri UPDATE berdasarkan logika program lain di luar cakupan pertanyaan ini.

Mana yang lebih cepat dan memiliki lebih sedikit overhead? (Ini akan diulang puluhan ribu kali per program yang dijalankan, dan akan dijalankan berkali-kali sehari).

(Menjalankan kueri ini terhadap M $ SQL Server dari Java melalui driver JDBC yang disediakan M $)

SnakeDoc
sumber
1
Ini mungkin tergantung pada basis data. Sebagai contoh, mengandalkan Postgres agak lambat.
Mike Christensen
Maaf, ini Java berbicara dengan M $ SQL melalui driver jdbc. Saya akan memperbarui OP saya.
SnakeDoc
2
Ada juga ada .
Nikola Markovinović
@Nikola Markovinović: bagaimana Anda menggunakannya dalam kasus ini?
zerkms
5
@zerkms Tergantung pada konteks. Jika dalam prosedur tersimpan akan menjadi if exists(select null from products where id = @id); jika dalam kueri dipanggil langsung oleh klien select case when exists (...) then 1 else 0 end.
Nikola Markovinović

Jawaban:

170

SELECT TOP 1 products.id FROM products WHERE products.id = ?; akan mengungguli semua saran Anda karena akan menghentikan eksekusi setelah menemukan catatan pertama.

Deklarasi_K
sumber
5
Tidakkah pengoptimal memperhitungkannya sendiri ketika melakukan pencarian melalui PK (atau kunci unik lainnya)?
zerkms
3
Dia tidak pernah menyatakan bahwa itu adalah PK, tetapi jika demikian maka pengoptimal akan mempertimbangkannya.
Declan_K
3
@Declan_K: sepertinya bidang sihir saya gagal dalam kasus ini dan kolom berjudul idbukan PK. Jadi +1 atas saran Anda.
zerkms
4
Jika bukan PK, saya juga menyarankan memastikan ada indeks pada kolom itu. Jika tidak, kueri harus melakukan pemindaian tabel alih-alih pencarian tabel yang lebih cepat.
CD Jorgensen
3
Saya pikir kita harus mempertimbangkan jawaban @ nenad-zivkovic untuk yang satu ini.
Giulio Caccin
192

EXISTS(atau NOT EXISTS) dirancang khusus untuk memeriksa apakah ada sesuatu dan karenanya (dan) pilihan terbaik. Ini akan berhenti pada baris pertama yang cocok sehingga tidak memerlukan TOPklausa dan tidak benar-benar memilih data sehingga tidak ada overhead dalam ukuran kolom. Anda dapat menggunakan dengan aman di SELECT *sini - tidak berbeda dari SELECT 1, SELECT NULLatau SELECT AnyColumn... (Anda bahkan dapat menggunakan ekspresi tidak valid seperti SELECT 1/0dan tidak akan rusak) .

IF EXISTS (SELECT * FROM Products WHERE id = ?)
BEGIN
--do what you need if exists
END
ELSE
BEGIN
--do what needs to be done if not
END
Nenad Zivkovic
sumber
tidakkah ini harus terlebih dahulu menjalankan pernyataan SELECT, kemudian jalankan pernyataan JIKA ADA ... menyebabkan overhead tambahan dan karenanya lebih banyak waktu pemrosesan?
SnakeDoc
7
@SnakeDoc No. Existsbekerja dengan selectsedemikian rupa sehingga keluar segera setelah satu baris ditemukan. Lebih lanjut ada hanya mencatat keberadaan catatan, bukan nilai aktual dalam catatan, menghemat kebutuhan untuk memuat baris dari disk (tentu saja dengan asumsi kriteria pencarian diindeks). Adapun overhead if- Anda harus menghabiskan waktu yang sangat kecil ini.
Nikola Markovinović
1
@ Titik menarik NikolaMarkovinović. Saya tidak yakin apakah ada Indeks di bidang ini, dan SQL pemula saya tidak tahu bagaimana mengetahuinya. Saya bekerja dengan DB ini dari Jawa melalui JDBC dan database jarak jauh terletak di colo di suatu tempat. Saya hanya diberikan "ringkasan basis data" yang hanya merinci bidang mana yang ada di setiap tabel, jenisnya, dan setiap FK atau PK. Apakah ini mengubah sesuatu?
SnakeDoc
3
@SnakeDoc Untuk mengetahui tentang struktur tabel, termasuk kunci dan indeks asing, jalankan sp_help table_name . Indeks sangat penting ketika mengambil beberapa baris dari banyak, di mana menggunakan select topatau exists; jika tidak ada, mesin sql harus melakukan pemindaian tabel. Ini adalah opsi pencarian tabel yang paling tidak diinginkan. Jika Anda tidak berwenang membuat indeks, Anda harus berkomunikasi dengan staf teknis di sisi lain untuk mengetahui apakah mereka menyesuaikan secara otomatis atau mereka mengharapkan Anda untuk menyarankan indeks.
Nikola Markovinović
1
@Konstantin Anda dapat melakukan sesuatu sepertiSELECT CASE WHEN EXISTS(..) THEN 1 ELSE 0 END;
Nenad Zivkovic
21

Tidak ada yang bisa mengalahkan -

SELECT TOP 1 1 FROM products WHERE id = 'some value';

Anda tidak perlu menghitung untuk mengetahui apakah ada data dalam tabel. Dan jangan gunakan alias saat tidak diperlukan.

AgentSQL
sumber
5
Meskipun namanya idbukan kunci utama. Jadi, meskipun Anda tidak menghitung Anda masih perlu menemukan semua catatan yang cocok, mungkin ribuan dari mereka. Tentang aliasing - kode adalah pekerjaan konstan yang sedang berjalan. Anda tidak pernah tahu kapan Anda harus kembali. Aliasing membantu mencegah kesalahan runtime yang bodoh; misalnya, nama kolom unik yang tidak memerlukan alias tidak lagi unik karena seseorang membuat kolom dengan nama yang sama di tabel gabungan lainnya.
Nikola Markovinović
Ya, Anda benar sekali. Mengasingkan banyak membantu tetapi saya tidak berpikir itu membuat perbedaan ketika tidak menggunakan gabungan. Jadi, saya katakan jangan menggunakannya jika tidak perlu. :) Dan Anda dapat menemukan diskusi panjang di sini tentang memeriksa keberadaan. :)
AgentSQL
3
Saya tidak tahu mengapa saya menerima istilah itu aliasing. Istilah yang benar adalah qualifying. Berikut ini penjelasan yang lebih panjang dari Alex Kuznetzov . Tentang kueri tabel tunggal - ini adalah tabel tunggal sekarang . Tetapi kemudian, ketika bug ditemukan dan Anda mencoba untuk menahan banjir, klien gugup, Anda bergabung dengan meja lain hanya untuk menghadapi pesan kesalahan - pesan yang mudah dikoreksi, tetapi tidak pada saat berkeringat ini, serangan stroke kecil - dan Anda memperbaiki kesalahan mengingat tidak pernah meninggalkan kolom ...
Nikola Markovinović
1
Tidak bisa mengabaikannya sekarang. Terima kasih!! :)
AgentSQL
15
SELECT CASE WHEN EXISTS (SELECT TOP 1 *
                         FROM dbo.[YourTable] 
                         WHERE [YourColumn] = [YourValue]) 
            THEN CAST (1 AS BIT) 
            ELSE CAST (0 AS BIT) END

Pendekatan ini mengembalikan boolean untuk Anda.

Kris Coleman
sumber
1
Mungkin bisa menghilangkan pernyataan Top dan pernyataan * untuk membuatnya sedikit lebih cepat, karena Exist akan keluar setelah menemukan catatan, jadi kira-kira seperti ini: PILIH KASUS KETIKA ADA (PILIH 1 DARI Dbo. [Meja Anda] DI MANA [Kolom Anda] = [Nilai Anda]) LALU CAST (1 AS BIT) LAIN CAST (0 AS BIT) AKHIR
Stefan Zvonar
Saran ini gagal menyebutkan mengapa ini akan lebih cepat selama ada / tidak ada pernyataan yang ada di dalam SQL Server. Tanpa tolok ukur apa pun, saya akan kesulitan untuk percaya bahwa pernyataan kasus akan menghasilkan hasil yang lebih cepat daripada tanggapan benar / salah yang langsung.
Bonez024
8

Anda juga bisa menggunakan

 If EXISTS (SELECT 1 FROM dbo.T1 WHERE T1.Name='Scot')
    BEGIN
         --<Do something>
    END 

ELSE    
     BEGIN
       --<Do something>
     END
atik sarker
sumber
7

Jangan berpikir ada orang yang menyebutkannya, tetapi jika Anda yakin data tidak akan berubah di bawah Anda, Anda mungkin ingin juga menerapkan petunjuk NoLock untuk memastikannya tidak diblokir saat membaca.

SELECT CASE WHEN EXISTS (SELECT 1 
                     FROM dbo.[YourTable] WITH (NOLOCK)
                     WHERE [YourColumn] = [YourValue]) 
        THEN CAST (1 AS BIT) 
        ELSE CAST (0 AS BIT) END
Stefan Zvonar
sumber
3
SELECT COUNT(*) FROM products WHERE products.id = ?;

Ini adalah solusi basis data lintas relasional yang berfungsi di semua basis data.

anak nakal
sumber
6
Namun Anda memaksa db untuk loop atas semua catatan, sangat lambat pada meja besar
amd
@ Saya ingin menjelaskan alasannya?
UmNyobe
@amd komentar Anda masuk akal. Permintaan ini lebih merupakan TEMUKAN SEMUA daripada TEMUKAN APA PUN.
UmNyobe
1

Di bawah ini adalah cara termudah dan tercepat untuk menentukan apakah ada catatan dalam database atau tidak. Untung itu berfungsi di semua DB Relasional

SELECT distinct 1 products.id FROM products WHERE products.id = ?;
manish Prasad
sumber
0
create or replace procedure ex(j in number) as
i number;
begin
select id into i from student where id=j;
if i is not null then
dbms_output.put_line('exists');
end if;
exception
   when no_data_found then
        dbms_output.put_line(i||' does not exists');

end;
kiran
sumber
2
Mungkin kode Anda berfungsi dengan baik, tetapi akan lebih baik jika Anda menambahkan beberapa informasi tambahan sehingga lebih mudah dimengerti.
idmean
0

Saya telah menggunakan ini di masa lalu dan tidak memerlukan pemindaian tabel penuh untuk melihat apakah ada sesuatu. Ini sangat cepat ...

UPDATE TableName SET column=value WHERE column=value
IF @@ROWCOUNT=0
BEGIN
     --Do work
END             
Eric Parsons
sumber
0

Bagi mereka yang menemukan ini dari latar belakang MySQL atau Oracle - MySQL mendukung klausa LIMIT untuk memilih sejumlah catatan, sementara Oracle menggunakan ROWNUM.

Werner
sumber