Metode terbaik untuk menerapkan pencarian yang difilter

17

Saya ingin menanyakan pendapat Anda tentang penerapan formulir pencarian yang difilter. Mari kita bayangkan kasus berikut:

  • 1 Meja besar dengan banyak kolom
  • Mungkin penting untuk mengatakan bahwa ini SQL Server

Anda perlu menerapkan formulir untuk mencari data dalam tabel ini, dan dalam formulir ini Anda akan memiliki beberapa kotak centang yang memungkinkan Anda untuk mengkustomisasi pencarian ini.

Sekarang pertanyaan saya di sini adalah mana dari berikut ini yang harus menjadi cara terbaik untuk mengimplementasikan pencarian?

  1. Buat prosedur tersimpan dengan kueri di dalamnya. Prosedur tersimpan ini akan memeriksa apakah parameter diberikan oleh aplikasi dan dalam kasus mereka tidak diberikan wildcard akan dimasukkan ke dalam kueri.

  2. Buat kueri dinamis, yang dibangun sesuai dengan apa yang diberikan oleh aplikasi.

Saya bertanya ini karena saya tahu bahwa SQL Server membuat rencana eksekusi ketika prosedur tersimpan dibuat, untuk mengoptimalkan kinerjanya, namun dengan membuat kueri dinamis di dalam prosedur tersimpan, akankah kita mengorbankan optimisasi yang diperoleh oleh rencana eksekusi?

Tolong beritahu saya apa yang akan menjadi pendekatan terbaik menurut pendapat Anda.

j0N45
sumber
Anda menyatakan di bawah ini bahwa Anda cenderung menuju solusi dinamis. Itu keren, pastikan Anda menghitung kemungkinan filter dan memiliki indeks yang mendukungnya. Selama pertanyaan dibangun secara konsisten, mereka harus efisien.
Matthew Flynn

Jawaban:

10

Anda mungkin ingin melihat jawaban untuk pertanyaan serupa ini di sini: /programming/11329823/add-where-claus---qc-dynamically-programmatically

Kami telah menemukan bahwa SPROC yang mengambil banyak parameter opsional dan mengimplementasikan filter seperti ini:

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)

akan melakukan cache pada rencana eksekusi pertama yang dijalankannya (mis. @optionalParam1 = 'Hello World', @optionalParam2 = NULL) tetapi kemudian berkinerja buruk jika kita memberikannya serangkaian parameter opsional yang berbeda (mis @optionalParam1 = NULL, @optionalParam2 = 42.). (Dan jelas kami ingin kinerja dari rencana yang di-cache, begitu WITH RECOMPILEjuga keluar)

Pengecualian di sini adalah bahwa jika ada JUGA setidaknya satu filter WAJIB pada permintaan yang SANGAT selektif dan diindeks dengan benar, di samping parameter opsional, maka PROC di atas akan bekerja dengan baik.

Namun, jika SEMUA filter adalah opsional, kebenaran yang agak mengerikan adalah bahwa sql parameter parametrik benar-benar berkinerja lebih baik (kecuali jika Anda menulis N! PROCS statis yang berbeda untuk setiap permutasi parameter opsional).

SQL dinamis seperti di bawah ini akan membuat dan cache rencana yang berbeda untuk setiap permutasi dari parameter Query, tetapi setidaknya setiap rencana akan 'disesuaikan' dengan permintaan tertentu (tidak masalah apakah itu PROC atau Adhoc SQL - karena selama mereka parameter permintaan, mereka akan di-cache)

Maka dari itu preferensi saya untuk:

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

dll. Tidak masalah jika kita memasukkan parameter berlebihan ke sp_executesql - mereka diabaikan. Perlu dicatat bahwa ORM seperti Linq2SQL dan EF menggunakan sql dinamis berparameterisasi dengan cara yang sama.

StuartLC
sumber
1
Ya saya pikir begitu, ini adalah opsi yang saya pilih. Hanya ingin memastikan itu bagus. Terima kasih atas tanggapannya.
j0N45
"Jika pernyataan SQL dijalankan tanpa parameter, SQL Server membuat parameter pernyataan secara internal untuk meningkatkan kemungkinan mencocokkannya dengan rencana eksekusi yang ada. Proses ini disebut parameterisasi sederhana." Jadi pada dasarnya program bisa menggunakan beberapa hal seperti "where filenumber =" + filename. Tentu saja, itu membuka kaleng cacing tapi itu topik yang berbeda ;-)
Codism
5

Mulailah dengan apa pun yang menurut Anda lebih mudah diterapkan (saya kira opsi 2). Kemudian mengukur kinerja untuk data dunia nyata. Hanya mulai mengoptimalkan ketika dibutuhkan, bukan sebelumnya.

Omong-omong, tergantung pada seberapa rumitnya filter pencarian Anda, tugas Anda mungkin tidak akan mudah diselesaikan tanpa SQL dinamis. Jadi, bahkan ketika Anda menggunakan prosedur tersimpan, kemungkinan besar itu tidak akan meningkatkan kinerja, seperti yang sudah Anda duga. Di sisi lain, jika itu membantu, ada beberapa jenis petunjuk (lihat http://www.simple-talk.com/sql/performance/controlling-execution-plans-with-hints/ ) Anda dapat menambahkan ke SQL permintaan, dinamis atau tidak, untuk membantu server SQL mengoptimalkan rencana pelaksanaannya.

Doc Brown
sumber
Yah, saya sudah menerapkan opsi 2 dan saya pikir itu adalah cara terbaik untuk pergi, terutama karena wildcard akan secara dramatis menurunkan kinerja, namun saya mengorbankan pemeliharaan, karena ini akan meningkatkan kompleksitas dalam kode. Saya hanya ingin tahu apakah seseorang tahu pilihan yang lebih baik untuk situasi seperti ini.
j0N45
Saya akan memberikan Anda suara, tetapi saya tidak memiliki reputasi maaf.
j0N45