Saya mencoba menyisipkan set hasil dari:
SELECT * FROM sys.database_scoped_configurations
ke tabel temp, karena saya ingin memeriksa pengaturan untuk semua database di server saya. Jadi saya menulis kode ini:
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
Tapi kemudian hanya akan ada satu baris per basis data, bukan empat baris yang saya harapkan dari menjalankan pilihan polos di setiap basis data.
Saya tahu ada cara yang lebih baik untuk kode ini daripada menggunakan sp_MSForEachDB, dan saya mencoba beberapa. Tapi saya masih hanya mendapatkan satu baris per basis data. Saya sudah mencoba ini pada SQL Server 2016 RTM dan SP1
Apakah ini bug dengan SQL Server 2016, atau apakah saya melakukan sesuatu yang salah?
sql-server
configuration
sql-server-2016
Henrik Staun Poulsen
sumber
sumber
Jawaban:
Iya. Jelas ini bukan perilaku yang benar. Saya telah melaporkannya di sini dan diperbaiki di SQL Server 2016 SP2 CU9 .
Seperti yang dikatakan Mikael Eriksson dalam komentar
sys.database_scoped_configurations
dansys.dm_exec_sessions
diimplementasikan sebagai tampilan dalam formatNamun membandingkan dua rencana di bawah ini ada perbedaan yang jelas.
Lacak flag 8619 output untuk kedua queri ini
SQL Server tampaknya tidak dapat memastikan bahwa sumber untuk TVF tidak juga target penyisipan sehingga membutuhkan perlindungan Halloween.
Dalam kasus sesi ini diimplementasikan sebagai gulungan yang menangkap semua baris terlebih dahulu. Di
database_scoped_configurations
dengan menambahkanTOP 1
ke rencana. PenggunaanTOP
untuk perlindungan Halloween dibahas dalam artikel ini . Artikel itu juga menyebutkan bendera jejak yang tidak berdokumen untuk memaksa spool daripadaTOP
yang berfungsi seperti yang diharapkan.Masalah yang jelas dengan menggunakan
TOP 1
daripada spool adalah bahwa itu akan secara sewenang-wenang membatasi jumlah baris yang dimasukkan. Jadi ini hanya akan valid jika jumlah baris yang dikembalikan oleh fungsi adalah <= 1.Memo awal terlihat seperti ini
Bandingkan ini dengan memo awal untuk kueri 2
Jika saya memahami hal di atas dengan benar, ia berpikir bahwa TVF pertama dapat mengembalikan maksimum satu baris dan menerapkan pengoptimalan yang salah. Maks untuk kueri kedua diatur ke
1.34078E+154
(2^512
).Saya tidak tahu dari mana asal jumlah baris maksimum ini. Mungkin metadata disediakan oleh penulis DMV? Juga aneh bahwa
TOP(50)
penyelesaiannya tidak ditulis ulangTOP(1)
karenaTOP(50)
tidak akan mencegah masalah Halloween terjadi (meskipun akan menghentikannya berlanjut tanpa batas waktu)sumber
Tolong berhenti menggunakan
sp_MSForEachDB
. Ini tidak didukung, tidak berdokumen, dan bermasalah - yang mungkin menjadi masalah di sini. Pengganti saya menunjukkan masalah yang sama di sini, tetapi secara umum itu adalah hal yang lebih aman untuk digunakan.Untuk hal-hal seperti ini saya lebih suka untuk menghasilkan SQL dinamis daripada menyerahkan satu perintah ke prosedur untuk dieksekusi beberapa kali (bahkan prosedur saya, yang saya percayai lebih banyak), dengan cara ini saya bisa mencetak perintah daripada menjalankannya, dan pastikan mereka semua akan melakukan apa yang mereka katakan.
Meminjam dari pengamatan bahwa kode yang mendasari tampilan sistem mengimplementasikan a
TOP (1)
, kita dapat mencoba cara ini:Perhatikan bahwa saya tidak menggunakan di
USE
sini, melainkan awalan tampilansys
katalog dengan nama database.Mengapa pandangan bekerja dengan cara yang ajaib, saya tidak tahu; Saya tidak tahu bahwa Anda akan mendapatkan jawaban yang baik di sini, karena kemungkinan membutuhkan komentar dari Microsoft (atau siapa pun yang memiliki akses ke kode sumber, atau bersedia menjalankan debugger).
sumber
Terima kasih telah melaporkan permasalahan ini!
Ini memang bug dalam cara Pengoptimal Kueri membuat rencana untuk tampilan
sys.database_scoped_configurations
katalog. Kami akan membahas ini pada salah satu pembaruan SQL Server 2016 dan Azure SQL Database berikutnya.Sebagai solusinya, Anda bisa menambahkan
TOP
klausa padaSELECT
bagian sisipan Anda untuk mendapatkan paket yang benar, misalnya:sumber
Saya setuju bahwa ini sangat aneh dan berpotensi bug, tetapi menambahkan TOP (50), misalnya, ke pilihan Anda benar-benar mengembalikan semua baris, sehingga setidaknya membuat Anda maju. Hasilnya tampaknya berasal dari fungsi Table Value Function sistem ([DB_SCOPED_CONFIG]), jadi saya tidak bisa mengatakan apa yang sebenarnya terjadi.
Saya akan mengawasi utas ini untuk melihat apakah orang-orang 'pintar' tahu MENGAPA ini terjadi.
sumber