Apakah pemutakhiran di tempat SQL Server tidak disarankan seperti dulu?

78

Saya telah bekerja dengan SQL server sejak SQL Server 6.5, saran lama yang masih terngiang-ngiang di kepala saya adalah tidak pernah melakukan upgrade di tempat.

Saat ini saya meningkatkan sistem DEV dan TEST 2008 R2 saya ke SQL Server 2012 dan perlu menggunakan perangkat keras yang sama. Pikiran tidak harus mengembalikan konfigurasi layanan Pelaporan saya sangat menarik dan saya sangat berhadapan dengan masalah waktu. Tidak ada layanan analisis yang terlibat atau apa pun yang tidak biasa atau tidak standar - hanya mesin basis data dan layanan pelaporan yang diinstal.

Adakah yang mengalami masalah serius dengan peningkatan di tempat? Atau haruskah saya mengevaluasi kembali posisi saya tentang peningkatan di tempat?

Barang rusak
sumber
Saya memilih untuk melakukan upgrade inplace pada 1 server dengan instalasi layanan pelaporan. Satu-satunya masalah yang saya temui adalah mencoba menggunakan alat ekspor impor di SSMS dengan klien asli 11. Mencoba transformasi gagal dengan kesalahan tentang tipe data yang tidak dikenal. solusi yang saya gunakan adalah untuk menyimpan paket dan menjalankannya di SQL Data Tools (penggantian BIDS) yang berfungsi dengan baik. Saya pikir ini harus dilakukan dengan file konfigurasi untuk SSIS 2008 tidak ditimpa. Itu terjadi pada saya nanti, Anda mungkin dapat mengubah klien asli kembali ke 10.
DamagedGoods

Jawaban:

92

Really Short Answer - In Place tidak apa-apa. Anda dapat meninjau konfigurasi Anda sesudahnya dan menerapkan praktik terbaik untuk SQL Server 2012.

Jawaban yang Lebih Panjang tentang Upgrade / Migrasi SQL Server

Jadi ini adalah pendapat dan tidak ada jawaban yang salah atau benar, tetapi saya lebih memilih peningkatan gaya migrasi di tempat karena banyak alasan. Yang sedang berkata - beberapa klien saya karena berbagai alasan tidak punya pilihan selain melakukan di tempat dan benar-benar sejak SQL Server 2005, upgrade di tempat belum seburuk dulu.

Mengapa Saya Memilih Migrasi ke Peningkatan di Tempat

  • Rollback yang Lebih Mudah - Jika terjadi kesalahan, Anda dapat mengembalikan dengan mengatakan "kami membatalkan upgrade .. Silakan ubah string koneksi ke server lama saat kami menyelesaikan ini". Dengan di-tempat Anda memperbaikinya atau Anda turun.
  • Refresh Hardware - Hardware berubah dengan cepat. Anda dapat dengan mudah terjebak pada perangkat keras yang tepat untuk perusahaan Anda 4 tahun yang lalu tetapi tidak tepat untuk hari ini dan empat tahun berikutnya dengan peningkatan di tempat. Anda mungkin harus melakukan migrasi di beberapa titik untuk perangkat keras baru.
  • Feel Better - Sure ... Yang ini subjektif, tapi rasanya senang mengetahui Anda mulai dengan instalasi OS baru, instalasi SQL baru tanpa sarang laba-laba dari orang yang bekerja sebelum Anda (atau Anda sebelum Anda tahu apa yang Anda ketahui) hari ini) yang mungkin dapat menyebabkan Anda sakit kepala di masa depan.
  • OS Baru - Suatu migrasi memberi Anda kesempatan untuk memulai dengan versi OS baru jika Anda tidak berada pada yang terbaru dan terhebat hari ini.
  • Anda Dapat Mengujinya - Pernah ingin mendapatkan satu set baseline pada mesin baru sebelum Anda menginstal SQL dan cloud itu dengan database dan penggunaan? Anda bisa melakukannya sekarang.
  • Terkadang lebih mudah untuk menyelinap dalam praktik terbaik - Mungkin akun layanan SQL Server adalah admin lokal. Mungkin Administrator Builtin dalam peran server SA. Mungkin beberapa hal telah diretas bersama untuk membuatnya bekerja sebelumnya. Anda dapat memperbaiki itu semua dan mulai yang baru.
  • Lingkungan pengujian gratis dan tidur tambahan - Merupakan manfaat besar untuk memiliki lingkungan tempat Anda dapat bekerja sebelum hari peralihan saat Anda menjadikan lingkungan baru ini hidup. Melakukan migrasi ke lingkungan baru berarti Anda dapat membangunnya selama jam kerja, jauh sebelum hari peralihan Anda yang sebenarnya dan mengujinya dengan berbagai cara sebelumnya. Anda dapat menjalankan pengujian regresi penuh pada semua aplikasi dan sistem selama berhari-hari dan memiliki ketenangan pikiran yang besar sebelum Anda benar-benar melakukan set final mengembalikan / melampirkan dan memotong semua aplikasi dan akses ke lingkungan baru.
  • Anda tidak harus melakukan semuanya sekaligus - Situasi yang sangat umum yang saya temui adalah lingkungan yang mencoba untuk mengkonsolidasikan beberapa contoh saja. Mungkin satu per versi, mungkin satu per "tier" dan versi. Banyak dari proyek-proyek ini memiliki jadwal yang berbeda untuk berbagai aplikasi dan database berdasarkan pengujian, rencana proyek dan ketepatan waktu sertifikasi vendor. Melakukan migrasi berarti Anda dapat memindahkan basis data yang sudah siap, saat sudah siap dan masih menangani permintaan untuk basis data yang tidak dapat dipindahkan karena satu dan lain alasan.

