我能够跟踪到这个陈述:
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)
该表如下所示:
CREATE TABLE dbo.[TestTable]([MPNR] [numeric](9,0) NOT NULL)
每次启动查询时都会发生崩溃.如果我减少IN子句中的值的数量,它的工作原理. (当然,它不返回任何行.)
我知道IN子句中的值是10位数字,列只有9位数,但这不应该导致整个sql Server实例崩溃.
我的sql Server版本是Windows Server 2003 32位上的2008 R2.
解决方法
查看介入版本中修复的错误,看起来好像需要升级到包含以下修复的构建.
在2008 R2上,您至少需要CU 9 for SP1或CU 5 for SP2.
症状的描述有些简短,但提到了不匹配的数据类型
When you run a query that contains many constant values in an IN
clause in Microsoft sql Server 2008,Microsoft sql Server 2012 or in
Microsoft sql Server 2008 R2,an access violation might occur.Note For the issue to occur,the constants in the IN clause cannot
match exactly with the column data type.
它没有定义“很多”.从我做的测试中我怀疑这可能意味着“20或更多”,因为这似乎是两种估算基数的不同方法之间的截止点.
崩溃发生在CScaOp_In :: FCalcSelectivity()调用的几个方法中,其名称如LoadHistogramFromXVariantArray()和CInMemHistogram :: FJoin() – > WalkHistograms().
对于19个或更少的不同列表项,这些方法根本没有被调用. A similar SQL Sever 2000 bug也提到这个截止点是重要的.
使用值为0到1047之间的100,000行随机测试数据填充测试表,并按如下方式开始直方图
+--------------+------------+---------+---------------------+----------------+ | 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 | +--------------+------------+---------+---------------------+----------------+
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)
显示估计的行数为1856.
这正是通过单独获取19个等式谓词的估计行并将它们加在一起所预期的结果.
+-------+----------------+-------+ | 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
在将20添加到列表中后,该公式不再有效(估计行1902.75而不是1952年,将生成另外96个将生成).
BETWEEN似乎还在使用另一种计算基数估算的方法.
其中mpnr BETWEEN 1和20估计只有1829.6行.我不知道这是如何从显示的直方图得出的.