Bizarre crash d'instance SQL Server lors de la conversion en numérique

20

En travaillant avec C # Entity Framework, j'ai remarqué un plantage de mon instance SQL Server.

J'ai pu le retrouver jusqu'à cette déclaration:

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)

Le tableau ressemble à ceci:

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

Le plantage se produit chaque fois que je lance la requête. Si je réduis le nombre de valeurs dans la INclause, cela fonctionne. (Il ne renvoie aucune ligne, bien sûr.)

Je suis conscient que les valeurs de la INclause sont des nombres à 10 chiffres et que la colonne n'a que 9 chiffres, mais cela ne devrait pas conduire à un crash de toute l'instance SQL Server.

La version de My SQL Server est 2008 R2 sur Windows Server 2003 32 bits.

Est-ce un bug connu? Existe-t-il un correctif pour SQL Server?

SteLoe
la source
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Paul White dit GoFundMonica

Réponses:

20

J'ai pu faire une repro sur 2008 R1 SP3 10.00.5512 mais l'installation de la dernière CU (14) l'a corrigé.

En examinant les bogues corrigés dans les versions intermédiaires, il semble que vous deviez mettre à niveau vers une version qui comprend le correctif suivant.

Violation d'accès lorsque vous exécutez une requête qui contient de nombreuses valeurs constantes dans une clause IN dans SQL Server 2008 ou SQL Server 2012

Comme vous êtes sur 2008 R2, vous aurez besoin d'au moins CU 9 pour SP1 ou CU 5 pour SP2.

La description des symptômes est quelque peu brève mais mentionne des types de données incompatibles

Lorsque vous exécutez une requête qui contient de nombreuses valeurs constantes dans une clause IN dans Microsoft SQL Server 2008, Microsoft SQL Server 2012 ou dans Microsoft SQL Server 2008 R2, une violation d'accès peut se produire.

Remarque Pour que le problème se produise, les constantes de la clause IN ne peuvent pas correspondre exactement au type de données de la colonne.

Il ne définit pas "beaucoup". D'après les tests que j'ai faits, je soupçonne que cela peut signifier "20 ou plus" car cela semble être le point de coupure entre deux méthodes différentes d'estimation de la cardinalité.

Le crash se produisait à l'intérieur de deux méthodes appelées par CScaOp_In::FCalcSelectivity()des noms tels que LoadHistogramFromXVariantArray()et CInMemHistogram::FJoin() -> WalkHistograms().

Pour 19 éléments de liste distincts ou moins, ces méthodes n'étaient pas du tout appelées. Un bogue similaire à SQL Sever 2000 mentionne également ce point de coupure comme significatif.

Remplissage d'une table de test avec 100 000 lignes de données de test aléatoires avec des valeurs comprises entre 0 et 1047 et un histogramme commençant comme suit

+--------------+------------+---------+---------------------+----------------+
| 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 requête

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)

Affiche les rangées estimées de 1856.

C'est exactement ce à quoi on pourrait s'attendre en obtenant les lignes estimées pour les 19 prédicats d'égalité individuellement et en les additionnant.

+-------+----------------+-------+
| 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 formule ne fonctionne plus après l' 20ajout à la liste dans (les lignes estimées 1902.75plutôt que l' 1952ajout d'une autre 96au total générerait).

BETWEEN semble utiliser encore une autre méthode de calcul des estimations de cardinalité.

where mpnr BETWEEN 1 AND 20estime seulement 1829,6 lignes. Je ne sais pas comment cela est dérivé de l'histogramme montré.

Martin Smith
la source