lỗi trong cơ sở dữ liệu_scoped_configurations


9

Tôi đang cố gắng chèn tập kết quả từ:

SELECT * FROM sys.database_scoped_configurations

vào bảng tạm thời, vì tôi muốn kiểm tra cài đặt cho tất cả các cơ sở dữ liệu trên máy chủ của mình. Vì vậy, tôi đã viết mã này:

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

Nhưng sau đó sẽ chỉ có một hàng cho mỗi cơ sở dữ liệu, không phải là bốn hàng mà tôi mong đợi khi chạy một lựa chọn đơn giản trong mỗi cơ sở dữ liệu.

Tôi biết có nhiều cách tốt hơn để mã hóa điều này hơn là sử dụng sp_MSForEachDB và tôi đã thử một vài cách. Nhưng tôi vẫn chỉ nhận được một hàng cho mỗi cơ sở dữ liệu. Tôi đã thử điều này trên cả SQL Server 2016 RTM và SP1

Đây có phải là một lỗi với SQL Server 2016 hay tôi đang làm gì đó sai?


lỗi đã được sửa, ít nhất là trong Microsoft SQL Server 2017 (RTM-CU15-GDR)
Henrik Staun Poulsen

Câu trả lời:


8

Đây có phải là một lỗi với SQL Server 2016 không?

Đúng. Chắc chắn đây không phải là hành vi đúng. Tôi đã báo cáo nó ở đây và được sửa trong SQL Server 2016 SP2 CU9 .

Như Mikael Eriksson nói trong các bình luận sys.database_scoped_configurationssys.dm_exec_sessionsđược thực hiện dưới dạng các khung nhìn ở định dạng

SELECT ...  
FROM OpenRowset(TABLE xxxx)  

Tuy nhiên, so sánh hai kế hoạch dưới đây có một sự khác biệt rõ ràng.

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 );

nhập mô tả hình ảnh ở đây

Trace cờ 8619 đầu ra cho cả hai truy vấn này cho thấy

Áp dụng quy tắc: EnforceHPandAccCard - x0-> Spool hoặc Top (x0)

SQL Server rõ ràng là không thể xác định được rằng nguồn cho TVF không phải là mục tiêu chèn nên nó yêu cầu bảo vệ Halloween.

Trong các phiên, trường hợp này được thực hiện như một ống chỉ chụp tất cả các hàng trước. Trong database_scoped_configurationsbằng cách thêm một TOP 1vào kế hoạch. Việc sử dụng TOPđể bảo vệ Halloween được thảo luận trong bài viết này . Bài báo cũng đề cập đến một cờ theo dõi không có giấy tờ để buộc một ống chỉ hơn TOPlà hoạt động như mong đợi.

DECLARE @database_scoped_configurations TABLE(x INT);

INSERT INTO @database_scoped_configurations
SELECT configuration_id
FROM   sys.database_scoped_configurations
OPTION (QUERYTRACEON 8692)

Một vấn đề rõ ràng với việc sử dụng TOP 1chứ không phải là một ống chỉ là nó sẽ tùy ý giới hạn số lượng hàng được chèn. Vì vậy, điều này sẽ chỉ hợp lệ nếu số lượng hàng được hàm trả về là <= 1.

Bản ghi nhớ ban đầu trông như thế này

nhập mô tả hình ảnh ở đây

So sánh điều này với bản ghi nhớ ban đầu cho truy vấn 2

nhập mô tả hình ảnh ở đây

Nếu tôi hiểu chính xác những điều trên, nó nghĩ rằng TVF đầu tiên có thể trả về tối đa một hàng và do đó áp dụng tối ưu hóa không chính xác. Max cho truy vấn thứ hai được đặt thành 1.34078E+154( 2^512).

Tôi không biết số lượng hàng tối đa này được lấy từ đâu. Có lẽ siêu dữ liệu được cung cấp bởi tác giả của DMV? Một điều kỳ lạ là TOP(50)cách giải quyết không được viết lại TOP(1)bởi vì TOP(50)sẽ không ngăn chặn sự cố Halloween xảy ra (mặc dù điều đó sẽ ngăn chặn nó tiếp diễn vô thời hạn)


6

Hãy ngừng sử dụng sp_MSForEachDB. Nó không được hỗ trợ, không có giấy tờ và đó là lỗi - có thể là vấn đề ở đây. Sự thay thế của tôi cho thấy vấn đề tương tự ở đây, nhưng nói chung nó là một thứ an toàn hơn để sử dụng.

Đối với những thứ như thế này, tôi thích tạo SQL động hơn là thực hiện một lệnh duy nhất cho một thủ tục để thực thi nhiều lần (ngay cả thủ tục của tôi, mà tôi tin tưởng nhiều hơn), bằng cách này tôi có thể chỉ cần in các lệnh thay vì thực thi chúng và đảm bảo tất cả họ sẽ làm những gì họ nói.

Mượn từ quan sát rằng mã bên dưới khung nhìn hệ thống thực hiện a TOP (1), chúng ta có thể thử theo cách này:

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;

Lưu ý rằng tôi không sử dụng USEở đây, mà thay vào đó là tiền tố của syschế độ xem danh mục với tên cơ sở dữ liệu.

Tại sao chế độ xem hoạt động theo những cách kỳ diệu, tôi không biết; Tôi không biết rằng bạn sẽ nhận được câu trả lời tốt ở đây, vì có thể yêu cầu nhận xét từ Microsoft (hoặc bất kỳ ai có quyền truy cập vào mã nguồn hoặc sẵn sàng kích hoạt trình gỡ lỗi).


đó là phương pháp đầu tiên trong số một số phương pháp tôi đã thử, nhưng tôi không nghĩ rằng tôi có thể sử dụng phương pháp đó trong ví dụ.
Henrik Staun Poulsen

6

Cảm ơn bạn đã báo cáo vấn đề này!

Đây thực sự là một lỗi trong cách Trình tối ưu hóa truy vấn tạo kế hoạch cho sys.database_scoped_configurationschế độ xem danh mục. Chúng tôi sẽ giải quyết vấn đề này trên một trong các bản cập nhật tiếp theo của SQL Server 2016 và trong Cơ sở dữ liệu SQL Azure.

Như một giải pháp thay thế, bạn có thể thêm một TOPmệnh đề vào SELECTphần chèn của bạn để có được kế hoạch chính xác, ví dụ:

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

3

Tôi đồng ý rằng điều này rất lạ và là một lỗi tiềm ẩn, nhưng việc thêm TOP (50), ví dụ, vào lựa chọn của bạn thực sự sẽ trả về tất cả các hàng, do đó ít nhất sẽ giúp bạn đi. Kết quả dường như đến từ Hàm Giá trị Bảng của hệ thống ([DB_SCOPED_CONFIG]), vì vậy tôi thực sự không thể biết chuyện gì đang xảy ra.

Tôi sẽ theo dõi chủ đề này để xem mọi người 'thông minh hơn' biết TẠI SAO điều này đang xảy ra.


Bạn có nhận được hàng MAXDOP cho mỗi cơ sở dữ liệu không?
Dan Guzman

@DanGuzman - có Việc tự chọn chỉ hoạt động tốt (không có tất cả các công cụ tìm kiếm, chỉ trên một cơ sở dữ liệu). Đó là khi bạn thêm Chèn vào để tạo ra hành vi kỳ lạ
Scott Hodgin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.