Contoh SQL Server aneh crash pada casting ke numerik

20

Saat bekerja dengan C # Entity Framework saya melihat crash contoh SQL Server saya.

Saya dapat melacaknya ke pernyataan ini:

SELECT * FROM dbo.[TestTable]
where mpnr in (1099059904,
1038139906,
1048119902,
1045119902,
1002109903,
1117109910,
1111149902,
1063149902,
1117159902,
1116109904,
1105079905,
1012079906,
1129129904,
1103059905,
1065059905,
1091059906,
1110149904,
1129149903,
1083029905,
1080139904,
1076109903,
1010019902,
1058019902,
1060019903,
1053019902,
1030089902,
1018149902,
1077149902,
1010109901,
1011109901,
1000119902,
1023049903,
1107119909,
1108119909,
1106119909)

Tabelnya terlihat seperti ini:

CREATE TABLE dbo.[TestTable]([MPNR] [numeric](9, 0) NOT NULL)

Kecelakaan terjadi setiap kali saya memulai kueri. Jika saya mengurangi jumlah nilai dalam INklausa, itu berfungsi. (Tentu saja tidak mengembalikan baris.)

Saya sadar bahwa nilai-nilai dalam INklausa adalah angka 10-digit dan kolom hanya memiliki 9-digit, tetapi itu tidak menyebabkan crash seluruh contoh SQL Server.

Versi SQL Server saya adalah 2008 R2 pada Windows Server 2003 32-bit.

Apakah ini Bug yang dikenal? Apakah ada Patch untuk SQL Server?

SteLoe
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
Paul White mengatakan GoFundMonica

Jawaban:

20

Saya dapat repro pada 2008 R1 SP3 10.00.5512 tetapi menginstal CU terbaru (14) memperbaikinya.

Meninjau bug yang diperbaiki dalam versi intervensi sepertinya Anda perlu memutakhirkan ke versi yang menyertakan perbaikan berikut.

Pelanggaran akses saat Anda menjalankan kueri yang berisi banyak nilai konstan dalam klausa IN di SQL Server 2008 atau SQL Server 2012

Saat Anda menggunakan 2008 R2, Anda membutuhkan setidaknya CU 9 untuk SP1 atau CU 5 untuk SP2.

Deskripsi gejala agak singkat tetapi menyebutkan tipe data yang tidak cocok

Saat Anda menjalankan kueri yang berisi banyak nilai konstan dalam klausa IN di Microsoft SQL Server 2008, Microsoft SQL Server 2012 atau Microsoft SQL Server 2008 R2, pelanggaran akses mungkin terjadi.

Catatan Agar masalah terjadi, konstanta dalam klausa IN tidak bisa sama persis dengan tipe data kolom.

Itu tidak mendefinisikan "banyak". Dari pengujian yang saya lakukan saya menduga ini mungkin berarti "20 atau lebih" karena ini tampaknya menjadi titik potong antara dua metode yang berbeda dalam memperkirakan kardinalitas.

Kecelakaan itu terjadi di dalam beberapa metode yang disebut CScaOp_In::FCalcSelectivity()dengan nama-nama seperti LoadHistogramFromXVariantArray()dan CInMemHistogram::FJoin() -> WalkHistograms().

Untuk 19 item yang berbeda atau lebih sedikit dalam daftar, metode ini tidak dipanggil sama sekali. Sebuah mirip SQL Sever 2000 bug juga menyebutkan cut ini off point yang signifikan.

Mengisi tabel uji dengan 100.000 baris data uji acak dengan nilai antara 0 dan 1047 dan histogram dimulai sebagai berikut

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
|            0 |          0 |     104 |                   0 | 1              |
|            8 |        672 |     118 |                   7 | 96             |
|           13 |        350 |     118 |                   4 | 87.5           |
|           18 |        395 |     107 |                   4 | 98.75          |
|           23 |        384 |      86 |                   4 | 96             |
|           28 |        371 |      85 |                   4 | 92.75          |
+--------------+------------+---------+---------------------+----------------+

Kueri

SELECT * FROM dbo.[TestTable]
where mpnr in (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)
option (maxdop 1)

Menampilkan baris yang diperkirakan pada 1856.

Inilah yang diharapkan dengan mendapatkan baris yang diperkirakan untuk 19 predikat kesetaraan secara individual dan menambahkannya bersama-sama.

+-------+----------------+-------+
| 1-7   | AVG_RANGE_ROWS | 96    |
| 8     | EQ_ROWS        | 118   |
| 9-12  | AVG_RANGE_ROWS | 87.5  |
| 13    | EQ_ROWS        | 118   |
| 14-17 | AVG_RANGE_ROWS | 98.75 |
| 18    | EQ_ROWS        | 107   |
| 19    | AVG_RANGE_ROWS | 96    |
+-------+----------------+-------+

7*96 + 118 + 4*87.5 + 118 + 4*98.75 + 107 + 1*96 = 1856

Rumus tidak lagi berfungsi setelah 20ditambahkan ke dalam daftar (Diperkirakan baris 1902.75daripada 1952yang menambahkan yang lain 96untuk total akan menghasilkan).

BETWEEN tampaknya masih menggunakan metode lain untuk menghitung perkiraan kardinalitas.

where mpnr BETWEEN 1 AND 20memperkirakan hanya 1.829,6 baris. Saya tidak tahu bagaimana itu diturunkan dari histogram yang ditampilkan.

Martin Smith
sumber