Czy to błąd w SQL Server 2016?
Tak. Zdecydowanie nie jest to właściwe zachowanie. Zgłosiłem to tutaj i został naprawiony w SQL Server 2016 SP2 CU9 .
Jak mówi Mikael Eriksson w komentarzach sys.database_scoped_configurations
i sys.dm_exec_sessions
są realizowane jako widoki w formacie
SELECT ...
FROM OpenRowset(TABLE xxxx)
Jednak porównanie dwóch poniższych planów jest oczywistą różnicą.
DBCC TRACEON(3604);
DECLARE @database_scoped_configurations TABLE(x INT);
INSERT INTO @database_scoped_configurations
SELECT configuration_id
FROM sys.database_scoped_configurations
OPTION (QUERYTRACEON 8608, QUERYTRACEON 8615, QUERYTRACEON 8619, QUERYTRACEON 8620 );
DECLARE @dm_exec_sessions TABLE(x INT);
INSERT INTO @dm_exec_sessions
SELECT session_id
FROM sys.dm_exec_sessions
OPTION (QUERYTRACEON 8608, QUERYTRACEON 8615, QUERYTRACEON 8619, QUERYTRACEON 8620 );
Dane wyjściowe flagi śledzenia 8619 dla obu tych zapytań pokazują
Zastosuj regułę: EnforceHPandAccCard - x0-> Spool or Top (x0)
SQL Server najwyraźniej nie jest w stanie ustalić, czy źródło TVF nie jest również celem wstawiania, więc wymaga ochrony na Halloween.
W przypadku sesji zostało to zaimplementowane jako bufor, który najpierw przechwytuje wszystkie wiersze. W database_scoped_configurations
dodając a TOP 1
do planu. Zastosowanie ochrony TOP
na Halloween omówiono w tym artykule . W artykule wspomniano również o nieudokumentowanej fladze śledzenia, która wymusza buforowanie, a nie TOP
działa zgodnie z oczekiwaniami.
DECLARE @database_scoped_configurations TABLE(x INT);
INSERT INTO @database_scoped_configurations
SELECT configuration_id
FROM sys.database_scoped_configurations
OPTION (QUERYTRACEON 8692)
Oczywistym problemem związanym z używaniem TOP 1
zamiast szpuli jest to, że arbitralnie ogranicza liczbę wstawionych wierszy. Byłoby to prawidłowe tylko wtedy, gdy liczba wierszy zwróconych przez funkcję wynosiła <= 1.
Wstępna notatka wygląda następująco
Porównaj to z początkową notatką dla zapytania 2
Jeśli dobrze rozumiem powyższe, to wydaje się, że pierwszy TVF może zwrócić maksymalnie jeden wiersz i dlatego stosuje niepoprawną optymalizację. Maksimum dla drugiego zapytania jest ustawione na 1.34078E+154
( 2^512
).
Nie mam pojęcia, skąd pochodzi ta maksymalna liczba wierszy. Być może metadane dostarczone przez autora DMV? Dziwne jest również to, że TOP(50)
obejście nie zostało przepisane, TOP(1)
ponieważ TOP(50)
nie zapobiegłoby wystąpieniu problemu z Halloween (choć zatrzymałoby go na czas nieokreślony)