Apakah ada cara untuk melakukan pemeriksaan nol pada variabel dalam klausa WHERE hanya terjadi sekali?

12

Saya memiliki kueri di tabel besar yang terlihat seperti ini:

declare @myIdParam int = 1

select * 
from myTable
where (@myIdParam is null or myTable.Id = @myIdParam)

Ada beberapa persyaratan serupa seperti ini di mana klausa, dan ada juga banyak bergabung, tetapi ini adalah ringkasan.

Secara efektif, jika @myIdParam adalah nol, kami tidak ingin membatasi hasil menggunakan parameter ini.

Saya bukan pro DB, tetapi dari tes saya sepertinya pemeriksaan NULL ini dilakukan untuk setiap catatan dan tidak dioptimalkan dengan cara apa pun.

Jika saya menghapus centang nol dan menganggap parameternya bukan nol, kueri kembali seketika. Kalau tidak, dibutuhkan hingga sepuluh detik.

Apakah ada cara untuk mengoptimalkan ini sehingga pemeriksaan dilakukan hanya sekali saat runtime?

Mystagogue
sumber
1
Lihat jawaban ini: stackoverflow.com/questions/3415582/... tl; dr useOPTION(RECOMPILE)
vercelli
@vercelli ini berhasil. Mengingat pertanyaan ini benar-benar tentang parameter opsional, saya akan mengatakan itu adalah duplikat dari yang Anda tautkan.
Mystagogue
Mungkin, tetapi ini adalah posting dari 6 tahun yang lalu. Mungkin dengan SqlServer 2014 atau 2016 ada pendekatan baru. (Saya mengujinya pada 2014 tanpa kompilasi ulang dan mengambil selamanya)
vercelli
Karena permintaan aktual Anda memiliki banyak parameter opsional, SQL dinamis akan memberikan kinerja terbaik. Lihat sommarskog.se/dyn-search.html untuk artikel menyeluruh tentang masalah ini.
Dan Guzman
@DanGuzman menggunakan WITH RECOMPILE seperti yang dijabarkan dalam pertanyaan yang terhubung dengan vercelli memangkas waktu permintaan dari hampir satu menit menjadi praktis instan dengan kriteria yang sangat selektif. Saya menganggap ini pilihan terbaik untuk menyeimbangkan kinerja dan keterbacaan.
Mystagogue

Jawaban:

8

Salah satu caranya adalah dengan menggunakan SQL dinamis, menggunakan tanda centang nol untuk menambahkan bagian klausa mana.

declare @myIdParam int = 1
declare @vc_dynamicsql varchar(max)

set @vc_dynamicsql = 'select * from myTable where 1=1'

if @myIdParam is not null
    set @vc_dynamicsql = @vc_dynamicsql + ' and  myTable.Id = @myIdParam'

EXECUTE sp_executesql @vc_dynamicsql
Mystagogue
sumber
2
Saya benar-benar memilih untuk tidak melakukan ini, tetapi ini adalah solusi. Harapan saya adalah seseorang datang dengan yang jauh lebih baik.
Mystagogue
1
Ini adalah cara terbaik untuk menangani kelas permintaan pencarian ini. The jawaban stackoverflow disebut oleh @vercelli berisi referensi besar untuk bagaimana melakukan ini.
Max Vernon
Ini adalah metode terbaik, tetapi saya memang memperhatikan bahwa parameter @params sp_ExecuteSQLtidak ada dan @vc_dynamicsqlparameternya harus a NVARCHAR.
James Anderson
4

Setiap kali Anda meletakkan fungsi di sekitar kolom `ISNULL (@var, table.col) 'misalnya Anda menghapus kemampuan SQL untuk menggunakan indeks. Ini benar-benar adalah opsi berkinerja terbaik jika Anda ingin menyimpannya dalam satu permintaan.

@var IS NULL or @var = table.col

Kalau tidak, Anda memiliki dua opsi. Yang pertama adalah SQL dinamis dan jawaban @ Mystagogue sudah cukup untuk itu jika tidak Anda bisa memasukkan dua pertanyaan seperti ini:

IF @var is NULL
     SELECT * FROM table
ELSE
     SELECT * FROM table WHERE @var = col

Baik dalam format ini maupun SQL dinamis, Anda sebenarnya akan mendapatkan rencana kueri yang berbeda untuk setiap kueri (yang berpotensi menghasilkan kinerja yang lebih baik).

Kenneth Fisher
sumber
Sql dalam pertanyaan tidak menggunakan ISNULL atau fungsi lainnya.
Mystagogue
@MystagogueI saya sedang referensi jawaban yang sekarang dihapus
Kenneth Fisher
0

Anda bisa:

declare @myIdParam int = 1;

select *
from myTable
where nullif(@myIdParam, myTable.Id) is null;

Perlu diingat, bahwa nullif()fungsi tersebut pada dasarnya adalah pembungkus case. Ini bukan peluru perak yang secara ajaib menghilangkan ORdan dengan demikian mempercepat kueri.

Roger Wolf
sumber
menggunakan fungsi di mana klausa memiliki dampak negatif pada kinerja karena mencegah penggunaan indeks (atau begitulah yang saya dengar)
Mystagogue
@Mystagogue, ya - biasanya membuat kondisi pencarian menjadi tidak SARGable. Sayangnya, ini adalah satu-satunya cara saya tahu bagaimana menjawab pertanyaan Anda tanpa menggunakan SQL dinamis atau banyak UNION. Ketika saya memiliki tugas yang tepat ini, saya memilih SQL dinamis.
Roger Wolf