Mengapa kesalahan kueri dengan hasil kosong diatur di SQL Server 2012?

31

Saat menjalankan kueri berikut di MS SQL Server 2012 kueri kedua gagal tetapi bukan yang pertama. Juga, ketika dijalankan tanpa klausa di mana kedua kueri akan gagal. Saya bingung mengapa keduanya gagal karena keduanya harus memiliki set hasil kosong. Bantuan / wawasan apa pun dihargai.

create table #temp
(id     int primary key)

create table #temp2
(id     int)

select 1/0
from #temp
where id = 1

select 1/0
from #temp2
where id = 1
DavidN
sumber

Jawaban:

39

Tampilan awal pada rencana eksekusi menunjukkan bahwa ekspresi 1/0didefinisikan dalam operator Compute Scalar:

Rencana grafis

Sekarang, meskipun rencana eksekusi mulai dijalankan di paling kiri, iteratif memanggil Opendan GetRowmetode pada iterator anak untuk mengembalikan hasil, SQL Server 2005 dan kemudian berisi optimasi di mana ekspresi sering hanya didefinisikan oleh Compute Scalar, dengan evaluasi ditunda hingga berikutnya operasi membutuhkan hasilnya :

Hitung operator Scalar yang muncul di Showplans yang dihasilkan oleh SET STATISTICS XML mungkin tidak mengandung elemen RunTimeInformation.  Dalam Tampilan grafis, Baris Aktual, Rebind Aktual, dan Rewind Aktual mungkin tidak ada dari jendela Properties ketika opsi Include Actual Execution Plan dipilih di SQL Server Management Studio.  Ketika ini terjadi, itu berarti bahwa meskipun operator ini digunakan dalam rencana kueri yang dikompilasi, pekerjaan mereka dilakukan oleh operator lain dalam rencana kueri run-time.  Perhatikan juga bahwa jumlah eksekusi dalam output Showplan yang dihasilkan oleh SET STATISTICS PROFIL sama dengan jumlah rebind dan rewind di Showplans yang dihasilkan oleh SET STATISTICS XML.  Dari: Buku MSDN Online

Dalam kasus ini, hasil ekspresi hanya diperlukan ketika merakit baris untuk kembali ke klien (yang dapat Anda pikirkan terjadi pada SELECTikon hijau ). Dengan logika itu, evaluasi yang ditunda akan berarti ekspresi tidak pernah dievaluasi karena tidak ada rencana yang menghasilkan baris kembali. Untuk sedikit mengusahakan poin, baik Indeks Clustered Seek maupun Table Scan tidak mengembalikan baris, jadi tidak ada baris untuk berkumpul untuk kembali ke klien.

Namun, ada optimasi terpisah di mana beberapa ekspresi dapat diidentifikasi sebagai konstanta runtime dan dievaluasi sekali sebelum eksekusi permintaan dimulai . Dalam hal ini, indikasi yang telah terjadi ini dapat ditemukan di showplan XML (rencana Pencarian Indeks Berkelompok di sebelah kiri, rencana Pemindaian Tabel di sebelah kanan):

XML Showplan

Saya menulis lebih banyak tentang mekanisme yang mendasari dan bagaimana mereka dapat mempengaruhi kinerja dalam posting blog ini . Dengan menggunakan informasi yang disediakan di sana, kami dapat memodifikasi kueri pertama sehingga kedua ekspresi dievaluasi dan di-cache sebelum eksekusi dimulai:

select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

Sekarang, paket pertama juga berisi referensi ekspresi konstan, dan kedua kueri menghasilkan pesan kesalahan. XML untuk kueri pertama berisi:

Ekspresi Konstan

Informasi lebih lanjut: Hitung Skalar, Ekspresi, dan Kinerja

Paul White mengatakan GoFundMonica
sumber
21

Saya akan menebak dengan cerdas (dan dalam proses mungkin menarik guru SQL Server yang mungkin memberikan jawaban yang sangat rinci).

Kueri pertama mendekati eksekusi sebagai:

  1. Pindai indeks kunci utama
  2. Cari nilai dalam tabel data yang diperlukan untuk kueri

Itu memilih jalur ini karena Anda memiliki whereklausa pada kunci utama. Tidak pernah sampai ke langkah kedua, jadi kueri tidak gagal.

Yang kedua tidak memiliki kunci utama untuk dijalankan, sehingga mendekati kueri sebagai:

  1. Lakukan pemindaian tabel penuh data dan ambil nilai yang diperlukan

Salah satu nilai tersebut adalah 1/0penyebab masalah.

Ini adalah contoh dari SQL Server mengoptimalkan permintaan. Sebagian besar, ini adalah hal yang baik. SQL Server akan memindahkan kondisi dari selectoperasi pemindaian tabel. Ini sering menyimpan langkah-langkah dalam evaluasi permintaan.

Namun, pengoptimalan ini bukan hal yang baik. Bahkan, tampaknya melanggar dokumentasi SQL Server itu sendiri yang mengatakan bahwa whereklausa dievaluasi sebelum select. Yah, mereka mungkin punya beberapa penjelasan ilmiah untuk apa artinya ini. Namun, bagi kebanyakan manusia, pemrosesan secara logis wheresebelum selectartinya (antara lain) "tidak menghasilkan selectkesalahan-klausa pada baris yang tidak dikembalikan ke pengguna".

Gordon Linoff
sumber
1
+1 tidak tahu apakah Anda benar, tetapi jawaban terbaik yang dapat saya lihat mengingat satu-satunya perbedaan adalah kunci utama.
1
@GordonLinoff Paul Randal baru saja mengkonfirmasi melalui Twitter bahwa balasan Anda benar-benar diterima.
SchmitzIT
4
@Still, urutan eksekusi yang sebenarnya, namun berbeda, tidak boleh mengarah ke pesan kesalahan seperti itu.
ypercubeᵀᴹ
7
@ypercube Erland Sommarskog akan setuju dengan Anda (Hubungkan item)
Paul White mengatakan GoFundMonica
2
Terima kasih atas penunjuknya - Saya masuk dan membatalkan permintaan.
Gordon Linoff