Niepoprawne zachowanie programu SQL Server 2016 z tabelami zoptymalizowanymi pod kątem pamięci

13

Proszę spojrzeć na następujące zapytanie 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

Podczas wykonywania go w programie SQL Server 2014 (12.0.4100.1 X64) UPDATEkwerenda działa zgodnie z oczekiwaniami i zwracany jest następujący poprawny wynik:

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

Jednak podczas wykonywania na SQL Server 2016 (13.0.4001.0 X64) nie wszystkie wiersze są aktualizowane i zwracane są następujące informacje:

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

Dla mnie to wygląda na błąd, prawda?

Dmitrij Savchenko
źródło
Tak, to jest błąd. Testowałem go na SQL 2017 CTP 2.1 i zachowuje się tak samo jak na SQL 2016.
Dean Savović

Odpowiedzi:

12

Tak, jest to błąd, który wydaje się wpływać tylko na zmienne tabeli, z metodą dostępu do indeksu bw-tree i nieskorelowanym samozłączeniem.

Uproszczone repro przy użyciu 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;

Wadliwy plan

Uwaga: w powyższym planie poszukiwanie wierszy do usunięcia kończy się wcześniej niż oczekiwano (tylko dwa wiersze są odczytywane ze skanu). Ochrona Halloween jest ogólnie poprawnie obsługiwana dla OLTP w pamięci, po prostu wydaje się, że istnieje konkretny problem z kombinacją czynników wymienionych powyżej.


Ten błąd został naprawiony w SQL Server 2016 SP1 CU5 i SQL Server 2017 CU1 :

Paul White 9
źródło