SQL WHERE yan tümcesi kısa devre değerlendirildi mi?


142

SQL WHERE yan tümcelerinde boole ifadeleri kısa devre olarak değerlendiriliyor mu?

Örneğin:

SELECT * 
FROM Table t 
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key) 

Eğer @key IS NULL true değerlendirir olduğunu @key VE @key = t.Key IS NOT NULL Değerlendirilen?

Hayır ise neden olmasın?

Evet ise garanti edilir mi? ANSI SQL'in bir parçası mı yoksa veritabanına özgü mü?

Veritabanına özgü ise, SqlServer? Oracle? MySQL?


@Key yan tümcesi NULL NOT NOT gereksiz değil mi? LHS'deki @key IS NULL deyimi bu sorunla ilgileniyor mu?
harcı

10
@splender - sorunun cevabına bağlıdır
Greg Dean

@Greg: Harcamaya katılıyorum. Kısa devre yapmanın eksikliğini veya varlığını herhangi bir fark yarattığını görmüyorum. @Key NULL ise, @key = t.Anahtar her zaman false döndürür, NULL! = NULL olarak (bu nedenle IS NULL kullanıyoruz).
Michael Madsen

14
@Michael and @spender - Sorunun amacı ikinci durumun değerlendirilip değerlendirilmemesidir. Sorunun amacı, mümkün olan en az sayıda karakterle yazılmış bu SQL ifadesidir. Daha karmaşık örneklerde, şüphesiz önemliydi, sanki nerede kısa devre nerede, aksi takdirde hatalı olabilecek ifadeler yazabilirsiniz.
Greg Dean

2
Kısa devre, koşulları soldan sağa değerlendirme anlamına gelir. WHERE a = 1 AND b = 2Veritabanı motorunun önce b = 2 olduğu tüm satırları bulması verimli olabilir gibi bir koşul göz önüne alındığında , a = 1'e filtre uygulayın. Eğer garanti isterseniz optimizasyon işe yaramaz hale gelir.
Salman A

Yanıtlar:


72

ANSI SQL Taslak 2003 5WD-01-Çerçeve-2003-09.pdf

6.3.3.3 Kural değerlendirme sırası

[...]

Önceliğin Biçimler veya parantez tarafından belirlenmediği durumlarda, ifadelerin etkili değerlendirmesi genellikle soldan sağa doğru yapılır. Ancak, öyle uygulaması bağımlıdır işlenenler veya operatörler koşullar çıkarılmasına neden olabilir zaman ifadeleri aslında özellikle soldan sağa değerlendirilir olup olmadığını ya da ifadelerin sonuçları tamamen ifadesi tüm bölümlerini değerlendirilmeden belirlenebilir eğer.


4
Uygulama bağımlı? Harika. Bilmek de güzel. En azından CASEkısa devre.
dakab

3
Bu, ifade değerlendirmelerinin kötü tanımlandığı anlamına gelmez mi? "(0 = 0 VEYA NULL)", tüm terimler değerlendirilirse her zaman NULL olur, soldan sağa ve kısa devre değerlendirilirse her zaman doğrudur.
user48956

7
SQL bildirimsel bir dildir, temel olarak kontrol akışını açıklamadan hesaplamanın mantığını ifade eder; bu da kısa devre değerlendirmesinin zorunlu tarzı ve sonuçlarıyla çelişiyor.
Jorge Garcia

@JorgeGarcia hakkında böyle düşünmemiştim. Kısa devre değerlendirmesi dolaylı olarak operasyonlar için bir siparişi zorlar. Bu muhtemelen ince bir sorunun kökünde bazı kod ile güreş. İçgörü için teşekkürler.
Carnot Antonio Romero

58

Yukarıdan, kısa devre gerçekten mevcut değildir.

İhtiyacınız varsa, bir Case ifadesi öneririm:

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1Her zaman değerlendirilir, ancak sadece bir tanesidir Expr2ve Expr3satır başına değerlendirilecektir.


3
Bu, varsaydığım RDBMS uygulamasına bağlıdır. En azından SQL Server için, bu davranışı göstermediği belgelenen en az bir istisna vardır (yani kısa devre); cf CASE (Transact-SQL) - Açıklamalar . Ben bu davayı alıntı bu cevabı ben soru üzerine verdiği NEREDE koşulların Açık emir - Sql? .
TT.

1
Durum ifadesi , ifade değil.
jarlh

19

