Falha na instância estranha do SQL Server ao transmitir para numérico

20

Enquanto trabalhava com o C # Entity Framework, notei uma falha na minha instância do SQL Server.

Consegui rastreá-lo para esta declaração:

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)

A tabela fica assim:

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

A falha ocorre toda vez que inicio a consulta. Se eu reduzir o número de valores dentro da INcláusula, ele funcionará. (Ele não retorna linhas, é claro.)

Estou ciente de que os valores na INcláusula são números de 10 dígitos e a coluna possui apenas 9 dígitos, mas isso não deve levar a uma falha na instância inteira do SQL Server.

A versão do meu SQL Server é 2008 R2 em um Windows Server 2003 de 32 bits.

Isto é um erro conhecido? Existe um patch para o SQL Server?

SteLoe
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Paul White diz GoFundMonica

Respostas:

20

Consegui reproduzir novamente o R1 SP3 2008 10.00.5512, mas a instalação da CU (14) mais recente o corrigiu.

Revendo os erros corrigidos nas versões intermediárias, parece que você precisa atualizar para uma compilação que inclua a seguinte correção.

Violação de acesso ao executar uma consulta que contém muitos valores constantes em uma cláusula IN no SQL Server 2008 ou no SQL Server 2012

Como você está no 2008 R2, precisará de pelo menos CU 9 para SP1 ou CU 5 para SP2.

A descrição dos sintomas é um pouco breve, mas menciona tipos de dados incompatíveis

Quando você executa uma consulta que contém muitos valores constantes em uma cláusula IN no Microsoft SQL Server 2008, Microsoft SQL Server 2012 ou no Microsoft SQL Server 2008 R2, pode ocorrer uma violação de acesso.

Nota Para que o problema ocorra, as constantes na cláusula IN não podem corresponder exatamente ao tipo de dados da coluna.

Não define "muitos". Pelo teste que fiz, suspeito que isso possa significar "20 ou mais", pois esse parece ser o ponto de corte entre dois métodos diferentes de estimativa da cardinalidade.

O acidente estava ocorrendo dentro de alguns métodos chamados por CScaOp_In::FCalcSelectivity()com nomes como LoadHistogramFromXVariantArray()e CInMemHistogram::FJoin() -> WalkHistograms().

Por 19 ou menos itens de lista distintos, esses métodos não estavam sendo chamados. Um bug similar do SQL Sever 2000 também menciona esse ponto de corte como significativo.

Preencher uma tabela de teste com 100.000 linhas de dados de teste aleatórios com valores entre 0 e 1047 e um histograma começando da seguinte maneira

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

A pergunta

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 linhas estimadas de 1856.

É exatamente o que seria esperado obtendo as linhas estimadas para os 19 predicados de igualdade individualmente e juntando-as.

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

A fórmula não funciona mais depois 20é adicionada à lista in (linhas estimadas 1902.75em vez da 1952que adicionaria outra 96ao total geraria).

BETWEEN parece usar outro método para calcular estimativas de cardinalidade.

where mpnr BETWEEN 1 AND 20estima apenas 1829,6 linhas. Não faço ideia de como isso é derivado do histograma mostrado.

Martin Smith
fonte