SİPARİŞİM neden iki tabloyu HARİÇ (yavaş) ve sonra (hızlı) önce sıralıyor?


12

SQL Server 2008 R2 sorgu optimizer bulmaca

Her ikisi de 9 milyon satır içeren iki masamız var. 70.000 sıra farklı, diğerleri aynı.

Bu hızlı, 13 saniye,

select * from bigtable1
except select * from similar_bigtable2

Bu, çıktıyı sıralar ve 13 saniye de hızlıdır,

select * into #q from bigtable1
except select * from similar_bigtable2
select * from #q order by sort_column

Bu çok yavaş olsa da:

;with q as (
    select * from bigtable1
    except select * from similar_bigtable2
)
select * from q order by sort_column

Ve hatta bazen ben hareket etmeden önce sorgunun belirli bir bölümünü önceden hesaplamak için gereken SQL Server ipucu için kullandığım bir "hile", çalışmıyor ve aynı zamanda yavaş sorgu ile sonuçlanır:

;with q as (
    select top 100 percent * from bigtable1
    except select * from similar_bigtable2
)
select * from q order by sort_column

Sorgu planlarına bakmanın sebebini bulmak zor değildir:

Sorgu planı ORDER BY ile sorgu planı

SQL Server , hashmatch'tan önce 9 milyon satırlık iki tür yerleştirirken , hashmatch'tan sonra yalnızca bir tür 70.000 satır eklemesini tercih ederim .

Yani soru: Sorgu optimize ediciye bunu yapmasını nasıl söyleyebilirim?


3
Hashhmatch'tan önce sıralama yapmaz, sıralar ve sonra bir birleştirme birleştirme yapar (bir karma birleştirme değil). Belki bir karma birleştirmeyi zorlamak için bir ipucu vardır (veya birleştirme birleştirmesini önlemek)?
Thilo

3
SQL Server sorgu optimize edici çok daha yavaş Hash Match Join veya Nested Loop Join yerine çok daha hızlı Birleştirme Join (sadece sıralanan veriler için çalışır) kullanabilirsiniz böylece veri sıralama yararlı olduğunu belirledi görünüyor
marc_s

9
EXCEPT(Örn. OUTER JOIN) 'E alternatif denediniz mi? Sözdiziminin daha az uygun olduğunu anlıyorum ama orada daha iyi indeks / birleştirme ipuçları ile oynayabilirsiniz (veya gerekmeyebilir). Şimdi kullandığınız alternatif (önce #temp tablosuna yerleştirilenler) son çare geçici çözümdür, ancak bazı durumlarda optimize ediciyi bir sorgunun iki bölümünü istediğiniz şekilde tamamen ayırmaya zorlamanın tek yoludur.
Aaron Bertrand

Yanıtlar:


1

Bu iki sorgu planı arasındaki temel fark, aslında Hash Match ve Merge Join arasındaki farktır. Hash Match daha verimlidir ve gördüğünüz gibi sorgu 1'de daha hızlı çalışır (CTE kullanmadan).

CTE harika bir araçtır, ancak Karmaşık Tahminler veya Benzersiz Olmayan Ebeveyn / Çocuk Anahtarı olmak üzere iki durumda etkili görünmemektedir. Sizin durumunuzda benzersiz bir anahtar yoktur ve SQL sunucusunun gereksinimlerinizi karşılayabilmek için önce veri kümelerini sıralaması gerekir. Aşağıda bu konuda size daha fazla bilgi veren bağlantıya göz atın: http://blogs.msdn.com/b/sqlcat/archive/2011/04/28/optimize-recursive-cte-query.aspx

Bu yüzden ya yavaşlığını kabul etmeniz ya da mantığı daha verimli olabilecek WHILE döngüsü ile yeniden yazmanız gerekiyor gibi görünüyor.


0

Bunu dene, daha iyi mi?

select * from
(
    select * from bigtable1
    except 
    select * from similar_bigtable2
) t
order by sort_column

0

Bu ideal bir çözüm değildir, ancak tsql'yi verimli bir plan oluşturacak şekilde yapılandıramıyorsanız, istediğiniz planı zorlamak için bir plan kılavuzu ayarlayabilirsiniz. Bunu yapmak, daha verimli bir plan kullanılabilir hale gelirse, SQL bunu dikkate almayacaktır, ancak bir seçenektir.

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.