1

我有算術溢出值插入一個查找表的行-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個獨特值。

有人可以解釋這個嗎?

+0

我也隨後被測試場景中我絕對插入不到使用方法2中的255限制上述定義的:我創建(約)200個唯一的記錄設置一個值,並將其插入。我創建了一個具有55個(新)記錄的唯一值集合,並插入了前面的200個記錄。該查詢正確地標識了其中的200個已經存在並且不會嘗試插入;但即使這種方法產生溢出。 – user1884677 2013-04-22 20:46:54

回答

0

使用IGNORE_DUP_KEY的事件的序列是:

  1. 記錄被用於插入件製備,包括標識值的消耗。這使得IDENTITY序列上升到200
  2. 記錄被插入。 IGNORE_DUP_KEY觀察和插入被默默失敗

現在你的失敗批插入的實際產生的標識值201-300,爲此,任何超過255溢出的tinyint列。

這是平凡運行

select ident_current('tmp_ID10T_Test') 

寬鬆整個代碼驗證。因此,對於你的代碼,有註釋如下:

-- Method 1 - Simple INSERT INTO: Expect Approx. (100 row(s) affected) 
    -- ident_current = 1 

-- Method 2 - LEFT OUTER JOIN WHERE NULL to prevent dupes. 
    -- ident_current = 100 
    -- NOTE: The SELECT doesn't produce any rows. No rows to insert 

-- Repeat Method 1: Duplicate key was ignored (0 row(s) affected). 
    -- ident_current = 200 
    -- NOTE: SELECT produced 100 rows, which consumed IDENTITY numbers. Later ignored 

-- Repeat Method 1: Expected: Arithmetic overflow error converting IDENTITY to data type tinyint. 
    -- ident_current = 255 
    -- error raised when IDENTITY reaches 256 
+0

我懷疑可能是這種情況 - 我不理解的是爲什麼當前的身份種子持有,或者我沒有終止批處理?例如 - 輸入第一批100個(標識值現在是表中的100個記錄);第二批准備(100個假設記錄+ 100個硬化記錄)並消耗。 200仍然低於255的限制,但是沒有插入新記錄(如果不清楚,我不會重新創建基本測試中設置的值)。 第三批准備;我仍然有100個原始值和100個副本(但身份現在是300)。 – user1884677 2013-04-22 22:21:12

+0

'爲什麼當前的身份種子持有'?它被生成來填充構成INSERT基礎的記錄集。之後插入物在DUPLICATE IGNORE的流產。 IDENTITY序列在被拍攝後從未返回到流中。否則,對於高寫入事務表,您將遇到嚴重的併發問題。 – RichardTheKiwi 2013-04-22 22:24:02

+0

什麼可以重置它呢?如果一張桌子基本上被鬼魂記錄填滿了,那麼插入的唯一性檢查失敗會是荒謬的。 – user1884677 2013-04-22 22:38:35