Error extraño de instancia de SQL Server al convertir a numérico

20

Mientras trabajaba con C # Entity Framework, noté un bloqueo de mi instancia de SQL Server.

Pude rastrearlo hasta esta declaración:

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)

La tabla se ve así:

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

El bloqueo ocurre cada vez que inicio la consulta. Si reduzco el número de valores dentro de la INcláusula, funciona. (No devuelve filas, por supuesto).

Soy consciente de que los valores en la INcláusula son números de 10 dígitos y la columna tiene solo 9 dígitos, pero eso no debería conducir a un bloqueo de toda la instancia de SQL Server.

La versión de mi SQL Server es 2008 R2 en un Windows Server 2003 de 32 bits.

¿Es esto un error conocido? ¿Hay un parche para SQL Server?

SteLoe
fuente
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Paul White dice GoFundMonica

Respuestas:

20

Pude repro en 2008 R1 SP3 10.00.5512 pero la instalación de la última CU (14) lo arregló.

Al revisar los errores corregidos en las versiones intermedias, parece que necesita actualizar a una compilación que incluye la siguiente corrección.

Infracción de acceso cuando ejecuta una consulta que contiene muchos valores constantes en una cláusula IN en SQL Server 2008 o en SQL Server 2012

Como está en 2008 R2, necesitará al menos 9 u.m. para SP1 o 5 u.m. para SP2.

La descripción de los síntomas es algo breve pero menciona tipos de datos no coincidentes

Cuando ejecuta una consulta que contiene muchos valores constantes en una cláusula IN en Microsoft SQL Server 2008, Microsoft SQL Server 2012 o en Microsoft SQL Server 2008 R2, puede producirse una infracción de acceso.

Nota Para que se produzca el problema, las constantes en la cláusula IN no pueden coincidir exactamente con el tipo de datos de la columna.

No define "muchos". Según las pruebas que hice, sospecho que esto puede significar "20 o más", ya que este parece ser el punto de corte entre dos métodos diferentes para estimar la cardinalidad.

El bloqueo estaba ocurriendo dentro de un par de métodos llamados CScaOp_In::FCalcSelectivity()con nombres como LoadHistogramFromXVariantArray()y CInMemHistogram::FJoin() -> WalkHistograms().

Para 19 o menos elementos distintos en la lista, estos métodos no fueron llamados en absoluto. Un error similar de SQL Sever 2000 también menciona este punto de corte como significativo.

Rellenar una tabla de prueba con 100,000 filas de datos de prueba aleatorios con valores entre 0 y 1047 y un histograma que comienza de la siguiente manera

+--------------+------------+---------+---------------------+----------------+
| 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 consulta

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)

Muestra filas estimadas de 1856.

Esto es exactamente lo que se esperaría al obtener las filas estimadas para los 19 predicados de igualdad individualmente y sumarlos.

+-------+----------------+-------+
| 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 fórmula ya no funciona después de 20agregarla a la lista de entrada (filas estimadas en 1902.75lugar de la 1952que 96generaría agregar otra al total).

BETWEEN parece utilizar otro método para calcular las estimaciones de cardinalidad.

where mpnr BETWEEN 1 AND 20estima solo 1829.6 filas. No tengo idea de cómo se deriva eso del histograma que se muestra.

Martin Smith
fuente