Sono stato in grado di riprogrammare su R1 SP3 2008 10.00.5512 del 2008, ma l'installazione dell'ultima CU (14) l'ha risolto.
Esaminando i bug corretti nelle versioni intermedie sembra che sia necessario eseguire l'aggiornamento a una build che include la seguente correzione.
Accedere alla violazione quando si esegue una query che contiene molti valori costanti in una clausola IN in SQL Server 2008 o in SQL Server 2012
Dato che sei su 2008 R2 avrai bisogno di almeno CU 9 per SP1 o CU 5 per SP2.
La descrizione dei sintomi è piuttosto breve ma menziona tipi di dati non corrispondenti
Quando si esegue una query che contiene molti valori costanti in una clausola IN in Microsoft SQL Server 2008, Microsoft SQL Server 2012 o in Microsoft SQL Server 2008 R2, potrebbe verificarsi una violazione di accesso.
Nota Affinché il problema si verifichi, le costanti nella clausola IN non possono corrispondere esattamente al tipo di dati della colonna.
Non definisce "molti". Dal test che ho fatto sospetto che questo possa significare "20 o più" in quanto questo sembra essere il punto di interruzione tra due diversi metodi di stima della cardinalità.
L'incidente si stava verificando all'interno di un paio di metodi chiamati CScaOp_In::FCalcSelectivity()
con nomi come LoadHistogramFromXVariantArray()
e CInMemHistogram::FJoin() -> WalkHistograms()
.
Per 19 o meno voci distinte nell'elenco, questi metodi non venivano affatto richiamati. Un simile bug di SQL Sever 2000 menziona anche questo punto di interruzione come significativo.
Popolazione di una tabella di test con 100.000 righe di dati di test casuali con valori compresi tra 0 e 1047 e un istogramma che inizia come segue
+--------------+------------+---------+---------------------+----------------+
| 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 |
+--------------+------------+---------+---------------------+----------------+
La domanda
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)
Mostra le file stimate del 1856.
Questo è esattamente ciò che ci si aspetterebbe ottenendo le righe stimate per i 19 predicati di uguaglianza individualmente e sommandoli insieme.
+-------+----------------+-------+
| 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
La formula non funziona più dopo 20
essere stata aggiunta all'elenco in (Righe stimate 1902.75
anziché che ne verrebbe generata l' 1952
aggiunta di un'altra 96
al totale).
BETWEEN
sembra usare ancora un altro metodo per calcolare le stime di cardinalità.
where mpnr BETWEEN 1 AND 20
stima solo 1829,6 righe. Non ho idea di come derivi dall'istogramma mostrato.