Pikiran Anda, saya tidak mengatakan Anda harus melakukan ini sebagai migrasi. In-Place berfungsi dan berfungsi dengan baik jika Anda tidak berencana membeli perangkat keras baru dalam anggaran Anda dan tidak dapat melakukannya untuk peningkatan ini. Dukungan dalam proses peningkatan jauh lebih baik daripada dalam 6,5 hari sehingga Anda tidak menempatkan diri Anda dalam posisi yang buruk melakukan hal ini.

Jika Anda berencana melakukan di tempat untuk dev / tes tetapi ingin melakukan migrasi untuk produksi, Anda mungkin mempertimbangkan melakukan setidaknya satu migrasi sebelum produksi. Dengan cara ini Anda dapat mengerjakan daftar periksa Anda sebelumnya dan menangani masalah potensial yang tidak Anda pikirkan.

Lampirkan / Lepaskan vs Cadangkan / Kembalikan untuk Migrasi

Jika Anda memutuskan untuk pergi dengan pendekatan migrasi, masih ada satu keputusan lagi Anda mungkin masih memiliki perdebatan dan itulah bagaimana Anda memindahkan database Anda ke lingkungan baru. Anda dapat melepaskan basis data dari server lama dan melampirkannya ke yang baru atau mencadangkannya dan memulihkannya di sana.

Saya lebih suka backup / restore. Keuntungan terbesar yang saya dengar tentang detach / attach adalah menghemat waktu. Bagi saya cadangan / pengembalian kemenangan karena beberapa alasan:

  • Biarkan yang lama dapat diakses - Ini memungkinkan Anda untuk tetap memiliki database yang dapat diakses di server sumber. detach / attach harus melakukan hal yang sama, tetapi akan membutuhkan beberapa langkah dan ada ruang untuk kesalahan manusia dengan detach / attach yang dapat mempersulit ini.
  • Anda menjamin bahwa Anda memiliki cadangan - Alih-alih hanya mengambil basis data dari detach dan berpotensi melupakan langkah cadangan, Anda telah memastikan bahwa Anda telah mengambil cadangan itu.
  • Human error - Jika Anda menghapus file yang salah, lupa di mana Anda mengirim sesuatu atau jika tidak, mengacaukan langkah Anda, Anda berisiko besar dengan memindahkan data dan mencatat file-file untuk database Anda. Sekarang Anda dapat mengurangi ini dengan menyalin alih-alih memotong (dan jika Anda melepaskan, Anda harus keluar dari kebiasaan memotong dan menempel) tetapi Anda masih bisa berantakan. SQL Server tidak lagi mengunci file-file itu dan terlalu mudah untuk menghapus file secara tidak sengaja bagi saya untuk mengambil risiko.
  • Hal ini tidak benar-benar bahwa lambat - Mengambil cadangan dan menyalin itu adalah waktu yang sedikit lebih, tetapi tidak banyak yang saya bersedia untuk membayar risiko ekstra untuk itu. Bahkan - dengan menggunakan model pemulihan penuh dan pencadangan log, Anda dapat menurunkan downtime lebih rendah untuk cutover seperti yang dijelaskan di bawah ini dalam "Cara Membuat Pendekatan Migrasi Lebih Cepat"

Jika Anda memutuskan untuk melakukan backup / restore - itu berarti database sumber lama Anda masih online. Saya suka menjadikan database itu offline setelah mengambil cadangan. Saya kadang-kadang melangkah lebih jauh dan membuat seluruh contoh SQL offline setelah saya mencoret keamanan, pekerjaan, server tertaut, sertifikat, pengaturan basis data, dan informasi luas lainnya. Ini menghindari masalah selama pengujian di mana seseorang mengatakan "Semuanya tampak hebat!" hanya untuk menyadari satu atau dua hari kemudian bahwa mereka telah berbicara dengan database lama di server lama. Mengambil basis data tersebut offline atau seluruh instance offline memungkinkan Anda untuk mencegah hal-hal yang salah dan kekacauan yang mereka buat.

Cara Membuat Pendekatan Migrasi Lebih Cepat

Anda dapat meminimalkan waktu henti yang diperlukan untuk peralihan dari lingkungan lama ke baru untuk lingkungan produksi yang sibuk dengan sedikit waktu henti dengan menggunakan model pemulihan penuh. Pada dasarnya - tahap lingkungan tempat Anda bermigrasi dengan mengembalikan cadangan lengkap terbaru, cadangan diferensial apa pun, dan cadangan log apa pun yang sudah diambil menentukan NORECOVERY- maka yang harus Anda lakukan untuk pemotongan akhir adalah mengembalikan cadangan log yang belum dipulihkan dan cadangan log akhir yang ingin Anda pulihkan WITH RECOVERY. Dengan cara ini untuk database besar, jendela downtime aktual dapat diminimalkan secara drastis dengan membayar biaya penuh, diferensial, dan sebagian besar log dikembalikan sebelum jendela downtime. Terima kasih kepada Tao karena menunjukkan ini di komentar!

Cara Membuat Upgrade di Tempat Lebih Aman

