我有算术溢出值插入一个查找表的行-ID设置为TINYINT数据类型的错误。这不是唯一记录数超过255个值的情况。这是比较不寻常的,并且在该设置的第一次测试中没有发生。SQL算术溢出的标识插入
量产版下面却只有66个唯一值的代码,但它可能是新的值可以加入(缓慢,非常小的数字),随着时间的推移... 255可用插槽应该是绰绰有余这个分析过程的寿命。
我最初的想法是,它可能是由于识别分层源表超过255个值(事实上有1028个)的缓存计划,并且评估这可能会超出目标表的容量。我已经测试过,但这不是真的。
-- This table represents a small (tinyint) subset of unique primary values.
CREATE TABLE #tmp_ID10T_Test (
ID10T_Test_ID tinyint identity (1,1) not null,
ID10T_String varchar(255) not null
PRIMARY KEY CLUSTERED
(ID10T_String ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) ON [PRIMARY]
-- This table represents a larger (smallint) set of non-unique source values, defined by a secondary key value (Value_Set).
CREATE TABLE #tmp_ID10T_Values (
ID10T_Value_ID smallint identity (1,1) not null,
ID10T_Value_Set tinyint not null,
ID10T_String varchar(255) not null
) ON [PRIMARY]
-- Create the initial dataset - 100 unique records; The insertion tests below illustrate that the INDEX is working
-- correctly on the primary key field for repetative values, however something is happening with the IDENTITY field...
DECLARE @ID10T tinyint
, @i tinyint -- A randomized value to determine which subset of printable ASCII characters will be used for the string.
, @String varchar(255)
SET @ID10T = 0
WHILE @ID10T < 100
BEGIN
SET @String = ''
WHILE LEN(@String) < (1+ROUND((254 * RAND(CHECKSUM(NEWID()))),0))
BEGIN
SELECT @i = (1 + ROUND((2 * RAND()),0)) -- Randomize which printable character subset is drawn from.
SELECT @String = @String + ISNULL(CASE WHEN @i = 1 THEN char(48 + ROUND(((57-48)* RAND(CHECKSUM(NEWID()))),0))
WHEN @i = 2 THEN char(65 + ROUND(((90-65) * RAND(CHECKSUM(NEWID()))),0))
WHEN @i = 3 THEN char(97 + ROUND(((122-97) * RAND(CHECKSUM(NEWID()))),0))
END,'-')
END
INSERT INTO #tmp_ID10T_Values (ID10T_Value_Set, ID10T_String)
SELECT 1, @String
SET @ID10T = @ID10T + 1
END
-- Demonstrate that IGNORE_DUP_KEY = ON works for primary key index on string-field
SELECT * FROM #tmp_ID10T_Values
-- Method 1 - Simple INSERT INTO: Expect Approx. (100 row(s) affected)
INSERT INTO #tmp_ID10T_Test (ID10T_String)
SELECT DISTINCT ID10T_String
FROM #tmp_ID10T_Values
GO
-- Method 2 - LEFT OUTER JOIN WHERE NULL to prevent dupes.
-- this is the test case to determine whether the procedure cache is mixing plans
INSERT INTO #tmp_ID10T_Test (ID10T_String)
SELECT DISTINCT T1.ID10T_String
FROM #tmp_ID10T_Values AS T1
LEFT OUTER JOIN #tmp_ID10T_Test AS t2
ON T1.ID10T_String = T2.ID10T_String
WHERE T2.ID10T_Test_ID IS NULL
GO
-- Repeat Method 1: Duplicate key was ignored (0 row(s) affected).
INSERT INTO #tmp_ID10T_Test (ID10T_String)
SELECT DISTINCT ID10T_String
FROM #tmp_ID10T_Values
GO
这似乎不是一个查询计划缓存问题 - 我应该看到方法1的算术错误重新测试,如果这是真的。
-- Repeat Method 1: Expected: Arithmetic overflow error converting IDENTITY to data type tinyint.
INSERT INTO #tmp_ID10T_Test (ID10T_String)
SELECT DISTINCT ID10T_String
FROM #tmp_ID10T_Values
GO
我特别好奇为什么会抛出异常。我可以理解,在方法1中,所有100个唯一值都经过测试......因此,可以想象,查询代理在第二次插入尝试后会看到200条记录的潜在可能;我不明白为什么它会在第三次重复后看到300条记录的潜力 - 第二次尝试导致0行,因此最多可能有200个独特值。
有人可以解释这个吗?
我也随后被测试场景中我绝对插入不到使用方法2中的255限制上述定义的:我创建(约)200个唯一的记录设置一个值,并将其插入。我创建了一个具有55个(新)记录的唯一值集合,并插入了前面的200个记录。该查询正确地标识了其中的200个已经存在并且不会尝试插入;但即使这种方法产生溢出。 – user1884677 2013-04-22 20:46:54