Sanırım bu üç nedenden ötürü kısa devre yapmamış gibi yazdığım durumlardan biri.

  1. Çünkü MSSQL için, BOL'a bariz bir yerde bakarak çözümlenmedi, bu yüzden benim için kanonik olarak belirsiz.

  2. çünkü en azından kodumu çalışacağını biliyorum. Ve daha da önemlisi, benden sonra gelenler de öyle olacak, bu yüzden onları aynı soru üzerinde tekrar tekrar endişelenmeye ayarlamıyorum.

  3. Birkaç DBMS ürünü için yeterince sık yazıyorum ve kolayca çalışabilsem farklılıkları hatırlamak istemiyorum.


4
Büyük öneri. Bu soruyu cevaplamıyor, ama büyük bir pragmatik bakış açısı. yani +1
Greg Dean

12

SQL Server (2005) kısa devre garanti olduğunu inanmıyorum. SQL Server, sorgunuzu etkili bir yürütme planı bulmak için birçok şeyi (dizinler, istatistikler, tablo boyutu, kaynaklar, vb.) Dikkate alan optimizasyon algoritması aracılığıyla çalıştırır. Bu değerlendirmeden sonra kısa devre mantığınızın garanti edildiğinden emin olamazsınız.

Aynı soruyu bir süre önce kendimle de karşılaştım ve araştırmam gerçekten kesin bir cevap vermedi. Size çalıştığına dair bir kanıt hissi vermek için küçük bir sorgu yazabilirsiniz, ancak veritabanınızdaki yük arttıkça, tabloların daha da büyüyeceğinden ve veritabanında bir şeyler optimize edildiğinden ve değiştiğinden emin olabilirsiniz. ambar. Dikkatli davranamadım ve bu yüzden hata yaptım ve kısa devreyi sağlamak için WHERE yan tümcesinde CASE kullandım.


7

Veritabanlarının nasıl çalıştığını aklınızda bulundurmalısınız. Parametreli bir sorgu verildiğinde, db, parametrelerin değerleri olmadan bu sorguya dayalı bir yürütme planı oluşturur. Bu sorgu, sağlanan gerçek değerlerin ne olduğuna bakılmaksızın sorgu her çalıştırıldığında kullanılır. Belirli değerlere sahip sorgu kısa devrelerinin yürütme planı için önemli olup olmayacağı.


6
yürütme hızı için önemlidir!
user4951

Şu anda bu şekilde çalışması, değiştirilemeyeceği anlamına gelmez. Modeli / anlambilimi uygulamadan ayırmak zorundayız. Yürütme planları, sorguların yürütülmesini optimize etmek için dahili olarak uygulanır ... ve kısa devre semantiği, yalnızca SQL'in bildirici doğasıyla çelişmekle kalmaz, aynı zamanda bu optimizasyonları da kısıtlayabilir. Ancak, kısa devre değerlendirme semantiği DBMS tarafından desteklenecek olsaydı, yürütme planlarının uygulanması bu semantiği desteklemek için değişecektir.
Jorge Garcia

3

Bunu genellikle isteğe bağlı parametreler için kullanırım. Bu kısa devre ile aynı mıdır?

SELECT  [blah]
FROM    Emp
WHERE  ((@EmpID = -1) OR (@EmpID = EmpID))

Bu bana -1 veya bir özelliğin isteğe bağlı kontrolü için açıklanacak herhangi bir şeyi iletme seçeneği sunar. Bazen bu birden fazla tabloya veya tercihen bir görünüme katılmayı içerir.

Çok kullanışlı, db motoruna verdiği ekstra işten tamamen emin değilim.


2

SQL Server için, sürüme bağlı olduğunu düşünüyorum ama SQL Server 2000 ile yaşadığım deneyim @key null olsa bile @key = t.Key değerlendirir. Başka bir deyişle, WHERE yan tümcesini değerlendirirken etkili kısa devre yapmaz.

Kullanıcıların çeşitli kriterler girebileceği veya giremeyeceği esnek bir sorgu yapmanın bir yolu olarak örneğiniz gibi bir yapı öneren kişilerin gördüm. Gözlemim, @key null olduğunda Key'in sorgu planında yer alması ve Key indekslenmesi durumunda endeksi etkin bir şekilde kullanmamasıdır.

Değişken ölçütlere sahip bu tür esnek sorgu muhtemelen dinamik olarak oluşturulan SQL'in gerçekten en iyi yol olduğu bir durumdur. @Key boşsa, sorguyu hiç eklemezsiniz.



1

Kısa devre değerlendirmesinin temel özelliği, sonuç tespit edilir edilmez ifadeyi değerlendirmeyi durdurmasıdır. Bu, ifadenin geri kalanı göz ardı edilebileceği anlamına gelir, çünkü sonuç değerlendirilip değerlendirilmesin de aynı olacaktır.

