2009-08-31 5 views
11

Aşağıdakine benzer bir seçim ifadesi yazmanın en etkili yolu nedir?"İçinde değil" alt sorgusuyla seçim deyimi yazmanın en etkili yolu nedir?

SELECT * 
FROM Orders 
WHERE Orders.Order_ID not in (Select Order_ID FROM HeldOrders) 

Öğe, öğe başka bir tabloda olmadığında kayıtların bir tablodan olmasını ister.

+5

En iyi yol çeşitli yaklaşımları denemek ve İcra Planlarını incelemektir. – pjp

+0

Benim durumumda SQL Server 2000, söz konusu tablolarda indeksler verildiğinde "Birleştir" sorgusu en hızlıydı. kadar * SEC * SOL O siparişler GELEN o.Order_ID = h.Order_ID üzerinde HeldOrders h artır ve h.Order_ID Bu – Stimy

cevap

7

"En verimli" tabloları boyutlarına bağlı olarak farklı olacak deneyin , dizinler, vb. Başka bir deyişle, kullandığınız özel duruma göre farklılık gösterecektir.

Durumunuza bağlı olarak, istediğiniz şeyi gerçekleştirmek için yaygın olarak kullandığım üç yol vardır.

1. Örnekler, Orders.order_id dizine eklendiğinde ve HeldOrders oldukça küçükse, iyi çalışır.

2. başka yöntem nerede fıkra

SELECT * 
FROM Orders o 
WHERE Orders.Order_ID not in (Select Order_ID 
           FROM HeldOrders h 
           where h.order_id = o.order_id) 

Not ekleme ... ne varsa hafif bir varyasyonu olan "korelasyon alt sorgu" dir. Bu, HeldOrders'ın çok sayıda satırı olduğunda daha iyi çalışma eğilimindedir. Order_ID'nin her iki tabloda da endekslenmesi gerekiyor.

3. olduğunda bazen kullanmak başka yöntem

SELECT * 
FROM Orders o 
left outer join HeldOrders h on h.order_id = o.order_id 
where h.order_id is null 

sol dış kullanarak katılmak, h.order_id o o.order_id eşleşen bir değere sahip olacak ... dış birleştirme bırakılır eşleşen bir satır. Eşleşen bir satır yoksa, h.order_id NULL olacaktır. Nerede neredeyse NULL değerlerini kontrol ederek bir eşleşme olmayan her şeyi filtreleyebilirsiniz.

Bu varyasyonların her biri, çeşitli senaryolarda daha fazla veya daha az verimli çalışabilir.

+0

'@ Dave': Neden' ​​'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' yerine '' '' '' '' '' '' nı kullanıyorsunuz? – Quassnoi

+1

@Quassnoi: Dürüst, muhtemelen kötü bir alışkanlık. Cevabınızı okuduktan sonra NOT EXISTS kullanmaya başlamayı planlıyorum. –

+0

Seçenek 3 benim senaryoda en iyi çalıştı (SQL Server 2000, tabloları dizinlerim verilen). En iyi cevabın bir dizi yöntemi test etmek olduğunu düşünüyorum. – Stimy

4

LEFT OUTER JOIN'u kullanabilir ve sağdaki tablo için NULL denetleyebilirsiniz. Yeni başlayanlar için

SELECT O1.* 
FROM Orders O1 
LEFT OUTER JOIN HeldOrders O2 
ON O1.Order_ID = O2.Order_Id 
WHERE O2.Order_Id IS NULL 
+1

boş * en etkili yöntemdir olmaktan. – Quassnoi

+0

Bu, mutlaka en verimli yöntem olmayacak. –

+0

Bir alt sorgudan önemli ölçüde daha etkilidir, ancak en azından bir kez/satır yerine, yalnızca ikinci tabloya karşı yürütülür. – SqlRyan

19

, (çok ve diğer sistemlerde) NOT IN yüklem SQL Server nasıl çalıştığı hakkında bloguma eski makalesi bağlantısı:


