Bagaimana cara bermigrasi antar skema secara massal di SQL Server?

8

Saat ini kami memiliki banyak basis data tetapi ingin menggabungkannya dan, sebaliknya, memisahkan konteks domain kami menggunakan skema.

Dalam MS SQL Server 2008 R2, bagaimana saya bisa memindahkan semua konten dari satu skema ke yang lain secara massal?

Misalnya, semua tabel, tampilan, prosedur, indeks, dll ... yang kami buat dalam dboskema sekarang akan hidup dalam fooskema.

EDIT: Saya ingin mengklarifikasi berdasarkan komentar hebat AaronBertrand. Ini bukan situasi multi-sewa. Situasi kami adalah di mana plugin alat internal dikembangkan secara terpisah oleh pengembang yang tidak menggabungkan tabel mereka ke dalam basis data alat.

Matius
sumber
2
Ini bisa sangat rumit dengan FK dan dependensi lainnya. Mengapa Anda mengganti model? Saya suka model multi-db di atas model multi-skema karena berbagai alasan - lihat dba.stackexchange.com/questions/33550/… dan dba.stackexchange.com/questions/16745/…
Aaron Bertrand
@ AaronBertrand di antara alasannya adalah bahwa kami memiliki dependensi relasional antara entitas yang berada di basis data yang terpisah (pengguna, misalnya, dalam DB mereka sendiri) dan, juga, bahwa kami memiliki pandangan yang menjangkau pangkalan data dan dengan demikian tidak dapat menggunakan penyusunan skema.
Matius
Anda tidak perlu kunci asing untuk memiliki hubungan - ini dapat diberlakukan secara eksplisit dalam berbagai cara Dan pandangan Anda tidak perlu memiliki SCHEMABINDING kecuali mereka diindeks. Saya bekerja dengan sistem seperti itu selama 13 tahun, dan saya dapat berjanji kepada Anda bahwa hal-hal yang Anda khawatirkan tidak perlu dikhawatirkan dibandingkan dengan hal-hal yang Anda akan kehilangan dengan menggabungkan semua orang ke dalam satu basis data.
Aaron Bertrand
@ AaronBertrand perbedaan besar yang saya lihat antara kasus penggunaan saya dan yang sering dijelaskan dalam tautan Anda adalah bahwa basis data ini tidak memisahkan klien atau penyewa dengan cara apa pun. Masing-masing digunakan oleh kombinasi alat internal. Kemungkinan alasan mereka terpisah adalah karena pengembang membuat plugin alat dalam ruang hampa kemudian memasangnya tanpa bergabung ke dalam DB utama. Kami sebenarnya akan memiliki DB yang terpisah untuk menangani penyewaan dan lingkungan yang berbeda ...
Matius

Jawaban:

9

Konsep dasar sebenarnya cukup sederhana: Anda menghasilkan skrip dari sys.objectsdan sys.schemasyang membangun ALTER SCHEMA TRANSFERpernyataan. Jadi misalnya, Anda memiliki tiga objek dalam dboskema, dan Anda ingin memindahkan semuanya ke blatskema:

Table: dbo.foo
Table: dbo.bar
View:  dbo.vFooBar

Kode berikut:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'
  ALTER SCHEMA blat TRANSFER dbo.' + QUOTENAME(o.name) + ';'
FROM sys.objects AS o
INNER JOIN sys.schemas AS s
ON o.[schema_id] = s.[schema_id]
WHERE s.name = N'dbo';

PRINT @sql;
-- EXEC sp_executesql @sql;

Akan menghasilkan skrip ini (tapi mungkin tidak dalam urutan ini):

ALTER SCHEMA blat TRANSFER dbo.bar;
ALTER SCHEMA blat TRANSFER dbo.foo;
ALTER SCHEMA blat TRANSFER dbo.vFooBar;

(Anda mungkin ingin menambahkan filter tambahan untuk meninggalkan objek dalam dboskema yang tidak ingin Anda pindahkan, tinggalkan tipe objek tertentu (mis. Mungkin semua fungsi Anda adalah fungsi utilitas dan tidak perlu bergerak), menghasilkan skrip diurutkan berdasarkan jenis objek, dll.)

