Alt sorgular ve birleştirmeler


158

Başka bir şirketten devraldığımız bir uygulamanın yavaş bir bölümünü, bir alt sorgu yerine bir iç birleşim kullanmak üzere yeniden düzenledim:

WHERE id IN (SELECT id FROM ...)

Yeniden düzenlenmiş sorgu yaklaşık 100 kat daha hızlı çalışır. (~ 50 saniye ila ~ 0.3) Bir iyileşme bekledim, ama neden bu kadar sert olduğunu açıklayabilir mi? Where yan tümcesinde kullanılan sütunların tümü dizine eklenmiştir. SQL sorguyu her satırda bir kez nerede yan tümcesinde çalıştırıyor mu?

Güncelleme - Sonuçları açıklayın:

Fark "where id in ()" sorgusunun ikinci bölümünde -

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

vs 1 endeksli sıra ile birleşim:

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index


2
Kopya değil. Bu Soru özellikle çarpıcı performans farkı ile ilgilidir. Diğer Soru daha geneldir, her bir yaklaşımın artıları ve eksileri ve bir yaklaşımın neden daha popüler göründüğü hakkında açık uçludur.
Basil Bourque

@simhumileco Bu bir gelişme değil, fark değil, yazarın yazdıkları ve kod stili için bu tür düzenlemelerin aksine. Kodda ne zaman düzenleme yapmalıyım?
philipxy

Merhaba @ filipxy, ben yazarın düşüncesine müdahale etmek niyetinde değil, sadece kod parçasını daha okunabilir ve daha dikkatli bir şekilde yazmak için.
simhumileco

Yanıtlar:


160

Bir "ilişkili alt sorgu" (yani, burada koşulun, içeren sorgunun satırlarından elde edilen değerlere bağlı olduğu bir alt sorgu), her satır için bir kez yürütülür. İlişkilendirilmemiş bir alt sorgu (nerede koşulun içeren sorgudan bağımsız olduğu bir alt sorgu) başlangıçta bir kez yürütülür. SQL motoru bu ayrımı otomatik olarak yapar.

Ama evet, açıkla-plan size kirli detayları verecek.


3
Bunun DEPENDENT SUBQUERY"ilişkili alt sorgu" ile aynı anlama geldiğini lütfen unutmayın .
Timo

38

Alt satırı her satır için bir kez çalıştırırken birleştirme dizinlerde gerçekleşir.


5
Bunun doğru olduğunu düşünmüyorum. SQL motoru, alt sorguyu yalnızca bir kez çalıştırmalı ve sonucu liste olarak kullanmalıdır.
dacracot

8
Bu bağlıdır - alt sorgu bir şekilde dış sorgu ile ilişkilendirilirse (verilerini kullanır), her satırla yürütülür.
qbeuek

4
Bu durumda muhtemelen doğrudur, ancak genel olarak doğru değildir.
Amy B

1
OP'ler , bu davranışın en açık göstergesi olduğunu EXPLAINsöylüyor DEPENDENT SUBQUERY.
Timo


7

Her versiyonda açıklama planını çalıştırın, size nedenini söyleyecektir.


6

sorgular bir sorgu iyileştirici aracılığıyla yerleştirilen veri kümesine karşı çalıştırılmadan önce, iyileştirici sorguyu sonuç kümesinden olabildiğince çabuk sayıda kümeyi (satır) kaldırabilecek şekilde düzenlemeye çalışır. Genellikle alt sorgular (özellikle kötü olanlar) kullandığınızda, dış sorgu çalışmaya başlayana kadar tuples sonuç kümesinden budanamaz.

Sorgu görmeden orijinal hakkında ne kötü olduğunu söylemek zor, ama benim tahminim bu optimizer sadece çok daha iyi yapamadım bir şey olurdu. 'Açıkla' çalıştırıldığında, verileri almak için optimize edici yöntemi gösterilir.


4

Her sorgu için sorgu planına bakın.

Nerede ve Üyelik edebilirsiniz tipik aynı yürütme planı kullanılarak uygulanabilir, böylece tipik aralarında değiştirmesini sıfır hız-up vardır.


3
Haha, Ben <3 Sql aşağı oylamayı öneriyor çünkü sorgu planlarını nasıl okuyacaklarını bilmiyorlar.
Amy B

4

Optimizer çok iyi bir iş çıkarmadı. Genellikle herhangi bir fark olmadan dönüştürülebilirler ve optimize edici bunu yapabilir.


4

Genellikle eniyileyicinin sonucu, alt sorgunun bir birleşim olarak yürütülebileceğini anlayamamanın sonucudur; bu durumda, tablodaki her kayıt için alt sorguyu yürütür, daha sonra sorguladığınız tabloya karşı alt sorgudaki tabloya katılır. Daha "enterprisey" veritabanından bazıları bu konuda daha iyi, ama yine de bazen özlüyorlar.


4

Bu soru biraz genel, bu yüzden genel bir cevap:

Temel olarak, MySQL'de sıralanacak tonlarca satır olduğunda sorgular daha uzun sürer.

Bunu yap:

Sorguların her birinde (BİRLEŞTİRİLEN, sonra Alınan Sorgulanan) bir EXPLAIN çalıştırın ve sonuçları buraya gönderin.

MySQL'in bu sorguları yorumlamasındaki farkı görmek herkes için bir öğrenme deneyimi olacaktır.


4

Where alt sorgusu, döndürülen her satır için 1 sorgu çalıştırmalıdır. İç birleşim sadece 1 sorgu çalıştırmalıdır.


3

Alt sorgu muhtemelen bir "tam tablo taraması" yürütüyordu. Diğer bir deyişle, dizini kullanmamak ve ana sorgudan Where'in filtrelemek için ihtiyaç duyduğu çok fazla satır döndürmemek.

Sadece detaylar olmadan bir tahmin elbette ama bu ortak bir durum.


2

Bir alt sorguda, her sonuç için 2. SEÇİMİ yeniden yürütmeniz gerekir ve her yürütme genellikle 1 satır döndürür.

Birleştirme ile 2. SEÇİM çok daha fazla satır döndürür, ancak yalnızca bir kez yürütmeniz gerekir. Avantajı, şimdi sonuçlara katılabilir ve ilişkilere katılmak, bir veritabanının iyi olması gerektiği şeydir. Örneğin, belki de optimize edici şimdi bir dizinden nasıl daha iyi yararlanabileceğini tespit edebilir.


2

En azından Oracle'ın SQL motorunun temelini oluşturmasına ve son derece hızlı çalışmasına rağmen, IN yan tümcesi kadar alt sorgu değildir.


1
doğal olarak kötü değil.
Shawn

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.