помилка в базі даних_scoped_configurations


9

Я намагаюся вставити набір результатів із:

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, чи я щось роблю не так?


виправлено помилку, принаймні, у Microsoft SQL Server 2017 (RTM-CU15-GDR)
Генрік Стаун Поульсен

Відповіді:


8

Це помилка в 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-> Шпулька або Топ (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)це не завадить виникнути проблему Хеллоуїна (хоча це не зупинить її продовження на невизначений час)


6

Будь ласка, припиніть використання sp_MSForEachDB. Це непідтримується, недокументовано, і це баггі - що може бути тут проблемою. Моя заміна демонструє ту саму проблему, але загалом це безпечніше використовувати.

Для таких речей я вважаю за краще генерувати динамічний SQL, ніж передавати одну команду процедурі виконання декількох разів (навіть мою процедуру, якій я довіряю набагато більше), таким чином я можу просто надрукувати команди, а не виконувати їх, і переконайтесь, що всі вони будуть робити те, що вони кажуть.

Позичившись зі спостереження, що код, що лежить в основі системного виду, реалізує a TOP (1), ми можемо спробувати наступним чином:

DROP TABLE IF EXISTS #h;

CREATE TABLE #h(dbname sysname, configuration_id INT, name sysname, 
  value SQL_VARIANT,  value_for_secondary SQL_VARIANT);

DECLARE @sql nvarchar(max) = N'', @base nvarchar(max) = N'insert into #h
  (dbname, configuration_id, name, value,value_for_secondary)  SELECT TOP ($c$) 
  $db$ as dbname, * FROM $qdb$.sys.database_scoped_configurations;';

SELECT @sql += REPLACE(REPLACE(REPLACE(@base, N'$qdb$', QUOTENAME(name)), 
  N'$db$', CHAR(39) + name + CHAR(39)), N'$c$', RTRIM(COUNT(*) OVER()))
FROM sys.databases WHERE state = 0;

PRINT @sql;
EXEC sys.sp_executesql @sql;
SELECT * FROM #h;

Зауважте, що я тут не використовую USE, а скоріше додайте sysперегляд каталогу із назвою бази даних.

Чому вид працює магічними способами, я не знаю; Я не знаю, що ви отримаєте хорошу відповідь тут, оскільки це, ймовірно, вимагає коментарів від Microsoft (або тих, хто має доступ до вихідного коду, або бажає запустити налагоджувач).


це був перший із декількох методів, які я спробував, але я не думав, що зможу використати цей проросток у прикладі.
Генрік Стаун Поульсен

6

Дякуємо, що повідомили про це питання!

Це дійсно помилка в тому, що Оптимізатор запитів формує план для подання sys.database_scoped_configurationsкаталогу. Ми вирішимо це на одному з наступних оновлень SQL Server 2016 та в Azure SQL Database.

Як вирішення, ви можете додати TOPпункт про SELECTчастину своєї вставки, щоб отримати правильний план, наприклад:

DECLARE @database_scoped_configurations TABLE(x INT); 
INSERT INTO @database_scoped_configurations 
SELECT **TOP 100** configuration_id 
FROM sys.database_scoped_configurations 

3

Я погоджуюсь, що це дуже дивно і потенційна помилка, але додавання, наприклад, TOP (50) до вашого вибору насправді повертає всі рядки, так що, принаймні, ви змусите вас йти. Здається, результат походить від функцій системного значення таблиці ([DB_SCOPED_CONFIG]), тому я не можу реально сказати, що відбувається.

Я буду стежити за цією темою, щоб дізнатися, чи знають «розумніші» люди, ЧОМУ це відбувається.


Чи отримуєте ви лише рядок MAXDOP для кожної бази даних?
Дан Гузман

@DanGuzman - так Вибір сам по собі працює чудово (без усіх матеріалів передбачень, лише на одній базі даних). Це коли ви додаєте "
Вставку",
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.