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' 20
ajout à la liste dans (les lignes estimées 1902.75
plutôt que l' 1952
ajout d'une autre 96
au total générerait).
BETWEEN
semble utiliser encore une autre méthode de calcul des estimations de cardinalité.
where mpnr BETWEEN 1 AND 20
estime seulement 1829,6 lignes. Je ne sais pas comment cela est dérivé de l'histogramme montré.