Beberapa hal yang dapat Anda lakukan untuk meningkatkan pengalaman dan hasil Anda ketika memilih pendekatan di tempat.

  • Cadangkan - Ambil cadangan yang sesuai dari semua basis data pengguna dan sistem di lingkungan Anda sebelumnya dan pastikan semuanya baik (saya paranoid .. Saya sebenarnya akan memulihkannya di suatu tempat terlebih dahulu untuk benar-benar tahu bahwa mereka baik .. Mungkin membuang-buang waktu Anda. Tetapi Anda dapat berterima kasih pada diri sendiri jika terjadi bencana) .. Script semua informasi konfigurasi tentang instalasi SQL dan OS di lingkungan itu.
  • Uji hal-hal dengan baik sebelum Anda mulai - Pastikan Anda memiliki lingkungan dan basis data yang baik. Anda harus melakukan hal-hal seperti melihat log kesalahan dan menjalankan DBCC CHECKDB secara teratur, tetapi sebelum melakukan upgrade di tempat adalah waktu yang tepat untuk memulai. Perbaiki masalah apa pun sebelumnya.
  • Pastikan kesehatan OS - Jangan hanya memastikan bahwa SQL itu sehat, pastikan server Anda sehat. Adakah kesalahan serius dalam log peristiwa kesalahan sistem atau aplikasi Anda? Bagaimana ruang kosong Anda?
  • Bersiaplah untuk yang terburuk - Saya memiliki seri posting blog beberapa waktu lalu yang bertolak dari premis bahwa jika Anda tidak mempersiapkan kegagalan - Anda sebenarnya bersiap untuk gagal .. Saya masih percaya itu. Jadi pikirkan masalah yang mungkin Anda miliki dan atasi sesuai dengan itu sebelumnya. Dapatkan diri Anda dalam pola pikir "kegagalan" dan Anda akan memikirkan hal-hal yang Anda tidak akan sebaliknya.

Pentingnya Peningkatan atau Daftar Periksa Migrasi

Jika Anda memutuskan untuk melakukan pemutakhiran (baik di tempat atau migrasi) Anda harus serius mempertimbangkan membuat daftar periksa dan menggunakan daftar periksa ini di setiap lingkungan. Anda harus memasukkan banyak hal dalam daftar periksa ini, tidak sedikit di antaranya:

  1. Di Awal - Lakukan beberapa hal seperti melakukan pemutakhiran uji, uji aplikasi Anda pada tingkat Kompatibilitas Basis Data terbaru dan pertimbangkan untuk menjalankan alat seperti Penasihat Peningkatan Server SQL terlebih dahulu untuk melihat jenis tugas apa yang perlu Anda selesaikan sebelum melakukan SQL Peningkatan atau migrasi server.
  2. Pra Langkah - Pembersihan, tugas OS, menambal sebelumnya, menyiapkan aplikasi untuk peningkatan (pembersihan mati, koneksi string berfungsi), cadangan , dll.
  3. Langkah Peningkatan / Migrasi - Semua yang harus Anda lakukan untuk meningkatkan atau migrasi agar berhasil dan dalam urutan yang benar. Instalasi, perubahan (atau tidak berubah tergantung pada pengujian dan pendekatan Anda) mode kompatibilitas berubah ke database, dll.
  4. Langkah - langkah Post Migration / Upgrade - Berbagai tes, posting versi baru atau opsi konfigurasi server baru, penerapan praktik terbaik, perubahan keamanan, dll.
  5. Kembalikan Langkah - Sepanjang jalan Anda harus memiliki langkah kembalikan dan tonggak. Jika Anda sejauh ini dan ini terjadi, apa yang akan Anda lakukan? Apa kriteria "lakukan rollback penuh"? Dan bagaimana Anda melakukannya rollback (membalikkan string koneksi berubah, mengubah kembali pengaturan, kembali ke versi lama, instal ulang jika ada di tempat, arahkan kembali ke server lama jika migrasi, dll.)

Dan kemudian mintalah orang yang akan melakukan peningkatan produksi ikuti daftar di beberapa lingkungan selain produksi - terutama yang menutup menyerupai produksi jika memungkinkan ("South of prod", seperti yang saya katakan ...) dan perhatikan setiap masalah atau poin di mana mereka harus mengalihkan dari daftar periksa atau berimprovisasi karena kurangnya daftar periksa. Lalu, gabungkan perubahan itu dan bersenang-senanglah dengan perubahan produksi Anda.

Saya tidak bisa terlalu menekankan pentingnya pengujian menyeluruh pasca migrasi atau peningkatan dan lebih cepat dari migrasi Anda. Membuat keputusan rollback di tengah-tengah pembaruan harus mudah - terutama selama migrasi. Jika ada sesuatu yang tidak nyaman, kembalikan dan cari tahu jika Anda tidak dapat memecahkan masalah secara efektif dan andal dalam panasnya migrasi. Setelah Anda hidup di lingkungan baru ini dan pengguna terhubung - rollback menjadi tugas yang sulit. Anda tidak dapat mengembalikan database SQL Server ke versi yang lebih lama. Itu berarti pekerjaan manual dan migrasi data. Saya selalu menunggu beberapa minggu untuk membunuh lingkungan lama, tetapi Anda harus melakukan semua yang Anda bisa untuk menghindari kebutuhan lingkungan lama itu dengan menemukan semua masalah Anda sebelum pengguna langsung menyentuh lingkungan baru. Lebih disukai bahkan sebelum Anda memulai pemutakhiran / migrasi.