İkili boole işleçleri sayısaldır, yani:

a AND b == b AND a
a OR  b == b OR  a
a XOR b == b XOR a

bu nedenle değerlendirme sırası için bir garanti yoktur. Değerlendirme sırası sorgu optimize edici tarafından belirlenecektir.

Nesneleri olan dillerde, yalnızca kısa devre değerlendirmesi ile değerlendirilebilen boole ifadeleri yazabileceğiniz durumlar olabilir. Örnek kod yapınız genellikle bu dillerde kullanılır (C #, Delphi, VB). Örneğin:

if(someString == null | someString.Length == 0 )
  printf("no text in someString");

Bu C # örneği, someString == nulltam olarak değerlendirileceğinden istisnaya neden olur . Kısa devre değerlendirmesinde, her zaman çalışacaktır.

SQL yalnızca başlatılmayan skaler değişkenlerde (nesne yok) çalışır, bu nedenle değerlendirilemeyen boole ifadesi yazmanın bir yolu yoktur. Bazı NULL değeriniz varsa, herhangi bir karşılaştırma false değerini döndürür.

Bu, SQL'de kısa devre veya tam değerlendirmeye bağlı olarak farklı değerlendirilen ifade yazamayacağınız anlamına gelir.

SQL uygulaması kısa devre değerlendirmesi kullanıyorsa, yalnızca sorgu yürütmeyi hızlandırabilir.


1
Evet, boole operatörleri değişmeli. Nesnelerin onunla bir ilgisi olmadığını (ya da olmadığını) sanmıyorum.
Greg Dean

1

kısa devre hakkında bilmiyorum, ama if-else deyimi olarak yazmak istiyorum

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

     SELECT * 
     FROM Table t 
     WHERE t.Key=@key

end

ayrıca, değişkenler her zaman denklemin sağ tarafında olmalıdır. bu onu huysuz yapar.

http://en.wikipedia.org/wiki/Sargable


1
Herkes sağdaki değişkenler hakkında destekleyebilir mi? Nedense buna inanmakta zorlanıyorum.
Greg Dean


Makaleyi anladığım gibi. Sütun adlarındaki işlevlerin anlaşılmaz olmaması hakkında konuşuyor. Hangi anlıyorum. Ancak, (A = @a) veya (@a = A) önemli olduğunu düşünmüyorum.
Greg Dean

yanlış olabilirim. zaten yoksa iyi bir soru olabilir.
DForck42

1

SQL Server 2008 R2'deki hızlı ve kirli bir testin altında:

SELECT *
FROM table
WHERE 1=0
AND (function call to complex operation)

Bu hemen kayıt olmadan geri döner. Bir tür kısa devre davranışı mevcuttu.

Sonra bunu denedim:

SELECT *
FROM table
WHERE (a field from table) < 0
AND (function call to complex operation)

hiçbir kaydın bilinmemesi bu koşulu karşılayamaz:

(a field from table) < 0

Bu, birkaç saniye sürdü ve kısa devre davranışının artık olmadığını ve karmaşık işlemin her kayıt için değerlendirildiğini gösterdi.

Umarım bu çocuklar yardımcı olur.


1
Benim tahminim, ilk sorgu planın gerçekte başlamadan önce derleme zamanında "kısa devre" oldu.
Louis Somers

1

MySQL'in WHERE yan tümcesi kısa devre yaptığını kanıtlayan bir demo :

http://rextester.com/GVE4880

Bu, aşağıdaki sorguları çalıştırır:

SELECT myint FROM mytable WHERE myint >= 3 OR myslowfunction('query #1', myint) = 1;
SELECT myint FROM mytable WHERE myslowfunction('query #2', myint) = 1 OR myint >= 3;

Bunlar arasındaki tek fark, OR koşulundaki işlenenlerin sırasıdır.

myslowfunctionkasıtlı olarak bir saniye uyur ve her çalıştırıldığında bir günlük tablosuna giriş eklemenin yan etkisi vardır. Yukarıdaki iki sorguyu çalıştırırken günlüğe kaydedilenlerin sonuçları şunlardır:

myslowfunction called for query #1 with value 1
myslowfunction called for query #1 with value 2
myslowfunction called for query #2 with value 1
myslowfunction called for query #2 with value 2
myslowfunction called for query #2 with value 3
myslowfunction called for query #2 with value 4

Yukarıdaki, yavaş bir işlevin, diğer işlenen her zaman doğru olmadığında (kısa devre nedeniyle) bir OR koşulunun sol tarafında göründüğünde daha fazla yürütüldüğünü gösterir.


4
Hmm muhtemelen ne demek istediğini "İşte MySQL bu örnekte WHERE yan tümcesi kısa devre yaptığını kanıtlamak için bir demo :"
TT.

1
Elbette - bunun olabileceğinin bir kanıtı.
Steve Chambers

0

Bu sorgu analizörü fazladan 4 saniye sürer, bu yüzden görebildiğim kadarıyla bile IF kısa değil ...

SET @ADate = NULL

IF (@ADate IS NOT NULL)
BEGIN
    INSERT INTO #ABla VALUES (1)
        (SELECT bla from a huge view)
END

Garantili bir yol olması güzel olurdu!


-2

MS Sql sunucusunun, gereksiz kontrollerden kaçınarak performansı artırmak için Kısa devre teorisini desteklediği açıktır.

Destekleyici Örnek:

SELECT 'TEST'
WHERE 1 = 'A'

SELECT 'TEST'
WHERE 1 = 1 OR 1 = 'A'

Burada ilk örnek, 'A' varchar değeri veri türü int'e dönüştürülürken dönüşüm başarısız oldu 'hatasıyla sonuçlanır.

İkincisi 1 = 1 koşulu TRUE olarak değerlendirildiğinden kolayca çalışır ve bu nedenle ikinci koşul hiç çalışmaz.

Daha fazlası

SELECT 'TEST'
WHERE 1 = 0 OR 1 = 'A'

burada ilk koşul yanlış olarak değerlendirilir ve bu nedenle DBMS ikinci koşul için gider ve yine yukarıdaki örnekte olduğu gibi dönüştürme hatası alırsınız.

NOT: HATA KOŞULLARINI, HATA DÜZENLENMİŞ DURUMUNUN YÜRÜTÜLMESİ, KISA DEVRE DIŞI BIRAKMA DURUMUNDA YÜRÜRLÜĞE VEYA KISA DEVREYE ALMAK GEREKEN SADECE HÜKÜMLÜ KOŞULUYORUM.

BASİT AÇIKLAMA

Düşünmek,

WHERE 1 = 1 OR 2 = 2

ilk koşul TRUE olarak değerlendirilirken, ikinci koşulu değerlendirmek anlamsızdır, çünkü hangi değerde olursa olsun değerlendirilmesi sonucu etkilemez, bu nedenle Sql Server'ın gereksiz koşul kontrolünü veya değerlendirmesini atlayarak Sorgu Yürütme zamanından tasarruf etmesi için iyi bir fırsat .

durumunda "VEYA" ilk koşulu ise değerlendirilir eğer TRUE ile bağlı tüm zinciri "VEYA" başkalarını değerlendirilmeden true değerlendirilen olarak kabul ederim.

condition1 OR condition2 OR ..... OR conditionN

koşul1 doğru olarak değerlendirilirse, koşulN atlanana kadar tüm koşulları dinlendirin. İlk TRUE'nun belirlenmesinde genelleştirilmiş kelimelerde, OR ile bağlantılı diğer tüm koşullar atlanır.

İkinci koşulu düşünün

WHERE 1 = 0 AND 1 = 1

ilk koşul FALSE olarak değerlendirilirken ikinci koşulu değerlendirmek anlamsızdır, çünkü hangi değerde olursa olsun değerlendirilmesi sonucu etkilemez, bu nedenle Sql Server'ın gereksiz koşul kontrolünü veya değerlendirmesini atlayarak Sorgu Yürütme zamanından tasarruf etmesi için iyi bir fırsat .

durumunda "AND" ilk koşulu ise değerlendirilir eğer FALSE ile bağlı tüm zinciri "AND" başkalarını değerlendirilmeden YANLıŞ olarak değerlendirilen olarak kabul ederim.

condition1 AND condition2 AND ..... conditionN

koşul1 için değerlendirilir eğer FALSE , kadar tüm koşullar dinlenme conditionN atlanır olurdu. İlk YANLIŞ'ın belirlenmesindeki genel kelimelerle, AND ile bağlantılı tüm diğer koşullar atlanır.

BU NEDENLE, BİR BİLİŞİM PROGRAMCISI HER ZAMAN KOŞULLARIN ZİNCİRİNİ KADAR DAHA AZ DÜŞÜK VEYA EN ÇOK KALDIRICI KOŞULLARIN DEĞERLENDİRİLMESİNİ GERÇEKLEŞTİRMELİ VEYA KOŞULU DAHA AZ ŞEKİLDE GERÇEKLEŞTİRMEK GEREKİR.


Nedeni azaltma: her zaman gerçek bir sunucudaki şeyleri gerçekçi verilerle test edin. Önceki yorumumun yenildiği anlaşılıyor.
Yasemin
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.