次の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;
上記の計画では、削除する行の検索が予想よりも早く終了することに注意してください(スキャンから2行のみが読み取られます)。ハロウィーン保護は、通常、インメモリOLTPで正しく処理されますが、上記の要因の組み合わせに特定の問題があるようです。
このバグは SQL Server 2016 SP1 CU5 および SQL Server 2017 CU1 でfixedです。