Catatan singkat tentang migrasi / pemutakhiran Layanan Pelaporan SQL Server Memigrasi instalasi SSR bukanlah tugas yang sangat penting yang banyak orang pikirkan. Ini TechNet / buku artikel online sebenarnya cukup berguna . Salah satu peringatan paling penting dalam artikel itu adalah "Cadangkan kunci enkripsi" terutama jika Anda memiliki banyak informasi sensitif yang disimpan seperti laporan terjadwal alamat email penerima email, informasi koneksi untuk banyak koneksi, dll. Anda dapat bertanya kepada salah satu klien saya dari waktu yang lalu betapa pentingnya hal itu. Mereka tahu karena saya mengacaukan langkah itu dan menghabiskan cukup banyak waktu memodifikasi jadwal laporan dan izin string koneksi.

Mike Walsh
sumber
14

Dalam pengalaman saya, proses pengambilan keputusan yang sama harus dibuat seperti sebelumnya. AFAIK belum ada 'pengubah dunia' dengan instalasi SQL Server, di dalam produk MS SQL Server itu sendiri, dan potensi masalah yang Anda miliki ketika meluncurkan perangkat lunak dengan jutaan baris kode. Sesuatu yang buruk dapat terjadi dan sekarang Anda terjebak tanpa opsi 'ROLLBACK'.

Namun Anda memiliki alternatif lain di tempat. Anda dapat mempertimbangkan untuk membuat snapshot dari sistem, memulihkan di tempat lain, melakukan peningkatan dan melihat apa yang terjadi. Tes ini seharusnya memberi Anda banyak kenyamanan, tetapi itu tidak sepenuhnya menjamin tidak akan ada masalah yang muncul pada kotak prod. Namun, ini adalah opsi yang tidak tersedia kembali dalam SQL 6,5 hari.

Saya hanya akan mengasumsikan skenario terburuk. Anda melakukan upgrade di tempat dan gagal total. Anda kemudian harus memulihkan dari ini dalam RTO dan RCO Anda. Apakah bisnis memahami risiko dan apakah Anda memiliki rencana untuk mengurangi itu?

Jika bisnis ini tidak oke dengan ini, maka jangan lakukan itu akan menjadi saran saya.

Ali Razeghi
sumber
2

Jika server Anda berjalan di lingkungan virtual, Anda dapat melakukan snapshot pada klon dan kemudian menerapkan pembaruan di tempat dan menguji contoh untuk memverifikasi bahwa pembaruan berhasil. Jika berhasil, Anda dapat menerapkan snapshot dan membuat klon server produksi. Jika berjalan buruk, Anda dapat menghapus snapshot dan kembali ke gambar pra-peningkatan untuk mencoba lagi, atau menghapus klon dan migrasi penuh.

Troy
sumber
1
Hanya jika penyimpanan juga tervirtualisasi dan menjadi bagian dari snapshot. Jika penyimpanan secara langsung dilampirkan ke VM itu tidak akan 'dibatalkan' ketika snapshot dikembalikan ...
Remus Rusanu
1

Karena investasi perangkat keras yang besar, kami diharuskan memperbarui hanya OS sambil mempertahankan versi SQL Server saat ini (2012, 3 server, 22 instance, ~ 300 database). Tidak ada pengaturan rumit seperti mirroring, dll.

Contoh ini tidak cocok dengan pertanyaan karena SQL Server tidak ditingkatkan. Saya pikir ini masih merupakan jawaban yang baik karena langkah-langkah yang ditampilkan sebenarnya akan lebih sederhana daripada migrasi yang benar di tempat.

Ikhtisar: Drive eksternal dilampirkan untuk mengambil cadangan lengkap terutama sebagai tindakan pencegahan. Hanya model dan msdb yang benar-benar akan dipulihkan dari drive eksternal. Ldf / mdf dibiarkan untuk dilepas / dilampirkan. Beberapa akun lokal direferensikan dalam DB. Setelah mereka dibuat kembali di OS, referensi dalam DB dibuat kembali (karena SID dapat berubah).

Lalu inilah langkah-langkah yang berhasil bagi kami:

1) Perhatikan pengaturan tingkat server yang akan dipulihkan dalam langkah 12 (Peran Server) dan 18 hingga 23.

2) Patch SQL Server 2012 ke SP3 (diperlukan konsistensi jika kita ingin mengembalikan sistem dbs).

3) Verifikasi versi cocok pada setiap contoh. "Pilih versi @@"

