Bir JOIN koşulu ile WHERE koşulu arasında bir yürütme farkı var mı?


17

Bu iki örnek sorgu arasında bir performans farkı var mı?

Sorgu 1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

Sorgu 2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

Tek fark, ek koşulun yerleştirilmesidir; birincisi bir WHEREcümle kullanır ve ikincisi koşulu cümleye ekler ON.

Bu sorguları Teradata sistemimde çalıştırdığımda, açıklama planları aynıdır ve JOIN adımı her durumda ek koşulu gösterir. Bununla birlikte, MySQL ile ilgili bu SO sorusunda , cevaplardan biri WHERE, birleştirmeler yapıldıktan sonra işlem gerçekleştiği için ikinci stilin tercih edildiğini ileri sürdü .

Bu tür sorguları kodlarken genel bir kural var mı? Açıkçası benim veritabanı üzerinde hiçbir fark yapar çünkü platform bağımlı olması gerektiğini tahmin ediyorum, ama belki de bu sadece Teradata bir özelliktir. O eğer olduğunu platformu bağımlı, birkaç dokümantasyon başvuruları almak için çok istiyorum; Ne arayacağımı gerçekten bilmiyorum.


9
RDBMSes optimizasyonunun ayrıştırma ve optimizasyonla nasıl başa çıktığına bağlı olduğundan platforma bağlıdır.
Philᵀᴹ

8
Bağlantılı sorudaki bu cevap birkaç aşağı oyu hak ediyor. MySQL'in ilkel iyileştiricisi bile bu basit sorguların eşdeğer olduğunu ve "tüm birleşimler yapıldıktan sonra WHERE yan tümcesinin değerlendirildiğini" gerçek yürütmede değil, yalnızca mantıksal düzeyde doğru olduğunu anlayacaktır .
ypercubeᵀᴹ

1
Gerçekten bir kopya değil; bu soru ve cevaplar "örtük" ile "açık" birleşme sözdizimini karşılaştırıyordu. Özellikle tamamlayıcı katılma koşullarını soruyorum.
BellevueBob

Ben daha önce denedim ve aşağı oy çok var gibi bir cevap sonrası cesaret edemez. Bir çok birleşim olduğunda, durumu birleştirmek için daha iyi bir sorgu planıyla sonuçlanan durum vakalarım var (erken filtrelendi). Yine de aynı sonuçlar.
paparazzo

Yanıtlar:


14

Bölüm 9'a (Ayrıştırıcı ve Optimize Edici) göre, Sasha Pachev'in MySQL İç Kısmını Anlama Kitabı

MySQL Dahili Öğelerini Anlama

İşte bir sorgu aşağıdaki görevler olarak değerlendirme dökümü:

  • Kayıtları tablolardan almak için hangi tuşların kullanılabileceğini belirleyin ve her tablo için en iyisini seçin.
  • Her tablo için, bir tablo taramasının bir anahtardaki okumadan daha iyi olup olmadığına karar verin. Anahtar değeriyle eşleşen çok fazla kayıt varsa, anahtarın avantajları azalır ve tablo taraması hızlanır.
  • Sorguda birden fazla tablo bulunduğunda tabloların birleştirilme sırasını belirleyin.
  • Ölü kodu ortadan kaldırmak için WHERE yan tümcelerini yeniden yazın, gereksiz hesaplamaları azaltın ve tuşları kullanma yolunu açmak için mümkün olan her yerde kısıtlamaları değiştirin.
  • Kullanılmayan tabloları birleştirmeden kaldırın.
  • Anahtarlar için kullanılıp kullanılamayacağını belirlemek ORDER BYve GROUP BY.
  • Alt sorguları basitleştirmeyi deneyin ve sonuçlarının ne ölçüde önbelleğe alınabileceğini belirleyin.
  • Görünümleri birleştir (görünüm referansını makro olarak genişlet)

Aynı sayfada şunu söylüyor:

MySQL optimizer terminolojisinde, her sorgu bir birleşim kümesidir. Terimi katılmak SQL komutları göre daha geniş buraya kullanılır. Yalnızca bir tablodaki sorgu, dejenere birleşimdir. Normalde bir tablodaki kayıtları bir birleştirme olarak okumayı düşünmese de, geleneksel birleşimlerle kullanılan aynı yapılar ve algoritmalar sorguyu tek bir tabloyla çözmek için mükemmel çalışır.

SONSÖZ

Mevcut anahtarlar, veri miktarı ve sorgunun ifadesi nedeniyle, MySQL Joins bazen kendi iyiliğimiz (veya bize geri dönmek) için şeyler yapabilir ve beklemediğimiz ve hızlı bir şekilde açıklayamadığımız sonuçlarla gelebilir.

Bu tuhaflık hakkında daha önce yazmıştım

çünkü MySQL Sorgu Optimize Edici, sorgunun değerlendirilmesi sırasında bazı anahtarları işten çıkarabilir.

@ Phil'in yorumu bu cevabı nasıl göndereceğimi görmeme yardımcı oldu (@ Phil'in yorumu için +1)

@ ypercube'un yorumu (bunun için +1 de) gönderimin kompakt bir sürümüdür, çünkü MySQL'in Sorgu Doktoru ilkeldir. Ne yazık ki, dış depolama motorlarıyla uğraştığından beri olmalı.

SONUÇ

Asıl sorunuza gelince, MySQL Sorgu Optimize Edici her sorgunun tamamlandığında performans metriklerini belirleyecektir

  • satır sayma
  • tuşları seçme
  • aralıklı sonuç kümelerine masaj yapma
  • Oh evet, asıl katılıyor

