Как выполнить массовую миграцию между схемами в SQL Server?

8

В настоящее время у нас есть несколько баз данных, но мы хотели бы объединить их и вместо этого разделить контексты нашего домена с помощью схем.

В MS SQL Server 2008 R2 как я могу переместить все содержимое одной схемы в другую навалом?

Например, все таблицы, представления, процедуры, индексы и т. Д., Которые мы создали в dboсхеме, теперь будут жить в fooсхеме.

РЕДАКТИРОВАТЬ: Я хотел уточнить на основе замечательных комментариев AaronBertrand. Это не многопользовательская ситуация. В нашей ситуации плагины внутренних инструментов разрабатывались изолированно разработчиками, которые не объединяли свои таблицы с базой данных инструмента.

Мэтью
источник
2
Это может быть очень сложно с FK и другими зависимостями. Почему вы переключаете модели? Мне нравится модель multi-db по сравнению с моделью multi-schema по ряду причин - см. Dba.stackexchange.com/questions/33550/… и dba.stackexchange.com/questions/16745/…
Аарон Бертран
@AaronBertrand среди причин состоит в том, что у нас есть реляционные зависимости между сущностями, которые находятся в отдельных базах данных (пользователи, например, в их собственной БД), а также, что у нас есть представления, которые охватывают базы данных и, таким образом, не могут использовать привязку схемы.
Мэтью
Вам не нужны внешние ключи, чтобы иметь отношения - они могут быть применены явно различными другими способами. И ваши представления не должны иметь SCHEMABINDING, если они не проиндексированы. Я работал с такой системой 13 лет, и я могу обещать вам, что вещи, о которых вы беспокоитесь, не стоит беспокоиться по сравнению с вещами, которые вы потеряете, объединяя всех в одну базу данных.
Аарон Бертран
@AaronBertra и большая разница между моим случаем использования и тем, что часто описывается в вашей ссылке, заключается в том, что эти базы данных никоим образом не разделяют клиентов или арендаторов. Каждый из них используется комбинацией внутренних инструментов. Вероятно, причина, по которой они разделены, заключается в том, что разработчик создает плагин инструмента в вакууме, а затем присоединяет его, не сливая с основной БД. На самом деле у нас будут отдельные БД для работы с арендаторами и различными средами ...
Мэтью

Ответы:

9

Основная концепция на самом деле довольно проста: вы генерируете скрипт из которого sys.objectsи sys.schemasстроите ALTER SCHEMA TRANSFERоператоры. Так, например, у вас есть три объекта в dboсхеме, и вы хотите переместить все их в blatсхему:

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

Следующий код:

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;

Даст этот скрипт (но, возможно, не в этом порядке):

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

(Вы можете захотеть добавить дополнительные фильтры, чтобы исключить объекты в dboсхеме, которые вы не хотите перемещать, исключить определенные типы объектов (например, возможно, все ваши функции являются служебными функциями и не должны перемещаться), сгенерировать сценарий упорядочен по типу объекта и т. д.)

Но есть пара проблем с перемещением всех ваших объектов в новую схему:

  1. Вероятно, ваш код все еще будет ссылаться на эти объекты как dbo.object- нет простого способа исправить это, кроме грубой силы. Вы, вероятно, можете найти все вхождения dbo.довольно легко, но они также могут возвращать ложные срабатывания, такие как EXEC dbo.sp_executesql, dbo.в комментариях, истинные ссылки на объекты, которые остаются в dbo.схеме, и т. Д.

  2. Ваши зависимости, вероятно, будут совершенно не в порядке, но я не проверил это полностью. Я знаю, что в этом сценарии:

    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;

    Внешние ключи на самом деле переносятся более плавно, чем я ожидал (с оговоркой, которую я тестирую на гораздо более свежей версии, чем вы). Но поскольку код по- blat.pXпрежнему ссылается dbo.bar, очевидно, выполняется процедура:

    EXEC blat.pX;

    Собирается дать эту ошибку:

    Сообщение 208, уровень 16, состояние 1, процедура pX
    Неверное имя объекта 'dbo.bar'.

    И запросы на зависимость, такие как:

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

    Выдаст эту ошибку:

    Сообщение 2020, уровень 16, состояние 1
    Зависимости, сообщаемые для объекта "blat.pX", могут не включать ссылки на все столбцы. Это либо потому, что объект ссылается на объект, который не существует, либо из-за ошибки в одном или нескольких утверждениях в объекте. Перед повторным запуском запроса убедитесь, что в объекте нет ошибок и все объекты, на которые ссылается объект, существуют.

    И запрашивая мнение:

    SELECT a, barA FROM blat.vFooBar;

    Выдает эти ошибки:

    Сообщение 208, Уровень 16, Состояние 1, Процедура vFooBar Неверное
    имя объекта 'dbo.foo'.
    Сообщение 4413, уровень 16, состояние 1
    Не удалось использовать представление или функцию blat.vFoobar из-за ошибок привязки.

    Таким образом, это может повлечь за собой много очистки. И после того, как вы исправите все ссылки на объекты, вы, вероятно, захотите перекомпилировать все модули и обновить все представления в новой схеме. Вы можете сгенерировать скрипт для этого, очень похожий на пример выше.

Аарон Бертран
источник
+1, похоже, мне нужно вручную сбросить несколько ФК, чтобы сделать эту передачу ... Я пока не знаю, что вызывает это
Мэтью
@ Матфе, да, если внешние ключи доставляют вам неприятности, посмотрите этот ответ - вам просто нужно настроить его так, чтобы часть повторного создания скрипта ссылалась на новую схему.
Аарон Бертран
@ Матфея вы выяснили, какие существуют обстоятельства, препятствующие плавной передаче определенных таблиц с внешними ключами? Какое именно сообщение об ошибке вы получаете? Было бы интересно узнать, можете ли вы обойти это, просто отключив ограничение, а не отбрасывая его ... но мне сложно это проверить, поскольку я не знаю, какой именно у вас блокировщик.
Аарон Бертран