4) Hasilkan 6 skrip ini dengan menjalankan skrip ini. Redgate SQL Multiscript adalah penghemat waktu yang sangat besar jika ada banyak contoh (Sesuaikan Alat -> Opsi => Panjang Jalur ke maks (8192) dan kemudian gunakan Output Teks).

  • Cadangkan
  • Mengembalikan
  • Melepaskan
  • Melampirkan
  • Buat Login
  • Tautkan Pengguna ke Login

    -- (1) BACKUP / (2) RESTORE
    --    
    --*** SET THESE to external drive location
    --*** and create the Destination Directories
    declare 
        @backupInstanceDir  varchar(300) = 'F:\ExternalDriveBackups\' + replace(@@servername, '\', '_'),
        @dateSuffix         varchar(100) = '2015-12-14'; 
    
    if (object_id('tempdb..DatabaseStatus') is not null)
    drop table #DAtabseSTatus;
    
    select 
        d.name DbName, 
        d.state_desc DbState,
        d.user_access_desc UserMode,
        convert(bit, (d.is_read_only * -1 + 1)) as IsWritable,
        d.is_trustworthy_on as IsTrustWorthy,
        d.is_in_standby IsInStandby,
        d.recovery_model_desc RecoveryModel,
        suser_sname(d.owner_sid) as Owner,
        convert(bit, 
            case when d.database_id <= 4 or d.is_distributor = 1
                then 1
                else 0
            end) as IsSystemDb,
        mf.type_desc as FileType,
        mf.name FileName,
        mf.state FileState,
        mf.state_desc FileStatDesc,
        mf.physical_name PhysicalName,
        mf.type as FileTypeId    
    into #DatabaseStatus
    from
        sys.master_files AS mf
    join sys.databases AS d
    ON  mf.database_id = d.database_id
    where
        1=1
    order by
        d.name,
        mf.physical_name;
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutBU
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutRE
    
    create table #sqlOutBU
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    create table #sqlOutRE
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutBU select char(10) + '-- BACKUP SCRIPT' + char(10);
    insert into #sqlOutRE select char(10) + '-- RESTORE SCRIPT' + char(10);
    
    
    insert into #sqlOutBU select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    insert into #sqlOutRE select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';        
    
    PRINT '--Script for Backing up all DBs in a SQL Server Instance to a specific location' 
    
    SET nocount ON 
    
    insert into #sqlOutBU select char(10) + 
    '--' + char(10) + '-- BACKUP ' + @@servername + '--' + char(10) + 
    'use [Master]; set deadlock_priority high;' + char(10);
    
    insert into #sqlOutRE select '
    -- RESTORE
    --
    -- BE SURE TO BACKUP SYSTEM DBS TO AN ALTERNATE LOCATION JUST BEFORE RESTORING!
    --
    use [Master]; set deadlock_priority high;' + char(10);
    
    DECLARE @dbname nvarchar(128) 
    declare dblist_cursor cursor fast_forward for 
    select [name] from master.sys.databases where [name] != 'tempdb'
    order by iif(database_id <= 4, '0', '1') + [name]
    
    open dblist_cursor 
    fetch next from dblist_cursor into @dbname 
    
    while @@fetch_status = 0 
    begin 
    
        declare @bak nvarchar(300) = @backupInstanceDir + '\' + @dbname + '_' + @dateSuffix + '.bak';
    
        insert into #sqlOutBU select char(10) + 'backup database [' + @dbname + '] to disk = ''' + @bak + ''' WITH COPY_ONLY, NOFORMAT, NOINIT, ' + char(10) + 
            'NAME = N''' + @dbName + '-Full'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION, STATS = 25;';
    
        insert into #sqlOutRE select 'restore database [' + @dbName + '] from disk = ''' + @bak + ''' WITH FILE = 1,' + char(10) +
        (
            select '    move ''' + FileName + ''' to ''' + PhysicalName + '''' From #DatabaseStatus
            where FileType = 'Rows' and DbName = @dbName
        ) + ',' + char(10) +
        (
            select '    move ''' + FileName + ''' to ''' + PhysicalName + '''' From #DatabaseStatus
            where FileType = 'Log' and DbName = @dbName
        ) + ',' + char(10) +
        '    NOUNLOAD, REPLACE, STATS = 25;' + char(10);               
    
        fetch next from dblist_cursor into @dbname 
    end 
    
    close dblist_cursor 
    deallocate dblist_cursor 
    
    insert into #sqlOutBU select char(10) + 'go' + char(10);
    insert into #sqlOutRE select char(10) + 'go' + char(10);
    
    select Command from #sqlOutBU order by Row; -- BACKUP SCRIPT
    select Command from #sqlOutRE order by Row; -- RESTORE SCRIPT
    
    go
    
    
    
    --
    -- (3) DETACH  -  Org Author: Artemakis Artemiou
    --      
    
    if object_id('tempdb..#sqlOutDT') is not null
        drop table #sqlOutDT
    
    create table #sqlOutDT
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutDT select char(10) + '-- DETACH all DBs from a SQL Server Instance' + char(10);      
    
    insert into #sqlOutDT select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    SET nocount ON 
    
    insert into #sqlOutDT select char(10) + '--' + char(10) + '-- DETACH ' + @@servername + char(10) + '--' + char(10) + '
    use MAster; set deadlock_priority high;' + char(10) + char(10);
    
    DECLARE @dbname nvarchar(128) 
    DECLARE dblist_cursor CURSOR fast_forward FOR 
    SELECT [name] 
    FROM   master.sys.databases 
    WHERE  database_id > 4 
    
    OPEN dblist_cursor 
    FETCH next FROM dblist_cursor INTO @dbname 
    
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
        insert into #sqlOutDT select
        'alter database ' + @dbname + ' set single_user with rollback immediate;' + char(10) +
        'EXEC sp_detach_db ''' + @dbname + ''', ''true'';' + char(10);
        FETCH next FROM dblist_cursor INTO @dbname 
    END 
    
    CLOSE dblist_cursor 
    DEALLOCATE dblist_cursor 
    
    insert into #sqlOutDT select char(10) + 'go' + char(10);
    select Command from #sqlOutDT order by Row;
    
    go
    
    
    
    --
    -- (4) ATTACH  -  Org Author: Artemakis Artemiou
    --    
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutAT
    
    create table #sqlOutAT
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutAT select char(10) + '-- ATTACH ALL DBs to a SQL Server Instance' + char(10);
    
    insert into #sqlOutAT select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    SET NOCOUNT ON
    
    insert into #sqlOutAT select char(10) + '--' + char(10) + '-- ATTACH ' + @@servername + char(10) + '--' + char(10) + 
    'use MAster;' + char(10) + char(10);
    
    DECLARE @dbname nvarchar(128);
    
    DECLARE DBList_cursor CURSOR fast_forward FOR 
    select [name] from master.sys.databases where database_id > 4
    order by name;
    
    OPEN DBList_cursor
    
    FETCH NEXT FROM DBList_cursor 
    INTO @dbname
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    
    declare @attach_TSQL_script varchar(max)
    set @attach_TSQL_script=''
    set @attach_TSQL_script=@attach_TSQL_script+'CREATE DATABASE ' + @dbname +' ON ' 
    
    declare @tsql varchar(max),@filename varchar(max)
    set @tsql='DECLARE DBFiles_cursor CURSOR FOR select [filename] from '+ @dbname + '.sys.sysfiles'
    
    execute (@tsql) 
    
    PRINT '--'+@dbname 
    
    OPEN DBFiles_cursor
    FETCH NEXT FROM DBFiles_cursor INTO @filename
    
    WHILE @@FETCH_STATUS = 0
    BEGIN   
    set @attach_TSQL_script=@attach_TSQL_script+ char(10)+'    (FILENAME = '''+ @filename +'''),' 
    FETCH NEXT FROM DBFiles_cursor INTO @filename
    END
    
    set @attach_TSQL_script=SUBSTRING(@attach_TSQL_script,0,len(@attach_TSQL_script))
    set @attach_TSQL_script=@attach_TSQL_script+ char(10) +'    FOR ATTACH;';
    
    insert into #sqlOutAT select @attach_TSQL_script + char(10);
    
    PRINT @attach_TSQL_script 
    PRINT ''
    
    CLOSE DBFiles_cursor
    DEALLOCATE DBFiles_cursor
    
    FETCH NEXT FROM DBList_cursor 
    INTO @dbname
    
    END 
    
    CLOSE DBList_cursor
    DEALLOCATE DBList_cursor
    
    insert into #sqlOutAT select char(10) + 'go' + char(10);
    select Command from #sqlOutAT order by Row;
    go
    
    
    
    --
    -- (5) GENERATE A 'RE-CREATE LOGINS' SCRIPT
    --
    -- This script was modified from a version that was designed to copy from one server to another:
    --      http://stackoverflow.com/a/5983773/538763
    --
    
    
    USE [master]
    
    if object_id('tempdb..#sqlOut') is not null
    drop table #sqlOut;
    
    create table #sqlOut
    (
    Command nvarchar(max) not null,
    Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOut select char(10) + '-- RECREATE LOGINS' + char(10);
    
    
    insert into #sqlOut select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    insert into #sqlOut select 'use Master;' + char(10);
    go
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    declare @Debug bit = 0;
    declare @PartnerServer varchar(100) = @@SERVICENAME;  -- use current server before it is shutdown (disabled below)
    
    declare
        @MaxID int,
        @CurrID int,
        @SQL nvarchar(max),
        @LoginName sysname,
        @IsDisabled int,
        @Type char(1),
        @SID varbinary(85),
        @SIDString nvarchar(100),
        @PasswordHash varbinary(256),
        @PasswordHashString nvarchar(300),
        @RoleName sysname,
        @Machine sysname,
        @PermState nvarchar(60),
        @PermName sysname,
        @Class tinyint,
        @MajorID int,
        @ErrNumber int,
        @ErrSeverity int,
        @ErrState int,
        @ErrProcedure sysname,
        @ErrLine int,
        @ErrMsg nvarchar(2048);
    
    declare @Logins Table (LoginID int identity(1, 1) not null primary key,
                        [Name] sysname not null,
                        [SID] varbinary(85) not null,
                        IsDisabled int not null,
                        [Type] char(1) not null,
                        PasswordHash varbinary(256) null)
    declare @Roles Table (RoleID int identity(1, 1) not null primary key,
                    RoleName sysname not null,
                    LoginName sysname not null)
    declare @Perms Table (PermID int identity(1, 1) not null primary key,
                    LoginName sysname not null,
                    PermState nvarchar(60) not null,
                    PermName sysname not null,
                    Class tinyint not null,
                    ClassDesc nvarchar(60) not null,
                    MajorID int not null,
                    SubLoginName sysname null,
                    SubEndPointName sysname null)
    
    Set NoCount On;
    
    If CharIndex('\', @PartnerServer) > 0
    Begin
    Set @Machine = LEFT(@PartnerServer, CharIndex('\', @PartnerServer) - 1);
    End
    Else
    Begin
    Set @Machine = @PartnerServer;
    End
    
    -- Get all Windows logins from principal server
    Set @SQL = 'Select P.name, P.sid, P.is_disabled, P.type, L.password_hash' + CHAR(10) +
        'From ' /*+ QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_principals P' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.sql_logins L On L.principal_id = P.principal_id' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'and P.Name Not like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;';
    
    Insert Into @Logins (Name, SID, IsDisabled, Type, PasswordHash)
    Exec sp_executesql @SQL;
    
    -- Get all roles from principal server
    Set @SQL = 'Select RoleP.name, LoginP.name' + CHAR(10) +
        'From '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_role_members RM' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + .*/ +'master.sys.server_principals RoleP' +
        CHAR(10) + char(9) + 'On RoleP.principal_id = RM.role_principal_id' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_principals LoginP' +
        CHAR(10) + char(9) + 'On LoginP.principal_id = RM.member_principal_id' + CHAR(10) +
        'Where LoginP.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And LoginP.name <> ''sa''' + CHAR(10) +
        'And LoginP.name Not Like ''##%''' + CHAR(10) +
        'And LoginP.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And RoleP.type = ''R''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', LoginP.name) = 0;';
    
    Insert Into @Roles (RoleName, LoginName)
    Exec sp_executesql @SQL;
    
    -- Get all explicitly granted permissions
    Set @SQL = 'Select P.name Collate database_default,' + CHAR(10) +
        '   SP.state_desc, SP.permission_name, SP.class, SP.class_desc, SP.major_id,' + CHAR(10) +
        '   SubP.name Collate database_default,' + CHAR(10) +
        '   SubEP.name Collate database_default' + CHAR(10) +
        'From '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_principals P' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_permissions SP' + CHAR(10) +
        CHAR(9) + 'On SP.grantee_principal_id = P.principal_id' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_principals SubP' + CHAR(10) +
        CHAR(9) + 'On SubP.principal_id = SP.major_id And SP.class = 101' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.endpoints SubEP' + CHAR(10) +
        CHAR(9) + 'On SubEP.endpoint_id = SP.major_id And SP.class = 105' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'And P.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;'
    
    Insert Into @Perms (LoginName, PermState, PermName, Class, ClassDesc, MajorID, SubLoginName, SubEndPointName)
    Exec sp_executesql @SQL;
    
    --select * from @Logins;
    --select * from @Roles;
    --select * from @perms;
    
    
    Select @MaxID = Max(LoginID), @CurrID = 1
    From @Logins;
    
    While @CurrID <= @MaxID
    Begin
    Select @LoginName = Name,
        @IsDisabled = IsDisabled,
        @Type = [Type],
        @SID = [SID],
        @PasswordHash = PasswordHash
    From @Logins
    Where LoginID = @CurrID;
    
    --    If Not Exists (Select 1 From sys.server_principals
    --              Where name = @LoginName)
    Begin
    
        set @sql = char(10);
        set @sql += 'If Not Exists (Select 1 From sys.server_principals Where name = ''' + @LoginName + ''')' + char(10);
        set @sql += 'begin' + char(10) + '    ';
    
        Set @SQL += 'Create Login ' + quotename(@LoginName)
        If @Type In ('U', 'G')
        Begin
            Set @SQL = @SQL + ' From Windows;'
        End
        Else
        Begin
            Set @PasswordHashString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@PasswordHash"))', 'nvarchar(300)');
    
            Set @SQL = @SQL + ' With Password = ' + @PasswordHashString + ' HASHED;  --, ';
    
            Set @SIDString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@SID"))', 'nvarchar(100)');
            Set @SQL = @SQL + 'SID = ' + @SIDString + ';' + char(10);
        End
    
        set @sql += char(10) +
            '    print ''Created Login ' + @loginName  + ''';' + char(10) +
            'end' + char(10) +
            'else' + char(10) +
            convert(nvarchar(max), '    print ''Login ' + @loginName + ' already existed. '';') + char(10);
    
        If @Debug = 0
        insert into #sqlOut select @SQL;                      
        Else
        Print @SQL;
    
        If @IsDisabled = 1
        Begin
            Set @SQL = 'Alter Login ' + quotename(@LoginName) + ' Disable;'
            If @Debug = 0
                insert into #sqlOut select @SQL;                              
            Else              
                Print @SQL;              
        End
        End
    Set @CurrID = @CurrID + 1;
    End
    
    
    insert into #sqlOut select char(10) + 'use Master;' + char(10);
    
    Select @MaxID = Max(RoleID), @CurrID = 1
    From @Roles;
    
    While @CurrID <= @MaxID
    Begin
    Select @LoginName = LoginName,
        @RoleName = RoleName
    From @Roles
    Where RoleID = @CurrID;
    
    /*  If Not Exists (Select 1 From sys.server_role_members RM
                Inner Join sys.server_principals RoleP
                    On RoleP.principal_id = RM.role_principal_id
                Inner Join sys.server_principals LoginP
                    On LoginP.principal_id = RM.member_principal_id
                Where LoginP.type In ('U', 'G', 'S')
                And RoleP.type = 'R'
                And RoleP.name = @RoleName
                And LoginP.name = @LoginName)*/
    Begin
        If @Debug = 0
        Begin          
            insert into #sqlOut select 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''', @loginame = ''' + @LoginName + ''';';
        End
        Else
        Begin
            Print 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''',';
            Print '     @loginame = ''' + @LoginName + ''';';
        End
    End
    
    Set @CurrID = @CurrID + 1;
    End
    
    
    insert into #sqlOut select char(10) + 'use Master;' + char(10);
    
    
    Select @MaxID = Max(PermID), @CurrID = 1
    From @Perms;
    
    While @CurrID <= @MaxID
    Begin
    Select @PermState = PermState,
        @PermName = PermName,
        @Class = Class,
        @LoginName = LoginName,
        @MajorID = MajorID,
        @SQL = PermState + space(1) + PermName + SPACE(1) +
            Case Class When 101 Then 'On Login::' + QUOTENAME(SubLoginName)
                    When 105 Then 'On ' + ClassDesc + '::' + QUOTENAME(SubEndPointName)
                    Else '' End +
            ' To ' + QUOTENAME(LoginName) + ';'
    From @Perms
    Where PermID = @CurrID;
    
    /*If Not Exists (Select 1 From sys.server_principals P
                Inner Join sys.server_permissions SP On SP.grantee_principal_id = P.principal_id
                Where SP.state_desc = @PermState
                And SP.permission_name = @PermName
                And SP.class = @Class
                And P.name = @LoginName
                And SP.major_id = @MajorID)*/
    Begin
        If @Debug = 0
                insert into #sqlOut select @sql;                      
        Else          
            Print @SQL;          
    End
    
    Set @CurrID = @CurrID + 1;
    End
    
    
    select Command from #sqlOut as SqlOut order by Row;
    go
    
    
    --
    -- (6) Generate a script to Re-link all users to logins based on current state (before shutdown)
    --
    
    use Master;
    
    if object_id('tempdb..#sqlOut') is not null
    drop table #sqlOut;
    
    create table #sqlOut
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOut select char(10) + '-- RELINK USERS TO LOGINS' + char(10);
    
    insert into #sqlOut select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    declare @dbCmd varchar(8000) = '
    use ?;
    
    insert into #sqlOut select char(10) + ''use ?;'' + char(10);  
    
    with links as
    (
    select u.name as UserName,
        l.loginname as LoginName
        from sysusers u 
        join master..syslogins l
        on u.sid = l.sid        
    where u.name != ''dbo''
        and u.isSqlUser = 1 or l.isNtName = 1 or l.isNtGroup = 1
    )
    insert into #sqlOut 
    select ''alter user ['' + UserName + ''] with name = ['' + UserName + ''], login = ['' + LoginName + '']''
    from links
    ';    
    
    exec sp_MSforeachdb @dbCmd;
    
    select Command from #sqlOut order by Row;
    
    go
    

5) Jalankan skrip untuk Cadangkan semua DB termasuk sistem (master, msdb, model) ke drive eksternal.

6) Jalankan skrip untuk Melepaskan semua DB

7) Drive C akan diformat ulang. Pertahankan LDF / MDF jika mereka TIDAK menggunakan C.

8) Windows Server 2012 diinstal pada C.

9) Pindahkan LDF / MDF untuk file sistem asli keluar dari jalan jika tidak ada di Drive C.

10) SQL Server 2012 akan diinstal ulang dan ditambal ke SP3 a. Menciptakan kembali akun Pengguna / Grup sistem

11) Cadangkan Sistem DB ke lokasi atau nama file BARU (hati-hati untuk tidak menimpa yang asli!).

12) Jalankan buat ulang cuplikan peran. Sesuatu seperti:

USE [master]
CREATE SERVER ROLE [SomeServerRole]
--ALTER SERVER ROLE [dbcreator] ADD MEMBER [SomeServerRole]
--ALTER SERVER ROLE [bulkadmin] ADD MEMBER [SomeServerRole]
-- ALTER SERVER ROLE [SomeServerRole] ADD MEMBER [SomeMemberOrRole]

13) Jalankan buat kembali skrip login (tidak melakukan apa-apa jika login dikembalikan)

14) Hentikan SQL AGEN.

(Bisakah mengembalikan Tuan di sini, kami ketakutan).

15) Lampirkan mdf / ldf menggunakan skrip dari atas. Sebuah. Jika gagal pulihkan secara manual dari bak menggunakan skrip dari atas.

16) Mencoba Pemulihan Model

17) Pastikan SQL Agent dihentikan. Pulihkan MSDB (tautan) a. Jika gagal, perlu menciptakan kembali pekerjaan + rencana pemeliharaan + konfigurasi email + operator

18) Buka skrip Pengguna Untuk Masuk ...

    a. If there are master users (rare?) then First Re-Create users for master since it was not restored:
        use master;       
        CREATE USER [ABC] FOR LOGIN [machine\ABC]

    b. Run the rest of the script

19) Aktifkan broker layanan untuk mencocokkan nama SELECT nilai asli, is_broker_enabled FROM sys.databases;

    alter database MSDB set single_user with rollback immediate;
    ALTER DATABASE [MSDB] SET ENABLE_BROKER;
    alter database MSDB set multi_user;

20) Mulai SQL Agent

21) Tetapkan ambang Paralelisme ke nilai asli

22) Sesuaikan pengaturan basis data apa pun dengan nilai aslinya:

 declare @dbCmd varchar(8000) = '
      use ?;
      if db_name() not in (''master'', ''model'', ''tempdb'', ''msdb'')
      begin
             print ''Adjusting [?]...'';    
            alter database [?] set single_user with rollback immediate;
             aLTER AUTHORIZATION ON DATABASE::[?] to [sa];
            -- alter database [?] set trustworthy on;
            ALTER DATABASE [?] SET AUTO_CLOSE OFF WITH NO_WAIT;     
            alter database [?] set multi_user;
      end     
      else
             print ''Skipping [?]...'';
    ';    

    exec sp_MSforeachdb @dbCmd;

23) Periksa kepemilikan pekerjaan:

select s.name as JobName, l.name as login, SUSER_SNAME(s.owner_sid) AS login2
from  msdb..sysjobs s 
left join master.sys.syslogins l on s.owner_sid = l.sid

Jika Versi SQL Server juga telah ditingkatkan, saya tidak percaya model dan database msdb bisa dipulihkan sehingga pekerjaan akan hilang karena https://support.microsoft.com/en-us/kb/264474

Apa yang hilang:

  • Pengguna asli dalam database master (jarang?)
  • Peran Server
  • ?
crokusek
sumber
0

Tidak ada yang salah dengan kedua pendekatan itu - saya telah melakukan keduanya dan hasilnya baik.

Jika ada masalah dengan pendekatan migrasi, itu tidak teknis: itu kemalasan. Terlalu sering saya menemukan bahwa alasan perusahaan belum sepenuhnya menggunakan versi xxxx adalah karena mereka memilih migrasi swing dan tidak pernah sempat melakukan kerja keras untuk sepenuhnya bergerak. Sekarang mereka memiliki dua atau lebih set server, bukan satu.

RowlandG
sumber