Daha verimli olan, nerede bir cümle veya milyon artı satır tablosuyla birleştirme?


17

Bir tabloda 250MM satır içeren bir web sitesi çalıştırıyoruz ve çoğu sorgu için katıldığımız başka bir tabloda 15MM satırların hemen altında.

Örnek yapılar:

MasterTable (Id, UserId, Created, Updated...) -- 15MM Rows
DetailsTable (Id, MasterId, SomeColumn...) -- 250MM Rows
UserTable (Id, Role, Created, UserName...) -- 12K Rows

Tüm bu tablolara karşı düzenli olarak birkaç sorgu yapmak zorundayız. Biri, ücretsiz kullanıcılar (~ 10 bin ücretsiz kullanıcı) için istatistikleri kapmaktır.

Select Count(1) from DetailsTable dt 
join MasterTable mt on mt.Id = dt.MasterId 
join UserTable ut on ut.Id = mt.UserId 
where ut.Role is null and mt.created between @date1 and @date2

Sorun, bu sorgunun, birleşme yerlerinden çok önce gerçekleşmesi nedeniyle bazen çok uzun bir süre çalışacağıdır.

Bu durumda, birleşimler yerine nereye gitmek daha akıllıca olur where column in(...)mu?


1
Hangi veritabanı ve sürüm?
Leigh Riffel

2
her iki yolu denedin mi
gbn

Bu Oracle olsaydı ben NVL2 (Rol, NULL, ID) üzerinde UserTable için fonksiyon tabanlı bir dizin oluşturmak istiyorum, ama bu başka bir DB gibi görünüyor.
Leigh Riffel

Yanıtlar:


20

Modern RDBMS için "açık JOIN" ve "NEREDE BİRLEŞİN" arasında (tüm JOINS INNER ise) performans ve sorgu planı açısından hiçbir fark yoktur.

Açık JOIN sözdizimi daha net ve daha az belirsiz (aşağıdaki bağlantılara bakın)

Şimdi, NEREDEN BİRLEŞTİR, gerçek işleme değil mantıksal işlemdir ve modern optimize ediciler bunu gerçekleştirmek için yeterince zekidir.

Buradaki sorununuz büyük olasılıkla dizine ekleniyor.

Lütfen bu tablolardaki tüm dizinleri ve anahtarları bize gösterin. Ve sorgu planları

Not: Bu soru StackOverflow'da şu ana kadar kopya olduğu için yakın olurdu ... COUNT (1) vs COUNT (*) de başka bir baskın efsanedir.


2
joinVe wherecümle arasında hiçbir fark olmaması DAİMA DOĞRU DEĞİLDİR . Uzun süren sorguları her zaman optimize ederim ve bazen whereyan tümce kullanan sorgular join70x'e kadar bir faktör tarafından kullanılanlardan daha iyi performans gösterir. Eğer bu kadar basit ve anlaşılır olsaydı, hayat tüm gökkuşağı ve tek boynuzlu atlar olurdu. Ve bu bazı eski belirsiz motorlarla ilgili değil - şu anda whereSQL 2012'deki maddenin 70x avantajına bakıyorum .
ajeh

Dahası, genellikle her iki yaklaşımdan da aynı planları gözlemliyorum ve sorguların tam olarak aynı whereperformansı sergilediğini izole ediyorum, ancak yan tümce sorgusunun bir parçası olması gerekiyorsa, büyük bir aralıkta olması gerekiyorsa, joinsorguyu büyük bir farkla geride bırakıyor. SQL sorguları vakumda yürütülmez - sunucu yükünün geri kalanından etkilenirler ve genellikle whereyan tümce sorguları oldukça iyi çalışır, çünkü joinsözdizimi gerçekten daha temizdir.
ajeh

3
@ajeh: Deneyiminizin çok tipik olmadığını öneririm.
X70

5

Sorguyu tamamen yeniden gözden geçirmelisiniz

WHERE yan tümcelerini daha erken ve JOIN'leri daha sonra gerçekleştirmeyi deneyin

Select Count(1) from DetailsTable dt
join (Select UserId,Id FROM MasterTable where
created between @date1 and @date2) mt on mt.Id = dt.MasterId 
join (Select Id FROM UserTable WHERE Role is NULL) ut
on ut.Id = mt.UserId;

Bu yeniden düzenlenmiş sorguda bir EXPLAIN planı çalıştırsanız ve orijinalinizin daha kötü görünse bile, yine de deneyin. Dahili olarak oluşturulan geçici tablolar kartezyen birleşimler gerçekleştirir, ancak bu tablolarla çalışmak daha küçüktür.

Bu fikri bu YouTube videosundan aldım .

StackOverflow'da çok karmaşık bir soruda videodan ilkeleri denedim ve 200 puanlık bir ödül aldım.

@gbn, doğru dizinlere sahip olduğunuzdan emin olarak bahsetti. Bu durumda, lütfen oluşturulan sütunu MasterTable'da dizine ekleyin.

Bir şans ver !!!

GÜNCELLEME 2011-06-24 22:31 EDT

Bu sorguları çalıştırmalısınız:

SELECT COUNT(1) AllRoles FROM UserTable;
SELECT COUNT(1) NullRoles FROM UserTable WHERE Role is NULL;

NullRoles X 20 <AllRoles ise (diğer bir deyişle, NullRoles tablo satırlarının% 5'inden azsa), UserTable'daki Rolü benzersiz olmayan bir dizin oluşturmalısınız. Aksi takdirde, Sorgu Optimize Edici muhtemelen bir dizin kullanarak devre dışı bırakabileceğinden, UserTable'ın tam bir tablosu yeterli olacaktır.

GÜNCELLEME 2011-06-25 12:40 EDT

Bir MySQL DBA olduğum için, bir şeyler yapma yöntemim olumlu kötümserlik ve muhafazakar olmak yoluyla MySQL Sorgu Optimize Edici'ye güvenmemeyi gerektirir. Bu nedenle, bir sorguyu yeniden düzenlemeyi veya MySQL Sorgu Optimize Edici'nin gizli kötü alışkanlıklarının önüne geçmek için gerekli kaplama dizinleri oluşturmayı deneyeceğim. @ gbn yanıt daha SQL Server sorguları değerlendirme daha "akıl sağlamlığı" olabilir daha eksiksiz gibi görünüyor.


0

Biz 75M satır hakkında bir [Detay] tablo vardı; 400K sıra civarında bir [Ana] tablo ve her zaman ve sonsuza dek 7 sıra içeren ilgili bir [Item] tablosu. Küçük “Öğe numaraları” (1-7) kümesini sakladı ve milyonlarca her ay basılan ve dağıtılan bir kağıt formu modelliyordu. En hızlı sorgu, Kartezyen Birleşmenin kullanımını içeren, ilk önce en az düşüneceğiniz sorudur. IIRC, şöyle bir şeydi:

SELECT m.order_id, i.line_nr, d.Item_amt
FROM Master m, Item i 
INNER JOIN Detail d ON m.order_id = d.order_id

[Item] ve [Detail] arasında mantıklı bir “id” bağlantısı olmasına rağmen, CROSS JOIN INNER JOIN'dan daha iyi çalıştı.

RDBMS, MPP teknolojisi ve IDR ile indeksleme şemasının ne olduğu Teradata idi. TABLO TARAMA her zaman en iyiyi gerçekleştirdiğinden, 7 satırlı tablonun dizini yoktu.

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.