Saya memiliki masalah kompilasi permintaan aneh yang sulit untuk direproduksi. Ini hanya terjadi di bawah beban tinggi dan tidak dapat dengan mudah diulang.
- Ada tabel T dengan kolom A, B, C, D.
- Ada indeks cluster yang tidak unik pada T (A, B, C, D).
- Ada query SELECT * DARI T DI MANA A = @ P1 DAN B = @ P2 DAN (C = @ P3 ATAU C = @ P4) DAN D = @ P5. Kondisi pencarian ada di semua kolom indeks berkerumun, kolom ke-3 memiliki OR.
Masalahnya adalah bahwa rencana kueri untuk kueri ini hanya mencari Predikat pada A dan B! Predikat pada C dan D adalah predikat biasa, jadi ini berarti bahwa pohon pencarian pada kolom C dan D tidak digunakan.
Tipe data untuk semua parameter cocok dengan tipe data kolom.
Adakah yang bisa memberikan petunjuk mengapa ini bisa terjadi? Versi SQL adalah 2008 R2 (SP1) - 10.50.2789.0 (X64)
OPTION (RECOMPILE)
?Jawaban:
Untuk kueri parameterised, ia tidak bisa hanya melakukan dua pencarian saja
dan
Karena jika
@P3 = @P4
itu salah akan mengembalikan baris duplikat. Jadi perlu operator yang menghapus duplikat dari ini terlebih dahulu.Dari tes cepat akhir ini tampaknya tergantung pada ukuran tabel apakah Anda mendapatkannya atau tidak. Dalam tes di bawah
245
/246
baris adalah titik cut off antara rencana (ini juga merupakan titik cut off antara indeks yang cocok semua pada satu halaman dan itu menjadi 2 halaman daun dan halaman root).1 Halaman / 245 baris
Rencana ini memiliki pencarian
A=1 AND B=2
dengan predikat residu aktif(C=@C1 OR C=@C2) AND D=5
2 lembar daun / 246 baris
Dalam paket kedua, operator tambahan bertanggung jawab untuk menghapus duplikat dari yang
@C1,@C2
pertama sebelum melakukan pencarian.Pencarian dalam rencana kedua sebenarnya adalah kisaran pencarian antara
A=1 AND B=2 AND C > Expr1010
danA=1 AND B=2 AND C < Expr1011
dengan predikat residu aktifD=5
. Itu masih bukan pencarian kesetaraan di semua 4 kolom. Informasi lebih lanjut tentang operator paket tambahan dapat ditemukan di sini .Menambahkan
OPTION (RECOMPILE)
memang memungkinkan untuk memeriksa nilai parameter untuk duplikat pada waktu kompilasi dan menghasilkan rencana dengan dua upaya kesetaraan.Anda juga bisa mencapainya dengan
Tetapi sebenarnya dalam kasus uji ini kemungkinan akan menjadi kontra produktif karena memiliki dua berusaha ke dalam indeks halaman tunggal daripada satu meningkatkan IO logis.
sumber
select .. union select ...
juga akan memberi Anda dua upaya ditambah langkah tambahan untuk menghapus duplikat dari hasilnya.SELECT * FROM T WHERE A=1 AND B=2 AND C=@C1 AND D=5 UNION SELECT * FROM T WHERE A=1 AND B=2 AND C=@C2 AND D=5
bisa salah menghapus duplikat yang harus dikembalikan. Dalam contoh data saya di mana saya malas mengisi semua dengan nilai yang sama itu akan mengembalikan 1 baris tidak256
Sepenuhnya setuju dengan analisis Martin. Kueri ini tidak dapat menghasilkan pencarian pada semua 4 kolom karena predikat ATAU, kecuali (mungkin) dengan OPTION (RECOMPILE). Saya menduga ini adalah pertanyaan jarum-in-a-tumpukan jerami, Anda mungkin tidak ingin overhead tambahan.
Bagaimana dengan ini:
Saya tidak menguji ini tetapi bagian lain harus memberikan 2 berusaha pada semua 4 nilai dan penyatuan murah melalui penggabungan. Dalam kasus ketika keduanya berusaha berakhir di halaman yang sama saya tidak berpikir bahwa membaca halaman ekstra logis akan menambah banyak waktu Namun, tergantung pada data Anda, keduanya berusaha sangat mungkin berada di halaman yang berbeda.
sumber