Aşağıdaki gibi yeniden yazabilirsiniz:

Bununla birlikte, çoğu veritabanları bu sorguları aynı şekilde ele alacaktır.

Bu iki sorgunun her ikisi de bir ANTI JOIN türünü kullanacaktır.

SELECT * 
FROM Orders o 
WHERE (col1, col2) NOT IN 
     (
     SELECT col1, col2 
     FROM HeldOrders ho 
     ) 

Not yolu o NULL davranır nedeniyle NOT IN zor olabileceğini, ancak,: Bu sözdizimini desteklemez SQL Server beri iki veya daha fazla sütun kontrol etmek istiyorsanız

Bu

SQL Server için yararlıdır değerler. Held.Orders null

, hiçbir kayıt bulunamadı ve alt sorgu döner ancak tek NULL, bütün sorgu hiçbir şey (hem IN ve NOT IN bu durumda NULL olarak değerlendirecektir) dönecektir.

Orders: 

OrderID 
--- 
1 

HeldOrders: 

OrderID 
--- 
2 
NULL 

Bu sorgu:

SELECT * 
FROM Orders o 
WHERE OrderID NOT IN 
     (
     SELECT OrderID 
     FROM HeldOrders ho 
     ) 

beklediğiniz değil muhtemelen şey, dönecektir

bu verileri göz önünde bulundurun. Ancak

, bu bir:

SELECT * 
FROM Orders o 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM HeldOrders ho 
     WHERE ho.OrderID = o.OrderID 
     ) 

OrderID = 1 bulunduğu satırı dönecektir.

Başkaları tarafından önerilen LEFT JOIN çözümlerinin en verimli çözüm olmaktan çok uzak olduğunu unutmayın.

Bu sorgu:

SELECT * 
FROM Orders o 
LEFT JOIN 
     HeldOrders ho 
ON  ho.OrderID = o.OrderID 
WHERE ho.OrderID IS NULL 

değerlendirilmesi ve Numerius olabilir satır uyan tüm filtrelemek için gereken bir filtre koşulu kullanır

hem IN ve EXISTS tarafından kullanılan bir ANTI JOIN yöntem olacak Sadece, Orders'daki her satır içinbir kaydın bulunmadığından emin olmanız gerekir, böylece ilk olarak tüm olası kopyaları ortadan kaldıracaktır: değerlendirirken 210

  • NESTED LOOPS ANTI JOIN ve MERGE ANTI JOIN sadece çiftleri atlayacak. HASH ANTI JOIN A karma tablosu oluştururken kopyaları ortadan kaldırır.
+1

İlk kez, 5 dakikadan daha kısa bir sürede girebildiğim ilişkili bir alt sorguya ihtiyaç duyulan ilişkili bir alt sorgu gördüm. Bu hileyi * yıllar önce biliyordum. –

+0

'@Philip Kelley': tam olarak hangi numara? – Quassnoi

+0

Bu bölümde ne demek istiyorsun: "SQL Server bu sözdizimini desteklemediğinden, iki veya daha fazla sütunu kontrol etmek istiyorsanız, bu SQL Server için kullanışlıdır:". Bunun SQL Server'a uygulanmadığını mı söylüyorsunuz? Bir "eksik" eksik misin? – Stimy

1

Ben en verimli ne olduğundan emin değilim, ama diğer seçenekleri şunlardır:

1. Use EXISTS 

SELECT * 
FROM ORDERS O 
WHERE NOT EXISTS (SELECT 1 
        FROM HeldOrders HO 
        WHERE O.Order_ID = HO.OrderID) 

2. Use EXCEPT 

SELECT O.Order_ID 
FROM ORDERS O 
EXCEPT 
SELECT HO.Order_ID 
FROM HeldOrders 
0

SELECT * 
FROM Orders 
LEFT JOIN HeldOrders 
ON HeldOrders.Order_ID = Orders.Order_ID 
WHERE HeldOrders.Order_ID IS NULL 
İlgili konular