Sql-Server

記憶體優化表的 SQL Server 2016 行為不正確

  • November 29, 2019

請查看以下 SQL 查詢:

CREATE TYPE dbo.IN_MEMORY_TABLE_TYPE AS TABLE
(
 source_col INT NULL,
 target_col INT not NULL
 INDEX ix_InMemoryTable NONCLUSTERED (target_col)
)
WITH (MEMORY_OPTIMIZED = ON)
GO

DECLARE
 @t dbo.IN_MEMORY_TABLE_TYPE

INSERT @t
(
 source_col,
 target_col
)
VALUES
 (10, 0),
 (0, 0)

UPDATE r1
SET
 target_col = -1
FROM @t r1
WHERE EXISTS
     (
       SELECT *
       FROM @t r2
       WHERE r2.source_col > 0
     )

SELECT *
FROM @t

GO
DROP TYPE dbo.IN_MEMORY_TABLE_TYPE

在 SQL Server 2014 (12.0.4100.1 X64) 上UPDATE執行時,查詢按預期執行,並返回以下有效結果:

source_col | target_col
----------------------
10 | -1
0 | -1

但是,在 SQL Server 2016 (13.0.4001.0 X64) 上執行時,並非所有行都得到更新,並返回以下內容:

source_col | target_col
----------------------
10 | -1
0 | 0

這在我看來像一個錯誤,在你看來是這樣嗎?

是的,這是一個錯誤,它似乎只影響表變數,具有 bw-tree 索引訪問方法和不相關的自連接。

使用以下簡化再現DELETE

CREATE TYPE dbo.IN_MEMORY_TABLE_TYPE AS TABLE
(
   col integer NOT NULL INDEX i NONCLUSTERED (col)
)
WITH (MEMORY_OPTIMIZED = ON);
GO
DECLARE @T AS dbo.IN_MEMORY_TABLE_TYPE;

INSERT @T (col)
VALUES (1), (2), (3), (4), (5);

DELETE T
FROM @T AS T
WHERE EXISTS 
(
   SELECT 1
   FROM @T AS T2
   WHERE T2.col = 1 -- Vary this number 1-5
);

SELECT T.col FROM @T AS T;
GO
DROP TYPE dbo.IN_MEMORY_TABLE_TYPE;

錯誤的計劃

請注意,在上面的計劃中,要刪除的行的搜尋比預期的要早終止(從掃描中只讀取了兩行)。對於記憶體中 OLTP,萬聖節保護通常得到了正確處理,只是上述因素的組合似乎存在一個特定問題。


此錯誤已在SQL Server 2016 SP1 CU5SQL Server 2017 CU1中修復

引用自:https://dba.stackexchange.com/questions/176667