11

Tam metin dizini kullanarak ürünleri (250.000 satır) arayan bir depolanmış procum var.Bu 2 sorgunun performansı neden bu kadar farklı?

Kaydedilen prok, tam metin arama koşulu olan bir parametre alır. Bu parametre boş olabilir, bu yüzden null bir kontrol ekledim ve sorgu aniden büyüklük sıralarını daha yavaş çalıştırmaya başladı.

Sorgu # 1 Execution plant #1

Sorgu # 2 Execution plant #2

ben yürütme planları ile çok aşina değilim itiraf gerekir:

-- This is normally a parameter of my stored proc 
DECLARE @Filter VARCHAR(100) 
SET @Filter = 'FORMSOF(INFLECTIONAL, robe)' 

-- #1 - Runs < 1 sec 
SELECT TOP 100 ID FROM dbo.Products 
WHERE CONTAINS(Name, @Filter) 

-- #2 - Runs in 18 secs 
SELECT TOP 100 ID FROM dbo.Products 
WHERE @Filter IS NULL OR CONTAINS(Name, @Filter) 

İşte yürütme planları vardır. Benim için tek açık fark, birleşmelerin farklı olmasıdır. Bir ipucu eklemeye çalışıyorum ama sorgumda bir katılma olmamasını nasıl yapacağımı bilmiyorum.

Ayrıca IX_SectionID adlı dizinin neden kullanıldığını tam olarak anlayamıyorum, çünkü yalnızca SectionID sütununu içeren bir dizin ve bu sütun hiçbir yerde kullanılmıyor.

cevap

8

OR performansı ezmek, böylece bu şekilde yapabilirsiniz: Dynamic Search Conditions in T-SQL by Erland Sommarskog ve bu soruya: SQL Server 2008 - Conditional Query bu makaleyi

DECLARE @Filter VARCHAR(100) 
SET @Filter = 'FORMSOF(INFLECTIONAL, robe)' 

IF @Filter IS NOT NULL 
BEGIN 
    SELECT TOP 100 ID FROM dbo.Products 
    WHERE CONTAINS(Name, @Filter) 
END 
ELSE 
BEGIN 
    SELECT TOP 100 ID FROM dbo.Products 
END 

bak.

+0

Güzel makale - SEÇENEĞİ (RECOMPILE) 'ekleyerek' aslında 2 sorguya performans sorununu (giderir ancak başka bir sorun '()' zam CONTAINS olmasıdır Parametre NULL olduğunda bir hata, ancak başka bir sorun). –

1

Bir VEYA koşulu getirdiniz. Çoğu durumda NULL için açık bir şekilde kontrol etmek ve yönteminize göre bir sorgulama yapmak çok daha hızlıdır.

Mesela bu deneyin:

IF @Filter IS NULL 
BEGIN 
SELECT TOP 100 ID FROM dbo.Products 
END 
ELSE 
BEGIN 
SELECT TOP 100 ID FROM dbo.Products 
WHERE @Filter CONTAINS(Name, @Filter) 
END 
3

ilk sorgu planı basit görünüyor:

  1. tam metin arama diğer sütunları bakmak CONTAINS(Name, @Filter)
  2. bir dizin tarama çözmek için eşleştirilen satırlar
  3. iki birleştirme birleştir kullanarak birleştirmek

concatenation operator iki kayıt kümesinin birleşimini oluşturur. İkinci sorgu yapıyor gibi Öyle görünüyor:

  1. (daha sonra diğer sütunları aramak için kullanılır) bir indeks taraması
  2. sabit taraması. Sorgunuzu parametrelenmemiş olarak ele aldığını varsayalım, bu nedenle sorgu planının @Filter diğer herhangi bir değeri için çalışması gerekmez. Doğruysa, sabit tarama @Filter is not null'u çözer.
  3. tam metin arama 2
  4. döngüden boş set ile CONTAINS(Name, @Filter)
  5. sendikalara 3 sonucunu çözmek için

Bir hash katılmak diğer sütunlar bakmak için 1 ile 4 sonucunu katıldı hız için hafıza ticareti yapar; Sisteminizde yeterli bellek varsa, bir döngü katılımından çok daha hızlıdır. Bu, 10-100x'lik bir yavaşlamayı kolayca açıklayabilir.

Bir düzeltme iki farklı sorguları kullanmaktır:

if @Filter is null 
    SELECT TOP 100 ID FROM dbo.Products 
else 
    SELECT TOP 100 ID FROM dbo.Products WHERE CONTAINS(Name, @Filter) 
+0

İlginç - ikinci sorguda karma birleştirme zorlamak için herhangi bir yolu var mı? –

+0

Evet, onu 'iç karma birleştir' kullanarak yeniden yazabilirsin, ama bu oldukça karmaşık olurdu. Sommarskog makalesinin çözümlerinden birini kullanmak daha iyi olurdu. – Andomar

İlgili konular