Tetapi ada beberapa masalah dengan memindahkan semua objek Anda ke skema baru:

  1. Mungkin banyak kode Anda masih akan merujuk objek-objek ini dbo.object- tidak ada cara mudah untuk memperbaikinya kecuali kekerasan. Anda mungkin dapat menemukan semua kejadian dbo.dengan cukup mudah, tetapi ini juga dapat mengembalikan positif palsu, seperti EXEC dbo.sp_executesql, dbo.dalam komentar, referensi yang benar ke objek yang masih ada dalam dbo.skema, dll.

  2. Ketergantungan Anda mungkin akan benar-benar rusak, tetapi saya belum benar-benar menguji ini. Saya tahu itu dalam skenario ini:

    CREATE SCHEMA blat AUTHORIZATION dbo;
    GO
    
    CREATE TABLE dbo.foo(a INT PRIMARY KEY);
    CREATE TABLE dbo.bar(a INT FOREIGN KEY REFERENCES dbo.foo(a));
    GO
    
    CREATE PROCEDURE dbo.pX AS
    BEGIN
      SET NOCOUNT ON;
      SELECT a FROM dbo.bar;
    END
    GO
    
    CREATE VIEW dbo.vFooBar
    AS
      SELECT foo.a, bar.a AS barA
        FROM dbo.foo 
        INNER JOIN dbo.bar
        ON foo.a = bar.a;
    GO
    
    ALTER SCHEMA blat TRANSFER dbo.foo;
    ALTER SCHEMA blat TRANSFER dbo.bar;
    ALTER SCHEMA blat TRANSFER dbo.pX;
    ALTER SCHEMA blat TRANSFER dbo.vFooBar;
    

    Kunci asing sebenarnya bermigrasi lebih lancar dari yang saya harapkan (dengan peringatan yang saya uji pada versi yang jauh lebih baru daripada Anda). Tetapi karena kode dalam blat.pXreferensi masih dbo.bar, jelas menjalankan prosedur:

    EXEC blat.pX;

    Akan menghasilkan kesalahan ini:

    Msg 208, Level 16,
    Status 1, Prosedur pX Nama objek tidak valid 'dbo.bar'.

    Dan pertanyaan ketergantungan, seperti:

    SELECT * FROM sys.dm_sql_referenced_entities('blat.pX', N'OBJECT');

    Akan menghasilkan kesalahan ini:

    Msg 2020, Level 16, Negara 1
    Ketergantungan yang dilaporkan untuk entitas "blat.pX" mungkin tidak menyertakan referensi ke semua kolom. Ini karena entitas mereferensikan objek yang tidak ada atau karena kesalahan dalam satu atau lebih pernyataan dalam entitas. Sebelum menjalankan kembali kueri, pastikan bahwa tidak ada kesalahan dalam entitas dan bahwa semua objek yang direferensikan oleh entitas ada.

    Dan menanyakan tampilan:

    SELECT a, barA FROM blat.vFooBar;

    Menghasilkan kesalahan ini:

    Msg 208, Level 16, Status 1, Prosedur vFooBar
    Nama objek tidak valid 'dbo.foo'.
    Msg 4413, Level 16, Negara 1
    Tidak dapat menggunakan tampilan atau fungsi 'blat.vFoobar' karena kesalahan yang mengikat.

    Jadi, ini bisa melibatkan banyak pembersihan. Dan setelah Anda memperbaiki semua referensi objek, Anda mungkin ingin mengkompilasi ulang semua modul dan menyegarkan semua tampilan dalam skema baru. Anda dapat membuat skrip untuk itu sangat mirip dengan contoh di atas.

Aaron Bertrand
sumber
+1, sepertinya saya perlu mengeluarkan beberapa FK secara manual untuk melakukan transfer ini ... Saya belum tahu apa penyebabnya
Matthew
@ Matius ya, jika kunci asing memberi Anda masalah, lihat jawaban ini - Anda hanya perlu menyesuaikannya sehingga bagian skrip yang dibuat ulang merujuk pada skema baru.
Aaron Bertrand
@ Matius, sudahkah Anda mengetahui keadaan apa yang membuat tabel tertentu dengan kunci asing tidak dapat ditransfer dengan lancar? Apa pesan kesalahan persis yang Anda dapatkan? Akan menarik untuk mengetahui apakah Anda dapat melewati itu dengan hanya menonaktifkan kendala daripada menjatuhkannya ... tetapi sulit bagi saya untuk menguji karena saya tidak tahu apa pemblokir yang tepat Anda.
Aaron Bertrand