Perilaku SQL Server 2016 yang salah dengan tabel yang dioptimalkan memori

13

Silakan lihat kueri SQL berikut:

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

Ketika menjalankannya di SQL Server 2014 (12.0.4100.1 X64), UPDATEdalam kueri melakukan seperti yang diharapkan dan hasil yang valid berikut dikembalikan:

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

Namun, ketika mengeksekusi pada SQL Server 2016 (13.0.4001.0 X64) tidak semua baris diperbarui dan berikut ini dikembalikan:

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

Ini terlihat seperti bug bagi saya, apakah itu terlihat bagi Anda?

Dmitry Savchenko
sumber
Ya, ini bug. Mengujinya pada SQL 2017 CTP 2.1 dan berperilaku sama seperti pada SQL 2016.
Dean Savović

Jawaban:

12

Ya itu adalah bug, yang tampaknya hanya mempengaruhi variabel tabel, dengan metode akses indeks bw-tree, dan self-join yang tidak berkorelasi.

Repro yang disederhanakan menggunakan 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;

Rencana yang salah

Catatan dalam paket di atas, pencarian baris yang akan dihapus berakhir lebih awal dari yang diharapkan (hanya dua baris yang dibaca dari pemindaian). Halloween Protection secara umum ditangani dengan benar untuk OLTP Dalam Memori, sepertinya ada masalah khusus dengan kombinasi faktor-faktor yang disebutkan di atas.


Bug ini diperbaiki di SQL Server 2016 SP1 CU5 dan SQL Server 2017 CU1 :

Paul White 9
sumber