Я пытаюсь вставить набор результатов из:
SELECT * FROM sys.database_scoped_configurations
во временную таблицу, потому что я хочу проверить настройки для всех баз данных на моем сервере. Итак, я написал этот код:
DROP TABLE IF EXISTS #h
CREATE TABLE #h(dbname sysname, configuration_id INT, name sysname, value SQL_VARIANT, value_for_secondary SQL_VARIANT)
EXEC sys.sp_MSforeachdb 'USE ?; insert into #h(dbname, configuration_id, name, value,value_for_secondary) SELECT ''?'' as dbname, * FROM sys.database_scoped_configurations D'
SELECT * FROM #h H
Но тогда в каждой базе данных будет только одна строка, а не четыре, которые я ожидаю от запуска простого выбора в каждой базе данных.
Я знаю, что есть лучшие способы кодирования, чем использование sp_MSForEachDB, и я пробовал несколько. Но я все еще получаю только одну строку на базу данных. Я пробовал это на SQL Server 2016 RTM и SP1
Это ошибка в SQL Server 2016 или я что-то не так делаю?
sql-server
configuration
sql-server-2016
Хенрик Стаун Поулсен
источник
источник
Ответы:
Да. Определенно это не правильное поведение. Я сообщил об этом здесь и исправлен в SQL Server 2016 SP2 CU9 .
Как говорит Микаэль Эрикссон в комментариях
sys.database_scoped_configurations
иsys.dm_exec_sessions
реализованы как представления в форматеОднако, сравнивая два плана ниже, есть очевидная разница.
Вывод флага трассировки 8619 для обоих этих запросов показывает
SQL Server, по-видимому, не может установить, что источник для TVF также не является целевым объектом вставки, поэтому он требует защиты на Хэллоуин.
В случае сессий это было реализовано как спул, который сначала захватывает все строки. В
database_scoped_configurations
добавивTOP 1
к плану. ИспользованиеTOP
для защиты Хэллоуина обсуждается в этой статье . В статье также упоминается недокументированный флаг трассировки для принудительной установки катушки, а неTOP
тот, который работает, как ожидалось.Очевидная проблема с использованием,
TOP 1
а не спула, заключается в том, что он будет произвольно ограничивать количество вставляемых строк. Так что это будет допустимо только в том случае, если число строк, возвращаемых функцией, было <= 1.Начальная записка выглядит так
Сравните это с первоначальной запиской для запроса 2
Если я правильно понимаю вышесказанное, он думает, что первый TVF может вернуть максимум одну строку, и поэтому применяет неверную оптимизацию. Максимальное значение для второго запроса установлено в
1.34078E+154
(2^512
).Я понятия не имею, откуда это максимальное количество строк. Возможно, метаданные предоставлены автором DMV? Также странно, что
TOP(50)
обходной путь не переписывается,TOP(1)
потомуTOP(50)
что не помешает возникновению проблемы Хэллоуина (хотя остановит его на неопределенный срок)источник
Пожалуйста, прекратите использование
sp_MSForEachDB
. Это не поддерживается, недокументировано и содержит ошибки - что может быть проблемой здесь. Моя замена демонстрирует ту же проблему здесь, но в целом это безопаснее.Для таких вещей я предпочитаю генерировать динамический SQL, чем передавать одну команду процедуре, которая должна выполняться несколько раз (даже моей процедуре, которой я доверяю намного больше), таким образом, я могу просто напечатать команды вместо их выполнения, и убедитесь, что они все будут делать то, что говорят.
Исходя из наблюдения, что код, лежащий в основе системного представления, реализует
TOP (1)
, мы можем попробовать это следующим образом:Обратите внимание, что я не использую
USE
здесь, а вместо этого префикс представленияsys
каталога с именем базы данных.Почему представление работает волшебным образом, я не знаю; Я не знаю, что вы получите хороший ответ здесь, поскольку для этого, вероятно, требуются комментарии от Microsoft (или любого, кто имеет доступ к исходному коду или желает запустить отладчик).
источник
Спасибо за сообщение об этой проблеме!
Это действительно ошибка в том, как Оптимизатор запросов генерирует план для представления
sys.database_scoped_configurations
каталога. Мы рассмотрим это в одном из следующих обновлений SQL Server 2016 и в базе данных SQL Azure.В качестве обходного пути вы можете добавить
TOP
пункт соSELECT
своей вставки, чтобы получить правильный план, например:источник
Я согласен, что это очень странная и потенциальная ошибка, но добавление TOP (50), например, к вашему select действительно возвращает все строки, так что это, по крайней мере, поможет вам. Похоже, что результат исходит от системной функции табличных значений ([DB_SCOPED_CONFIG]), поэтому я не могу точно сказать, что происходит.
Я буду следить за этой веткой, чтобы узнать, знают ли «умные» люди, ПОЧЕМУ это происходит.
источник