database_scoped_configurations içindeki hata


9

Sonuç kümesi eklemek çalışıyorum:

SELECT * FROM sys.database_scoped_configurations

geçici bir tabloya, çünkü sunucumdaki tüm veritabanlarının ayarlarını kontrol etmek istiyorum. Bu yüzden bu kodu yazdım:

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

Ama sonra her veritabanı için düz bir seçim çalıştırmak için beklediğim dört satır değil, veritabanı başına sadece bir satır olacak .

Bu kodlamak için sp_MSForEachDB kullanmaktan daha iyi yollar olduğunu biliyorum ve birkaç denedim. Ama yine de her veritabanı için sadece bir satır alıyorum. Bunu SQL Server 2016 RTM ve SP1'de denedim

Bu SQL Server 2016 ile ilgili bir hata mı yoksa yanlış bir şey mi yapıyorum?


hata düzeltildi, en azından Microsoft SQL Server 2017'de (RTM-CU15-GDR)
Henrik Staun Poulsen

Yanıtlar:


8

Bu SQL Server 2016 ile ilgili bir hata mı?

Evet. Kesinlikle bu doğru davranış değildir. Burada rapor ettim ve SQL Server 2016 SP2 CU9'da düzeltildi .

As Mikael Eriksson yorumlarda diyor sys.database_scoped_configurationsve sys.dm_exec_sessionsformatta görünümleri olarak uygulanır

SELECT ...  
FROM OpenRowset(TABLE xxxx)  

Ancak aşağıdaki iki planı karşılaştırdığımızda bariz bir fark vardır.

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

resim açıklamasını buraya girin

Bu sorguların her ikisi için izleme bayrağı 8619 çıktısı

Kural Uygula: EnforceHPandAccCard - x0-> Makara veya Üst (x0)

SQL Server görünüşe göre TVF kaynağının da ekleme hedefi olmadığını belirleyemiyor, bu yüzden Cadılar Bayramı koruması gerektiriyor.

Seanslar durumunda bu, önce tüm satırları yakalayan bir makara olarak uygulanır. Gelen database_scoped_configurationsbir ekleyerek TOP 1plana. TOPCadılar Bayramı koruması için kullanımı bu makalede ele alınmıştır . Makale ayrıca TOPbeklendiği gibi çalışmak yerine bir makarayı zorlamak için belgelenmemiş bir izleme işaretinden bahsediyor .

DECLARE @database_scoped_configurations TABLE(x INT);

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

Bir TOP 1makara yerine kullanmakla ilgili bariz bir sorun, eklenen satır sayısını keyfi olarak sınırlayacağıdır. Bu, yalnızca işlev tarafından döndürülen satır sayısı <= 1 olduğunda geçerli olur.

İlk not şuna benzer

resim açıklamasını buraya girin

Sorgu 2 için ilk notla karşılaştırın

resim açıklamasını buraya girin

Yukarıdakileri doğru anlarsam, ilk TVF'nin en fazla bir satır dönebileceğini düşünür ve bu nedenle yanlış bir optimizasyon uygular. İkinci sorgu için Maks 1.34078E+154( 2^512) olarak ayarlanır .

Bu maksimum satır sayısının nereden türetildiği hakkında hiçbir fikrim yok. Belki de DMV'nin yazarı tarafından sağlanan meta veriler? TOP(50)Geçici çözümün yeniden yazılmaması da tuhaftır TOP(1)çünkü TOP(50)Cadılar Bayramı sorununun oluşmasını engellemeyecektir (ancak süresiz olarak devam etmesini durduracaktır)


6

Lütfen kullanmayı bırakın sp_MSForEachDB. Desteklenmiyor, belgesiz ve buggy - buradaki sorun olabilir. Değişim burada aynı sorunu gösteriyor, ancak genel olarak kullanmak daha güvenli bir şey.

Bu gibi şeyler için birden çok kez yürütmek için bir yordama tek bir komut teslim daha dinamik SQL üretmeyi tercih ederim (hatta çok daha fazla güvendiğim prosedürüm), bu şekilde komutları yürütmek yerine basitçe yazdırabilirim ve hepsinin söylediklerini yapacaklarından emin olun.

Sistem görünümünün altında yatan kodun bir uyguladığı gözleminden ödünç alarak TOP (1)şu şekilde deneyebiliriz:

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;

USEBurada kullanmamaya dikkat ediyorum , bunun yerine syskatalog görünümüne veritabanı adı önekini ekledim .

Görünüm neden büyülü bir şekilde çalışıyor, bilmiyorum; Burada iyi bir yanıt alacağınızı bilmiyorum, çünkü muhtemelen Microsoft'tan (veya kaynak koduna erişimi olan veya bir hata ayıklayıcıyı tetiklemeye istekli olan herkes) yorum gerektiriyor.


bu denediğim birkaç yöntemden biriydi, ama örnekte o sproc'u kullanabileceğimi düşünmemiştim.
Henrik Staun Poulsen

6

Bu sorunu bildirdiğin için teşekkürler!

Bu gerçekten de Sorgu Optimize Edici'nin sys.database_scoped_configurationskatalog görünümü için bir plan oluşturma biçimindeki bir hatadır . Bunu SQL Server 2016'nın bir sonraki güncellemelerinden birinde ve Azure SQL Veritabanı'nda ele alacağız.

Geçici bir çözüm olarak, doğru planı almak için eklentinizin bir bölümüne bir TOPcümle SELECTekleyebilirsiniz. Örneğin:

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

3

Bunun çok garip ve potansiyel bir hata olduğunu kabul ediyorum, ancak örneğin bir TOP (50) eklemek, seçiminize aslında tüm satırları döndürür, böylece en azından gitmenizi sağlar. Sonuç bir sistem Tablo Değer Fonksiyonu ([DB_SCOPED_CONFIG]) geliyor gibi görünüyor, bu yüzden gerçekten neler olduğunu söyleyemem.

'Daha akıllı' insanların bunun neden olduğunu bilip bilmediklerini görmek için bu konuya göz kulak olacağım.


Her veritabanı için yalnızca MAXDOP satırı mı alıyorsunuz?
Dan Guzman

@DanGuzman - evet Seçim tek başına iyi çalışır (tüm foreach öğeleri olmadan, sadece tek bir veritabanında). Garip davranışlar yaratan Ekle'yi eklediğinizde
Scott Hodgin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.