Kaydın var olup olmadığını belirlemenin en hızlı yolu


143

Başlıktan da anlaşılacağı gibi ... Tabloda bir kayıt olup olmadığını belirlemek için en az yük ile en hızlı yolu anlamaya çalışıyorum.

Örnek sorgu:

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 = ?;

Say ?ile takas 'TB100'... hem birinci ve ikinci sorgular (... diyelim ki aynı sonucu dönecektir 1bu konuşma için). Son sorgu 'TB100'beklendiği gibi döner veya idtabloda yoksa hiçbir şey döndürmez .

Amaç, idtabloda olup olmadığını anlamaktır. Değilse, program daha sonra kaydı ekler, eğer öyleyse, program bu kaydı atlar veya bu sorunun kapsamı dışındaki diğer program mantığına dayalı bir UPDATE sorgusu gerçekleştirir.

Hangisi daha hızlı ve daha az yükü var? (Bu, her program çalışması için on binlerce kez tekrarlanacaktır ve günde birçok kez çalıştırılacaktır).

(Bu sorguyu M $ sağlanan JDBC sürücüsü aracılığıyla Java'dan M $ SQL Server'a karşı çalıştırmak)


1
Bu veritabanına bağlı olabilir. Örneğin, Postgres'e güvenmek oldukça yavaş.
Mike Christensen

Üzgünüz, bu Java j $ bdc sürücüsü üzerinden M $ SQL konuşuyor. OP'mi güncelleyeceğim.
SnakeDoc


@Nikola Markovinović: bu durumda nasıl kullanırdın?
zerkms

5
@zerkms Bağlama bağlıdır. Saklı yordamda ise if exists(select null from products where id = @id); doğrudan bir istemci tarafından çağrılan bir sorgudaysa select case when exists (...) then 1 else 0 end.
Nikola Markovinović

Yanıtlar:


170

SELECT TOP 1 products.id FROM products WHERE products.id = ?; ilk kaydı bulduktan sonra yürütmeyi sona erdireceği için tüm önerilerinizden daha iyi performans gösterir.


5
PK (veya başka bir benzersiz anahtar) üzerinden arama yaparken optimize edici bunu dikkate almıyor mu?
zerkms

3
O, bunun PK olduğunu belirtti, ancak eğer öyleyse, evet, optimize edici bunu dikkate alacaktı.
Declan_K

3
@Declan_K: Sihirli kürem bu durumda başarısız gibi görünüyor ve idPK değil başlıklı bir sütun . Yani tavsiyene +1.
zerkms

4
PK değilse, bu sütunda bir dizin olduğundan emin olmanızı da öneririm. Aksi takdirde, sorgunun daha hızlı bir tablo araması yerine bir tablo taraması yapması gerekir.
CD Jorgensen

4
Sanırım bu konuda @ nenad-zivkovic cevabını düşünmeliyiz.
Giulio Caccin

193

EXISTS(veya NOT EXISTS) bir şeyin var olup olmadığını kontrol etmek için özel olarak tasarlanmıştır ve bu nedenle en iyi seçenek olmalıdır (ve olmalıdır). Eşleşen ilk satırda durur, bu nedenle bir TOPcümle gerektirmez ve aslında herhangi bir veri seçmez, bu nedenle sütun boyutunda ek yük olmaz. SELECT *Burada güvenle kullanabilirsiniz - farklı değil SELECT 1, SELECT NULLveya SELECT AnyColumn... (gibi geçersiz bir ifade bile kullanabilirsiniz SELECT 1/0ve kırılmaz) .

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

bunun önce SELECT ifadesini yürütmesi, ardından IF EXISTS ifadesini yürütmesi gerekmez ... ek ek yüke ve dolayısıyla daha fazla işlem süresine neden olur mu?
SnakeDoc

7
@SnakeDoc No. öyle bir şekilde Existsçalışır selectki, bir sıra bulunur bulunmaz çıkar. Dahası, yalnızca kayıttaki varlığın değerini not eder, kayıttaki gerçek değerleri değil, satırı diskten yükleme ihtiyacını kaydeder (arama kriterlerinin endekslendiği varsayılırsa, elbette). Yükü gelince if- bu minik zamanı yine de harcamanız gerekecek.
Nikola Markovinović

1
@ NikolaMarkovinović ilginç nokta. Bu alanda bir Dizin olup olmadığından emin değilim ve yeni SQL'im nasıl bulunacağını bilmiyor. JDBC aracılığıyla Java bu DB ile çalışıyorum ve veritabanı uzaktan bir yerde bir colo bulunur. Ben sadece her tablo, türleri ve herhangi bir FK veya PK's hangi alanların detayları sadece bir "veritabanı özeti" sağlandı. Bu bir şeyi değiştirir mi?
SnakeDoc