Muhtemelen sorguyu yeniden yazarak (yeniden düzenleyerek) yürütme sırasını zorlamanız gerekir.

İşte verdiğiniz ilk Sorgu

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

İlk olarak NEREDE değerlendirmek için yeniden yazmayı deneyin

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

Bu kesinlikle EXPLAIN planını değiştirecektir. Daha iyi veya daha kötü sonuçlar verebilir.

Bir keresinde StackOverflow'da bu tekniği uyguladığım bir soruya cevap verdim. EXPLAIN çok korkunçtu ama performans dinamitti. Yalnızca doğru indekslerin mevcut olması ve bir alt sorguda LIMIT kullanılması nedeniyle işe yaradı .

Hisse senedi fiyatlarında olduğu gibi, Sorgular söz konusu olduğunda ve bunları ifade etmeye çalışırken, kısıtlamalar uygulanır, sonuçlar değişebilir ve geçmiş performans gelecekteki sonuçların göstergesi değildir.


2
Ayrıntılı MySQL'e özgü bilgiler için +1 ve özellikle "Epilog" ve "Sonuç" arasındaki farkı öğrenmem için beni kandırdın!
BellevueBob

Benim yazımda, Epilog bir alt sonuçtur.
RolandoMySQLDBA

6
@Rolando: En son MariaDB (5.3 ve 5.5) sürümlerinde ve yakın zamanda piyasaya sürülen ana MySQL (5.6) sürümünde iyileştiricilerle ilgili gelişmelerden sonra Aftermath ekleyebilirsiniz . Bu da yeniden yazmayı gereksiz hale getirebilir.
ypercubeᵀᴹ

1

Oracle için, mySQL'in uzun bir açıklaması olduğundan, optimize ediciyi kullanmanın 2 üst düzey yoluna sahibiz.

Birincisi Kural Tabanlı Optimizasyon (veya RBO). Oracle'ın ayrıştırdığı her sorgunun belirli bir sırada izlemeye çalıştığı 15 set-in-stone kuralı vardır. Kural 1'den optimize edilmiş bir sorgu oluşturamazsa, kural 15'e kadar kural 2'ye ve ileriye doğru ilerler.

daha fazla bilgi için: https://docs.oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

Bunlar, 11.1 ve daha önceki sürümlerden Maliyet Tabanlı Optimize Edici'ye (CBO olarak dönüştürülmemiş) Oracle RDBMS çekirdeklerini etkiler. Oracle 11.2 ve üstü için CBO optimizer gerekir, ancak kullanıcı isterse belirli Sql kimliklerini eski RBO yönteminde optimize etmeye zorlayabilir.

Oracle 11.1+ için CBO aynı SQL kimliği için birkaç yürütme planı yapar ve en az beklenen maliyetle yürütür. RBO'dan çok fazla mantık kullanır, ancak DB'nin son kullanıcıya verilerini sağlamak için yapması gereken her işlem için dinamik yürütme planı maliyetleri oluşturmak üzere tablo istatistiklerini analiz eder. Çok büyük tablolarda tam tablo taraması yapmak gerçekten maliyetlidir; 10 sıralı bir tabloda tam masa taraması yapmak ucuzdur. RBO'da bunlar eşit operasyonlar olarak kabul edildi.

daha fazla bilgi için: https://oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

Özel sorgu örneğiniz için: Oracle muhtemelen farklı yürütme planları yapmak için bilgileri ayrıştırır ve böylece biri teknik olarak diğerinden daha iyi olacaktır. Bununla birlikte, bu minimal bir fark olabilir. Bunu göz önünde bulundurarak, hem Oracle RBO hem de CBO, daha az koşulda bir birleştirme üzerinde çalıştığı ve daha sonra birleştirme işleminden yaptığı geçici tablodan belirli bir sütunu filtrelediği için sorgu 1'i daha fazla istiyor.


1

İki sorgunuz varsa ve bunların eşdeğer olduğunu düşünüyorsanız aşağıdakiler gerçekleşebilir:

  1. Her iki sorgu da aynı yürütme planına sahiptir. Bu iyi ve beklediğimiz bu. Umarız bu sorgu için en uygun yürütme planıdır.
  2. farklı icra planları var. Burada iki subcasımız var.

    2.1 Sorguların farklı yürütme planları vardır, ancak her iki plan da eşit derecede iyi performans gösterir. Bu da iyi. Eşdeğer sorgular için aynı planın oluşturulmasına gerek yoktur. Ancak performans eşit olmalıdır. Ve yine bunun mümkün olan en iyi olduğunu umuyoruz.

    2.2 Sorguların yürütme planları farklıdır ve bir plan diğerinden daha iyidir. Yine alt senaryolarımız var:

    2.2.1 Planlar farklıdır çünkü sorgular eşdeğer değildir. Bu yüzden gerçekten eşdeğer olup olmadığını dikkatlice kontrol edin. Senin durumunda gerçekten eşdeğerler.

    2.2.2 Planlar farklı, ancak sorgular eşdeğer. Bu, optimize edicinin yeterince olgunlaşmamış olduğu anlamına gelir. Mükemmel optimize ediciler ile mükemmel bir dünyada bu olmamalıdır. Yani evet, platforma bağlıdır ve bunun neden olduğunu öğrenmek için platforma özgü belgeleri incelemeniz gerekir.

    2.2.3 Planlar farklı, sorgular eşdeğer, veritabanı yazılımında bir hata var.

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.