Это ошибка в SQL Server 2016?
Да. Определенно это не правильное поведение. Я сообщил об этом здесь и исправлен в SQL Server 2016 SP2 CU9 .
Как говорит Микаэль Эрикссон в комментариях sys.database_scoped_configurations
и sys.dm_exec_sessions
реализованы как представления в формате
SELECT ...
FROM OpenRowset(TABLE xxxx)
Однако, сравнивая два плана ниже, есть очевидная разница.
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 );
Вывод флага трассировки 8619 для обоих этих запросов показывает
Применить правило: EnforceHPandAccCard - x0-> Spool or Top (x0)
SQL Server, по-видимому, не может установить, что источник для TVF также не является целевым объектом вставки, поэтому он требует защиты на Хэллоуин.
В случае сессий это было реализовано как спул, который сначала захватывает все строки. В database_scoped_configurations
добавив TOP 1
к плану. Использование TOP
для защиты Хэллоуина обсуждается в этой статье . В статье также упоминается недокументированный флаг трассировки для принудительной установки катушки, а не TOP
тот, который работает, как ожидалось.
DECLARE @database_scoped_configurations TABLE(x INT);
INSERT INTO @database_scoped_configurations
SELECT configuration_id
FROM sys.database_scoped_configurations
OPTION (QUERYTRACEON 8692)
Очевидная проблема с использованием, TOP 1
а не спула, заключается в том, что он будет произвольно ограничивать количество вставляемых строк. Так что это будет допустимо только в том случае, если число строк, возвращаемых функцией, было <= 1.
Начальная записка выглядит так
Сравните это с первоначальной запиской для запроса 2
Если я правильно понимаю вышесказанное, он думает, что первый TVF может вернуть максимум одну строку, и поэтому применяет неверную оптимизацию. Максимальное значение для второго запроса установлено в 1.34078E+154
( 2^512
).
Я понятия не имею, откуда это максимальное количество строк. Возможно, метаданные предоставлены автором DMV? Также странно, что TOP(50)
обходной путь не переписывается, TOP(1)
потому TOP(50)
что не помешает возникновению проблемы Хэллоуина (хотя остановит его на неопределенный срок)