Memaksa SQL Server untuk menjalankan kondisi permintaan seperti yang tertulis?

14

Saya menggunakan SQL Server 2008 R2 dan saya punya permintaan semu (SP) ini:

select ...
from ...
WHERE    @LinkMode IS NULL
     AND (myColumn IN (...very long-running query...))
     ...
     ...

Masalahnya adalah bahwa kueri membutuhkan waktu yang sangat lama untuk dieksekusi - bahkan jika saya menjalankan SP dengan @LinkMode=2.

Seperti yang Anda perhatikan, permintaan yang sudah berjalan lama harus dijalankan hanya jika @LinkMode adalah nol, yang tidak berlaku di sini. Dalam kasus saya @LinkMode = 2!

Namun, jika saya mengubahnya ke:

 select ...
    from ...
    WHERE    1=2
         AND (myColumn IN (...very long time exeted query...))
     ...
     ...

SP tidak berjalan cepat.

Saya pernah mendengar sebelumnya bahwa terkadang optimizer dapat mengoptimalkan urutan kriteria.

Jadi saya bertanya:

  • Bahkan jika optimizer memilih rute yang berbeda, apa yang bisa lebih cepat daripada memeriksa jika =null? Maksudku, saya berpikir bahwa pemeriksaan if a==nulladalah jauh lebih cepat daripada menjalankan query panjang lainnya ...

  • Bagaimana saya bisa memaksa SQL Server untuk menjalankan kueri seperti yang saya tulis (urutan yang sama)?

Royi Namir
sumber

Jawaban:

22

Anda jatuh ke dalam perangkap " Catch-All Query ", yang dijelaskan dengan sangat baik oleh Gail Shaw di sini .

Untuk meringkas masalah: SQL Server mengoptimalkan overhead signifikan dari kompilasi permintaan dengan caching rencana kueri setelah kompilasi, dan kemudian memeriksa cache untuk rencana kueri yang cocok sebelum kompilasi selanjutnya. "Pencocokan" yang terjadi di sini adalah murni tekstual, sehingga nilai aktual suatu variabel tidak akan memengaruhi ini.

Itu bagus 99% dari waktu, tetapi dalam beberapa kasus itu buruk . Satu kasus di mana itu buruk adalah ketika seseorang mencoba untuk membangun klausa WHERE seolah-olah seperti pernyataan IF hubung singkat di C, dll. Ini tidak berfungsi dengan baik, karena kompiler SQL harus membuat satu rencana kueri yang akan berfungsi tanpa dari apa nilai parameter sebenarnya, dan satu-satunya cara agar dapat menangani kondisi-kondisi logis "pintar" ini dalam klausa WHERE adalah membuat rencana brute-force sederhana yang hanya memindai seluruh tabel, memfilter baris saat berjalan , tanpa memanfaatkan indeks apa pun.

Tidak mengherankan, ini membuat mereka seragam lambat, tidak peduli apa nilai parameter / variabel.

RBarryYoung
sumber
8

Tidak ada cara yang dijamin untuk memaksa SQL server untuk mengeksekusi kondisi klausa Anda dalam urutan tertentu. Pengoptimal akan selalu mengevaluasinya sesuai urutan yang diinginkan.

Yang dapat Anda lakukan adalah sesuatu seperti ini:

IF @LinkMode IS NULL
BEGIN
    select ...
    from ...
    WHERE (myColumn IN (...very long time exeted query...))
         ...
         ...
END
ELSE
BEGIN
    select ...
    from ...
    WHERE ...
         ...
END
Nama Layar Esoterik
sumber
3

Jika itu pilihan, gunakan pernyataan IF untuk menjalankan bentuk kueri yang sesuai. Juga, dalam SQL, Anda memberi tahu mesin db apa yang harus dilakukan, bukan bagaimana melakukannya - semuanya tidak dijalankan dari awal hingga akhir. Sulit untuk memprediksi apa yang akan dilakukan. Anda mungkin tahu ini;)

Sam
sumber
2

Dynamic SQL mungkin akan bekerja juga, karena dalam hal ini optimizer kueri harus mendapatkan nilai aktual pada saat run-time (perbaiki saya jika saya salah, saya sebenarnya tidak yakin tetapi sepertinya ingat menggunakannya untuk situasi yang sama) . Tetapi saya bersama yang lain dalam hal ini, bahwa klausa IF / ELSE akan memberikan yang terbaik bagi Anda, karena ini adalah solusi termudah dan termudah yang akan melakukan apa yang dibutuhkan.

Untuk referensi di masa mendatang jika Anda belum menggunakannya, situs jelek yang mengerikan dengan contoh kerja untuk SQL dinamis dapat ditemukan di sini misalnya: http://sqlusa.com/bestpractices/dynamicsql/

Kahn
sumber
1

Saya akan merekomendasikan konstruk IF / ELSE .. Jika karena alasan apa pun yang tidak bekerja untuk Anda, Anda selalu dapat mempertimbangkan untuk menggunakan opsi WITH RECOMPILE ..

timvw
sumber
Bisakah Anda menguraikan seperti apa bentuk "jika / selain itu"? : D
jcolebrand
Saya akan menyarankan menggunakan OPTION (WITH RECOMPILE), karena itu akan menghasilkan rencana yang ideal setiap kali - penundaan kompilasi akan menambah overhead, tapi saya curiga lebih baik secara keseluruhan dalam hal ini.
SqlRyan