Comportement incorrect de SQL Server 2016 avec des tables optimisées en mémoire

13

Veuillez consulter la requête SQL suivante:

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

Lors de son exécution sur SQL Server 2014 (12.0.4100.1 X64), UPDATEla requête s'exécute comme prévu et le résultat valide suivant est renvoyé:

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

Cependant, lors de l'exécution sur SQL Server 2016 (13.0.4001.0 X64), toutes les lignes ne sont pas mises à jour et ce qui suit est renvoyé:

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

Cela ressemble à un bug pour moi, est-ce que ça vous ressemble?

Dmitry Savchenko
la source
Ouais, c'est un bug. Testé sur SQL 2017 CTP 2.1 et il se comporte de la même manière que sur SQL 2016.
Dean Savović

Réponses:

12

Oui, c'est un bogue, qui semble n'affecter que les variables de table, avec une méthode d'accès à l'index bw-tree et une auto-jointure non corrélée.

Repro simplifié utilisant 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;

Plan défectueux

Notez dans le plan ci-dessus que la recherche de lignes à supprimer se termine plus tôt que prévu (seules deux lignes sont lues à partir de l'analyse). La protection Halloween est généralement correctement gérée pour l'OLTP en mémoire, il semble qu'il y ait juste un problème spécifique avec la combinaison des facteurs mentionnés ci-dessus.


Ce bogue est résolu dans SQL Server 2016 SP1 CU5 et SQL Server 2017 CU1 :

Paul White 9
la source