database_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

그러나 각 데이터베이스에서 일반 선택을 실행할 것으로 예상되는 4 개의 행이 아닌 데이터베이스 당 하나의 행만 있습니다.

sp_MSForEachDB를 사용하는 것보다 이것을 코딩하는 더 좋은 방법이 있다는 것을 알고 여러 가지를 시도했습니다. 그러나 여전히 데이터베이스 당 하나의 행만 얻습니다. SQL Server 2016 RTM과 SP1에서 모두 시도했습니다.

이것은 SQL Server 2016의 버그입니까, 아니면 내가 잘못하고 있습니까?


버그는 마이크로 소프트 SQL 서버 2017 (RTM-계약 금액은 15,000-GDR)에 적어도 수정되었습니다
헨릭 Staun 폴센

답변:


8

이것은 SQL Server 2016의 버그입니까?

예. 확실히 이것은 올바른 행동이 아닙니다. 난 여기가보고 되고 SQL 서버 2016 SP2의 CU9에 고정 .

으로 미카엘 에릭손은 코멘트에 말했다 sys.database_scoped_configurationssys.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을 생성하는 것을 선호합니다. 그들이하는 말을 모두하게하세요.

시스템 뷰의 기본 코드가를 구현한다는 관찰에서 차용하면 다음 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 (또는 소스 코드에 액세스 할 수 있거나 디버거를 기꺼이 할 사람)의 의견이 필요할 수 있으므로 여기에 좋은 대답을 얻을 수 있다는 것을 모르겠습니다.


그것은 내가 시도한 몇 가지 방법 중 첫 번째 방법이지만 예제에서 해당 sproc을 사용할 수 있다고 생각하지 않았습니다.
Henrik Staun Poulsen

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 행만 얻습니까?
Dan Guzman

@ DanGuzman-예 select 자체는 잘 작동합니다 (foreach 항목이 하나도없고 단일 데이터베이스 만). 이상한 동작을
일으키는
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.