CATATAN UNTUK PEMBACA: Silakan baca seluruh pertanyaan, termasuk kode contoh (yaitu bukan hanya judulnya). Pertanyaan ini bukan tentang bagaimana cara terbaik menelusuri basis data, juga bukan tentang mengapa [tempdb] menerima kesalahan ini. OP sudah berusaha untuk menghindari mengeksekusi ALTER
pernyataan pada semua basis data sistem (well, 4 yang terlihat) dan menanyakan mengapa pernyataan IF yang seharusnya melewatkan [tempdb] tampaknya tidak melewatkannya.
Mengapa skrip berikut memberi saya kesalahan terkait tempdb?
Alasannya adalah bahwa IF
pernyataan hanya mempengaruhi apa yang terjadi ketika kode benar-benar berjalan, tetapi SQL Server masih harus mem-parsing dan mengkompilasi bets sebelum menjalankannya. Kesalahan Parse adalah yang terkait dengan sintaks, seperti memastikan bahwa pernyataan SQL terbentuk dengan benar dan variabel telah dideklarasikan dengan benar:
-- parse the following by hitting Control-F5 or clicking the check mark in SSMS
SELECT @Bob;
mendapat kesalahan berikut:
Msg 137, Level 15, State 2, Line 2
Must declare the scalar variable "@Bob".
Dan berikut ini:
-- parse the following by hitting Control-F5 or clicking the check mark in SSMS
CREATE TABLE b
mendapat kesalahan berikut:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'b'.
Jika batch berhasil diurai, maka dikompilasi, pada saat hal-hal seperti izin diperiksa dan beberapa pemeriksaan lainnya dilakukan.
-- parse the following by hitting Control-F5 or clicking the check mark in SSMS
IF (1 = 0)
BEGIN
ALTER AUTHORIZATION ON DATABASE::[tempdb] TO [sa];
ALTER DATABASE [tempdb] SET RECOVERY SIMPLE;
END;
SQL di atas terbentuk dengan benar sehingga batch berhasil. Sekarang coba jalankan SQL di atas dengan menekan F5 atau Control-E atau ! Jalankan tombol, dll.
Kali ini Anda mendapatkan kesalahan berikut:
Msg 5058, Level 16, State 1, Line 4
Option 'RECOVERY' cannot be set in database 'tempdb'.
meskipun kode IF (1 = 0)
memastikan bahwa tidak akan pernah berjalan. Ini berarti bahwa Anda mengalami kesalahan kompilasi. Anda dapat mengatasi jenis kesalahan ini dengan memindahkan kode yang menyinggung ke dalam subproses melalui EXEC
panggilan.
Jalankan berikut ini dan itu akan selesai dengan sukses karena apa yang ada di dalam EXEC()
tidak diuraikan atau dikompilasi sampai pernyataan itu dijalankan pada saat runtime.
IF (1 = 0)
BEGIN
EXEC('
ALTER AUTHORIZATION ON DATABASE::[tempdb] TO [sa];
ALTER DATABASE [tempdb] SET RECOVERY SIMPLE;
');
END;
Untuk meringkas:
Pertama, pertimbangkan bahwa sp_MSForEachDB
siklus melalui database dan mengeksekusi pass-in SQL Anda setelah mengganti ?
dengan nama database saat ini. Jadi ketika kursor di dalam sp_MSForEachDB
sampai ke [tempdb]
, itu efektif melakukan hal berikut:
IF ( (select database_id from sys.databases where name = ''tempdb'') > 4)
BEGIN
ALTER AUTHORIZATION ON DATABASE::tempdb TO [sa];
ALTER DATABASE [tempdb] SET RECOVERY SIMPLE;
END
Kedua, ada beberapa langkah yang dilakukan SQL Server ketika Anda menjalankan batch permintaan:
- Parse
- Menyusun
- Eksekusi Aktual
Penting untuk memahami bahwa ini adalah langkah-langkah terpisah dan dapat menghasilkan kesalahan sebelum melanjutkan ke langkah berikutnya (dan karenanya membatalkan pemrosesan lebih lanjut sebelum melanjutkan ke langkah berikutnya). Dalam kasus di sini, kesalahan terjadi pada Langkah 2 - Kompilasi - sebagaimana terbukti pada contoh ke-2 hingga terakhir di atas (yang pertama dimulai dengan IF (1 = 0)
). The IF (1 = 0)
mencegah bagian dalam kode BEGIN...END
blok dari yang pernah berjalan, namun kesalahan masih terjadi. Karenanya kesalahan tidak terjadi karena upaya aktual untuk menjalankan kedua ALTER
pernyataan.
Alasan yang membungkus ALTER
pernyataan di dalam EXEC()
fungsi berfungsi adalah karena SQL Server tidak akan menguraikan dan mengkompilasi apa yang ada di dalam EXEC()
sampai EXEC()
benar-benar berjalan. Pada saat itu, IF ( (select database_id from sys.databases where name = ''?'') > 4)
pernyataan akan diizinkan berjalan karena bets tidak akan gagal selama Kompilasi dan akan membuatnya untuk Eksekusi, dan IF
pernyataan itu akan melompati [tempdb]
dan "Opsi 'PEMULIHAN' tidak dapat diatur dalam kesalahan 'tempdb' basis data" tidak akan terjadi.
IF
pernyataan maupun pernyataan SQL lainnya (termasuk keduanyaALTER
) sedang dieksekusi pada saat ini. TheIF
pernyataan tidak memungkinkan ID tempdb untuk dikirim ke apa yang ada di dalamBEGIN
/END
blok, dan kode ini bahkan tidak menjalankanALTER
pernyataan pada saat ini. Kesalahan dilemparkan oleh SQL Server karena memvalidasi SQL sebelum menjalankannya. Saya menambahkan bagian ringkasan ke bagian akhir.Pertama-tama tidak perlu menggunakan
ms_foreachdb
yang tidak berdokumen dan seberapa buruk Anda dapat mengulang menggunakan kursor sederhana. Mengenai kesalahan Anda mencoba untuk mengubah model pemulihan semua databaseincluding tempdb
tetapi Anda tidak dapat mengubah model pemulihan tempdb juga Anda tidak dapat melakukan operasi cadangan di atasnya itu sebabnya Anda mendapat pesan kesalahan ini. Ini tidak diizinkan oleh Microsoft. Baca lebih lanjut tentang operasi yang dapat Anda lakukan di tempdbsumber
ALTER
pernyataan yang hanya sedang divalidasi , tidak dieksekusi. Saya memberikan detail dalam jawaban saya .Terlepas dari kenyataan bahwa Anda tidak dapat mengubah opsi pemulihan untuk tempdb, Anda tidak perlu perulangan untuk apa yang Anda lakukan:
Jalankan di SSMS dengan menekan CTRL+T
sumber