Я приветствую всех жителей Хабрахабра! Всем удачной новой рабочей недели! Итак, мы продолжаем процесс миграции базы данных на использование SQL Azure Federations. Как вы помните, в прошлый раз мы решили, по какой таблице и по какому полю мы будем разбивать базу данных на шарды. Давайте же наконец это сделаем!
Миграция
Итак, будем разбивать базы данных по таблице аккаунтов (Account), поскольку данные, хранящиеся в ней и связанные с ней логически друг с другом не пересекаются. Поскольку у нас есть скрипт создания базы данных, попробуем адаптировать его для использования SQL Azure Federations.
Будем считать, что база данных уже создана в Windows Azure Management Portal либо через SQL Server Management Studio.
Откроем скрипт создания объектов в базе данных.
USE xPenses
GO
IF EXISTS (SELECT name FROM sysobjects where name = N'Operation') DROP TABLE Operation
...
Первое, что необходимо убрать это использование операции USE, т. к. это одно из основых ограничений SQL Azure. Одна база данных — одно соединение. Вместо этого добавим запросы на создание федерации:
-- A database must be selected before executing this statement
CREATE FEDERATION Accounts(AccountId BIGINT RANGE)
GO
USE FEDERATION Accounts(AccountId = 1) WITH RESET, FILTERING = OFF
GO
Обратите внимание, что допустим, подключившись с помощью SSMS к SQL Azure Server необходимо выбрать базу данных из списка, для выполнения запроса.
Таким образом мы создадим новую федерацию, данные которой распределяются по значению идентификатора аккаунта (Account ID). Обратите внимание, что на данный момент никаких таблиц в базе не создано, то есть поле AccountId не связано ни с каким набором данных в реальных таблицах. Имя поля также может отличаться от имени поля таблицы, по которому будет производиться распределение.
Здесь мы можем увидеть еще одно, логичное, ограничение SQL Azure Federations. Поле, по которому будет будет осуществляться распределение должно иметь тип INT, BIGINT, UNIQUEIDENTIFIER и VARBINARY.
После создания федерации, нам необходимо выбрать первый шард, в который мы начинаем вносить данные. То есть шард, хранящий данные первого аккаунта (AccountId = 1).
Смотрим наш скрипт далее. Нам необходимо модифицировать создание таблицы аккаунтов таким образом, чтобы SQL Azure знал, что данные именно этой таблицы по полю Id будут распределяться по шардам.
CREATE TABLE Account (
[Id] INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1),
[EntityId] INTEGER NOT NULL FOREIGN KEY REFERENCES Entity(Id),
[Currency] NVARCHAR(3)
)
Таким образом скрипт создания таблицы превратится в следующий:
CREATE TABLE Account (
[Id] BIGINT NOT NULL,
[EntityId] INTEGER NOT NULL FOREIGN KEY REFERENCES Entity(Id),
[Currency] NVARCHAR(3),
CONSTRAINT [PK_Account] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
) FEDERATED ON (AccountId= Id)
Итак, что же изменилось? Тип поля ID стал BIGINT. Кроме этого, мы лишились возможности автоматической генерации значения для этого поля при вставке новой записи. Это является еще одним из ограничений SQL Azure Federations. Однако сохраняется возможность использования ключевого слова DEFAULT. Это к примеру будет полезно, если тип поля ID будет UNIQUEIDENTIFIER. В этом случае мы можем объявить поле таким образом:
[Id] UNIQUEIDENTIFIERNOT NULL DEFAULT NEWID()
Тогда при вставке новых записей в таблицу, нам нет необходимости указывать ID создаваемой записи. При работе с остальными типами эта логика должна быть реализована на уровне приложения.
Следующее, на что стоит обратить внимание — это объявление основного ключа таблицы. Нам необходимо явно указать то, что создаваемый ключ будет кластерным.
Последнее, что необходимо сделать, это указать с помощью ключевого слова FEDERATED ON, что данная таблица будет являться federated. Данные в ней мы будем разбивать по полю ID.
Итак, с создание таблицы аккаунтов мы разобрались. Едем дальше. Как видно из схемы базы данных, таблица аккаунтов является родительской по отношению к таблицам «кредитная карта» и «банковский счет».