3
@SnakeDoc Yabancı anahtarlar ve dizinler dahil tablo yapısı hakkında bilgi edinmek için sp_help table_name komutunu çalıştırın . Dizinler, select topveya kullanılırken bir çok satırdan birkaç satır alındığında önemlidir exists; eğer mevcut değilse sql motor tablo taraması yapmak zorunda kalacak. Bu en az istenen tablo arama seçeneğidir. Dizin oluşturma yetkiniz yoksa, diğer taraftaki teknik personelle otomatik olarak ayarlanıp ayarlanmadığını veya dizin önermenizi beklediklerini öğrenmek için iletişim kurmanız gerekir.
Nikola Markovinović

1
@Konstantin Şunun gibi bir şey yapabilirsinizSELECT CASE WHEN EXISTS(..) THEN 1 ELSE 0 END;
Nenad Zivkovic

22

Hiçbir şey yenemez -

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

Tabloda veri olup olmadığını bilmek için saymanıza gerek yoktur. Ve gerekli olmadığında takma ad kullanmayın.


5
Adına rağmen idbirincil anahtar değildir. Yani, almadıkları halde sayma hala tüm eşleşen kayıtları, bunların muhtemelen binlerce bulmalıyız. Takma ad hakkında - kod devam eden bir çalışmadır. Ne zaman geri dönmen gerektiğini asla bilemezsin. Örtüşme, aptal çalışma zamanı hatalarını önlemeye yardımcı olur; örneğin, bir takma adı gerekmeyen benzersiz sütun adı artık benzersiz değildir, çünkü biri başka bir birleştirilen tabloda aynı adda bir sütun oluşturmuştur.
Nikola Markovinović

Evet, kesinlikle haklısın. Takma ad çok yardımcı olur, ancak birleştirme kullanılmadığında herhangi bir fark yarattığını düşünmüyorum. Bu yüzden, eğer gerekli değilse kullanmayın dedim. :) Ve burada varlığı kontrol etme konusunda uzun bir tartışma bulabilirsiniz . :)
AgentSQL

3
Bu terimi neden kabul ettiğimi bilmiyorum aliasing. Doğru terim qualifying. İşte Alex Kuznetzov'un daha uzun açıklaması . Tek tablo sorguları hakkında - şimdi tek tablo . Ama daha sonra, hata keşfedildiğinde ve sel tutmaya çalıştığınızda, istemci gergin, sadece hata mesajıyla yüzleşmek için başka bir masaya katılırsınız - kolayca düzeltilebilir mesaj, ancak bu terli anda küçük bir vuruş grev yapar - ve bir sütunu asla bırakmamayı hatırlama hatası ...
Nikola Markovinović

1
Şimdi görmezden gelemiyorum. Teşekkürler!! :)
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

Bu yaklaşım sizin için bir boole döndürür.


1
Muhtemelen Top ifadesini ve * ifadesini biraz daha hızlı hale getirmek için atlayabilir, çünkü Exist bir kayıt bulduktan sonra çıkacaktır, şöyle bir şey: VAR OLDUĞUNDA DURUM SEÇİN (dbo'dan 1 SEÇİN. [YourTable] NEREDE [Sütununuz] = [Değeriniz]) SONRA DÖKÜM (1 BIT AS) BAŞKA DÖKÜM (BIT AS 0) END
Stefan Zvonar

Bu öneri, neden SQL Server içindeki yerleşik var / yok ifadeleri üzerinde daha hızlı olacağını belirtmemektedir. Herhangi bir kıyaslama olmadan, bir vaka ifadesinin hemen doğru / yanlış yanıttan daha hızlı bir sonuç alacağına inanmak zor olurdu.
Bonez024

8

Ayrıca kullanabilirsiniz

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

ELSE    
     BEGIN
       --<Do something>
     END

7

Henüz kimsenin bahsetmediğini düşünmeyin, ancak verilerin altında değişmeyeceğinden eminseniz, okurken engellenmediğinden emin olmak için NoLock ipucunu da uygulamak isteyebilirsiniz.

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

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

Bu, tüm veritabanlarında çalışan çapraz ilişkisel veritabanı çözümüdür.


7
Ancak büyük tablolarda çok yavaş, tüm kayıtları üzerinde döngü db zorlamak
amd

@amd neden açıklamak ister misiniz?
UmNyobe

@ yorumunuz tam anlamıyla. Bu sorgu HERHANGİ BİR BUL daha fazla bir BUL BUL.
UmNyobe

1

Aşağıda, bir kaydın veritabanında olup olmadığını belirlemenin en basit ve en hızlı yolu Tüm İlişkisel DB'lerde işe yarar İyi bir şey

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

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;

2
Muhtemelen kodunuz harika çalışıyor, ancak daha fazla anlaşılabilir olması için bazı ek bilgiler eklerseniz daha iyi olur.
idmean

0

Bunu geçmişte kullandım ve bir şey olup olmadığını görmek için tam bir tablo taraması gerektirmez. Süper hızlı ...

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

0

MySQL veya Oracle geçmişinden gelenler için - MySQL, sınırlı sayıda kayıt seçmek için LIMIT yantümcesini desteklerken, Oracle ROWNUM kullanır.

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.