Программы Железо Драйверы Лев Бондаренко
До некоторых пор на вопрос «Как нам увеличить производительность нашей базы данных?» было всего два ответа. Либо вы вкладывали деньги в наращивание мощности аппаратной части, либо развивали бизнес-логику ваших приложений.
Оба решения обладают существенными недостатками. Если вы решаете развивать аппаратную часть, вы можете достаточно быстро оказаться владельцем уникального оборудования с высокой стоимостью сопровождения. Усложнение бизнес-логики приложений приводит к удорожанию ПО промежуточного слоя. В обоих случаях каждый новый вложенный в систему рубль менее эффективен, чем предыдущий.
Теперь разработчики получили альтернативный инструмент, свободный от этих ограничений. Его идея довольно проста: всю БД необходимо разделить на равные части и поместить каждую часть на относительно недорогие и легко заменяемые узлы. При обработке запроса, для выполнения которого требуются данные, находящиеся на нескольких узлах распределенной БД, узел, к которому обращен запрос, разбивает его на части и перенаправляет подзапрос соответствующим узлам. Когда каждый узел обработал свою часть запроса, результат собирается узлом-инициатором и передается клиентскому приложению.
Рассмотрим такой пример. Ваша компания владеет 2 магазинами, которые используют для хранения торговых транзакций SQL-серверы Shop1 и Shop2. Вы хотите хранить заказы в распределенной БД и иметь возможность получать доступ ко всем заказам через некоторую сущность OrdersAll.
Для решения этой задачи вы должны всем серверам, входящим в группу, дать возможность выполнять между собой распределенные запросы. Для этого на каждом сервере надо зарегистрировать остальные серверы как связанные (Linked Servers). Это можно сделать либо из Enterprise Manager в закладке Security - Linked Servers, либо выполнить из Query Analyzer следующую инструкцию:
/* На сервере Shop1 */
exec sp_addlinkedserver ‘Shop2’
exec sp_serveroption ‘Shop2’,
‘Lazy schema validation’, true
/* На сервере Shop2 */
exec sp_addlinkedserver ‘Shop1’
exec sp_serveroption ‘Shop1’,
‘Lazy schema validation’, true
Опция Lazy Schema Validation влияет на увеличение производительности за счет отложенного чтения метаданных из связанных таблиц.
Чтобы проверить корректность сделанных настроек, попробуйте подключиться к серверу Shop1 и выполнить запрос, обращающийся к данным на сервере Shop2. Запрос может выглядеть следующим образом:
select * from Shop2.
northwind.dbo.employees
Здесь Shop2 — имя связанного сервера. Помните, что в синтаксисе распределенных запросов указание имени схемы dbo является обязательным.
Когда сервер Shop1 отрабатывает данный запрос, он обращается к серверу Shop2 и извлекает необходимые данные. Поскольку к данным на сервере Shop2 обращаетесь не вы, а сервер, необходимо позаботиться о правах доступа. SQL Server 2000 поддерживает несколько механизмов аутентификации. Во-первых, сервер может проверить, под каким именем и паролем вы вошли, и затем попытаться получить доступ под этими именем и паролем к данным на сервере Shop2. Во-вторых, можно принудительно указать имя и пароль, под которыми сервер Shop1 будет обращаться к серверу Shop2 при выполнении распределенных запросов. В нашем случае первый механизм является наиболее оптимальным, поскольку учетные записи на обоих серверах будут идентичными. Настроить механизм доступа можно в диалоге Security в свойствах связанного сервера.
Обязательно убедитесь, что на сервере запущен сервис Distributed Transaction Coordinator. Этот сервис отвечает за поддержку распределенных транзакций.
Теперь создадим таблицы, которые будут хранить заказы. Выполните из Query Analyzer следующие скрипты.
/* На сервере Shop1 */
CREATE DATABASE Sales
GO
USE Sales
Go
if exists (select * from dbo.sysobjects where
id = object_id(N’[dbo].[Orders]’)
and OBJECTPROPERTY(id, N’IsUserTable’) = 1)
drop table [dbo].[Orders]
GO
CREATE TABLE [dbo].[Orders] (
[ID_Order] [int] NOT NULL CHECK (ID_Order between 1 and 100),
[OrderDate] [datetime] NOT NULL,
[Description] [varchar] (255)
CONSTRAINT PK PRIMARY KEY ([ID_Order])
)
GO
/* На сервере Shop2 */
CREATE DATABASE Sales
GO
USE Sales
Go
if exists (select * from dbo.sysobjects where
id = object_id(N’[dbo].[Orders]’)
and OBJECTPROPERTY(id, N’IsUserTable’) = 1)
drop table [dbo].[Orders]
GO
CREATE TABLE [dbo].[Orders] (
[ID_Order] [int] NOT NULL CHECK (ID_Order between 101 and 200),
[OrderDate] [datetime] NOT NULL,
[Description] [varchar] (255)
CONSTRAINT PK PRIMARY KEY ([ID_Order])
)
GO
После выполнения этого скрипта вы создадите на серверах Shop1 и Shop2 таблицы Orders, в которые пользователи магазинов будут помещать заказы.
Создадим распределенное представление на обоих серверах.
CREATE VIEW OrdersAll
AS
select * from Shop1.Sales.dbo.
Orders
union all
select * from Shop2.Sales.dbo.
Orders
Теперь для доступа к списку всех заказов пользователи могут обращаться к представлению OrdersAll. Таким образом, от пользователей будет скрыта структура распределенной БД.
Такая возможность присутствовала и в предыдущей версии SQL-сервера. Однако теперь SQL Server 2000 предоставляет возможность модификации данных через распределенные представления. Для этого нужно соблюдать ряд условий при создании таблиц, на которых базируется распределенное представление.
Таблицы должны содержать ключевое поле, отвечающее за сегментацию представления. Поскольку оптимизатор запросов должен решать, к какой именно таблице применить соответствующие изменения, сделанные через распределенное представление, для каждой таблицы нужно описать ограничение CHECK, которое будет содержать условие, ограничивающее ключевое поле по некоторому диапазону.
Для реализации этого условия в нашем примере таблицы Orders содержат ограничения CHECK по ключевому полю ID_Order (ID_Order between 1 and 100) и CHECK (ID_Order between 101 and 200). Так мы сообщаем оптимизатору запросов, что заказы с диапазоном номеров от 1 до 100 будут храниться на сервере Shop1, а заказы с диапазоном от 101 до 200 — на сервере Shop2.
В случае когда вы используете композитный первичный ключ, ограничение, отвечающее за сегментацию, должно базироваться на первом поле композитного ключа.
Таблицы сегментированного представления не могут иметь поля IDENTITY или Timestamp, и, что особенно неприятно, таблицы не могут иметь ограничение DEFAULT, даже если это ограничение связано с полем, не входящим в первичный ключ.
Если все условия соблюдены, вы можете изменять данные через распределенное представление.
Соединитесь с сервером Shop1 и из Query Analyzer запустите следующий скрипт:
SET XACT_ABORT ON
insert OrdersAll ([ID_Order], [OrderDate],
[Description]) values (150, getdate(), ‘T’)
В процессе обработки запроса сервер Shop1 сравнит значение, добавляемое в первичный ключ 150 с ограничениями сегментации и обратится к серверу Shop2 для добавления новой записи в таблицу Orders.
Рассмотрим пример с изменением идентификатора заказа.
SET XACT_ABORT ON
update OrdersAll set [ID_Order] = 2
В результате работы этого скрипта запись переместится из таблицы Orders на сервере Shop2 в таблицу Orders на сервере Shop1.
Таким образом, распределенные секционированные представления открывают разработчикам новые возможности масштабирования их программных продуктов. И даже если производительности вашей системы на данный момент вполне достаточно, разумно закладывать основу построения распределенных БД уже сейчас.
|