Filtrelenmiş bir arama yapmanın en iyi yöntemi


17

Filtrelenmiş bir arama formu uygulamak söz konusu olduğunda size sormak istiyorum. Aşağıdaki durumu düşünelim:

  • 1 Sütun dolu büyük tablo
  • Bu SQL Server'ın

Bu tablodaki verileri aramak için bir form uygulamanız gerekir ve bu formda bu aramayı kostümlendirmenize izin veren birkaç onay kutunuz olur.

Şimdi burada sorum, aşağıdakilerden hangisinin aramayı gerçekleştirmenin en iyi yolu olması gerektiğidir?

  1. İçinde bir sorgu bulunan saklı yordam oluşturun. Bu saklı yordam, parametrelerin uygulama tarafından verilip verilmediğini kontrol eder ve verilmemesi durumunda sorguya bir joker karakter konur.

  2. Uygulama tarafından verilene göre oluşturulmuş dinamik bir sorgu oluşturun.

Saklı yordam oluşturulduğunda SQL Server'ın bir yürütme planı oluşturduğunu biliyorum, çünkü performansını en iyi duruma getirmek için, ancak saklı yordamın içinde dinamik bir sorgu oluşturarak yürütme planı tarafından kazanılan optimizasyonu feda edeceğiz?

Lütfen bana karşınızdaki en iyi yaklaşımın ne olacağını söyleyin.


Aşağıda dinamik çözüme yöneldiğinizi belirtiyorsunuz. Bu harika, sadece olası filtreleri numaralandırdığınızdan ve bunları destekleyen dizinler olduğundan emin olun. Sorgular tutarlı bir şekilde oluşturulduğu sürece verimli olmaları gerekir.
Matthew Flynn

Yanıtlar:


10

Bu benzer sorunun cevabına buradan bakmak isteyebilirsiniz: /programming/11329823/add-where-clauses-to-sql-dynamically-programmatically

Bir grup isteğe bağlı parametreyi alan ve filtreyi şu şekilde uygulayan bir SPROC'un:

CREATE PROC MyProc (@optionalParam1 NVARCHAR(50)=NULL, @optionalParam2 INT=NULL)
AS 
...
SELECT field1, field2, ... FROM [Table]
WHERE 
  (@optionalParam1 IS NULL OR MyColumn1 = @optionalParam1)
  AND (@optionalParam2 IS NULL OR MyColumn2 = @optionalParam2)

çalıştırıldığı ilk yürütme planını önbelleğe alır (örn. @optionalParam1 = 'Hello World', @optionalParam2 = NULL), ancak farklı bir dizi isteğe bağlı parametre (örn. @optionalParam1 = NULL, @optionalParam2 = 42) iletirsek sefil performans gösterir . (Ve tabii ki önbelleğe alınmış planın performansını istiyoruz, bu yüzden WITH RECOMPILEçıktı)

Buradaki istisna, isteğe bağlı parametrelere ek olarak, sorgu üzerinde YÜKSEK seçici ve düzgün bir şekilde indekslenmiş en az bir ZORUNLU filtre varsa, yukarıdaki PROC'nin iyi performans göstermesidir.

Bununla birlikte, TÜM filtreler isteğe bağlıysa, oldukça korkunç gerçek, parametrelenmiş dinamik sql'nin daha iyi performans göstermesidir (isteğe bağlı parametrelerin her permütasyonu için N! Farklı statik PROCS yazmazsanız).

Aşağıdaki gibi dinamik SQL, Sorgu parametrelerinin her bir permütasyonu için farklı bir plan oluşturur ve önbelleğe alır, ancak en azından her plan belirli bir sorguya 'uyarlanır' (bir PROC veya Adhoc SQL olup olmadığı önemli değildir) parametrelenmiş sorgular oldukları sürece önbelleğe alınırlar)

Bu yüzden benim tercihim:

DECLARE @SQL NVARCHAR(MAX)        

-- Mandatory / Static part of the Query here
SET @SQL = N'SELECT * FROM [table] WHERE 1 = 1'

IF @OptionalParam1 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn1 = @optionalParam1'    
    END        

IF @OptionalParam2 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn2 = @optionalParam2'    
    END        

EXEC sp_executesql @SQL,        
    N'@optionalParam1 NVARCHAR(50), 
      @optionalParam2 INT'
    ,@optionalParam1 = @optionalParam1
    ,@optionalParam2 = @optionalParam2

Yedek parametrelerde sp_executesql'e geçersek önemli değil - yok sayılırlar. ORM'lerin Linq2SQL ve EF gibi parametreli dinamik sql'i benzer şekilde kullandığını belirtmek gerekir.


1
Evet öyle düşündüm, bu benim seçtiğim seçimdi. Sadece iyi bir şey olduğundan emin olmak istedim. Cevap için teşekkürler.
j0N45

"Bir SQL ifadesi parametreler olmadan yürütülürse, SQL Server ifadeyi mevcut bir yürütme planıyla eşleştirme olasılığını artırmak için ifadeyi dahili olarak parametrelendirir. Bu işleme basit parametrelendirme denir." Yani program temel olarak "where filenumber =" + filename gibi bir şey kullanabilir. Tabii ki, bu bir kutu solucan açar ancak bu farklı bir konudur ;-)
Codism

5

Uygulamanın daha kolay olduğunu düşündüğünüz şeylerle başlayın (sanırım 2. seçenek). Ardından gerçek dünya verileri için performansı ölçün . Optimizasyona yalnızca gerektiğinde başlayın, önceden değil.

Bu arada, arama filtrelerinizin ne kadar karmaşık olduğuna bağlı olarak, göreviniz dinamik SQL olmadan kolayca çözülemeyebilir. Bu nedenle, saklı bir yordamı kullandığınızda bile, muhtemelen şüphelendiğiniz gibi performansı artırmayacaktır. Öte yandan, yardımcı olursa, bir SQL'e ekleyebileceğiniz birkaç tür ipucu vardır (bkz. Http://www.simple-talk.com/sql/performance/controlling-execution-plans-with-hints/ ). SQL sunucusunun yürütme planını optimize etmesine yardımcı olmak için dinamik veya sorguyu sorgulayın.


Eh, zaten 2. seçeneği uyguladım ve bunun en iyi yol olduğunu düşünüyorum, çünkü joker karakterler performansı önemli ölçüde azaltacaktır, ancak bakımdan feda ediyorum, çünkü bu koddaki karmaşıklığı artıracaktır. Birisinin bu tür durumlar için daha iyi bir seçenek biliyor mu diye bilmek istedim.
j0N45

Sana oy verirdim, ama itibarım yok üzgünüm.
j0N45
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.