Продолжается подписка на наши издания! Вы не забыли подписаться?

Microsoft SQL Server 2000 — что нового?

Итак, время SQL Server 7.0 истекло. На смену ему пришел Microsoft SQL Server 2000 — следующая версия сервера БД от фирмы Microsoft. Эта новая версия во многом похожа на S0L Server 7.0, и, возможно, если бы не страсть к переименованиям, ее можно было бы назвать версией 7.х.

Наиболее интересными для разработчиков будут улучшения в реляционном механизме. Эти усовершенствования расширяют функциональность СУБД, превращая SQL Server 2000 в прекрасную среду для разработки приложений, и мы в этой статье уделим большое внимание улучшениям программируемости SQL Server 2000 на Transact-SQL. Примеры в тексте основаны на поставляемом вместе с SQL Server БД Northwind.

Другая тема для разговора – индексированые view, они же Indexed View. Это нововведение уже знакомо пользователям некоторых других РСУБД, например, Oracle 8. Оно позволяет значительно ускорить выполнение повторяющихся запросов к нечасто обновляемым данным.

Кроме изменений в Transact-SQL в новой версии сделано множество внутренних изменений, служащих для улучшения ПМН (производительности, масштабируемости и надежности). Теперь поддерживаются до 32 процессоров и до 64GB памяти, параллельные операции DBCC (database consistency checking) и индексирования, улучшены резервное копирование и восстановление данных, поддерживаются кластеры серверов, встроено управление серверами резерва (log shipping) и поддержка высокоскоростной технологии System Area Network (SAN).

Репликация – это область, где внесено огромное количество изменений. Если оно вам нужно, всерьез подумайте о переходе на SQL Server 2000. При транзакционной репликации, появившейся в новой версии подписчик получает обновления через транзакционную очередь сообщений. Это позволяет большую часть времени работать в режиме офф-лайн, отключившись от сети.

Полнотекстовый поиск – еще одна область, где программисты Microsoft смогли внести изменения. Теперь ведется лог изменений индексированных текстовых данных. Полнотекстовый индекс можно обновлять вручную, по расписанию или по мере появления изменений.

Расширения возможностей реляционной базы данных

Новые типы данных

В SQL Server 2000 появилось три новых типа данных — bigint, sql variant и table.

bigint 

bigint — это 64-битное целое, поддерживающее значения от -263 до 263-1. Использовать его предлагается там, где недостаточно обычного целого (231-1). Соответственно появились и новые функции: count big() и rowcount big0, которые соответствуют функции COUNT и переменной @@ROWCOUNT, но возвращают значение типа bigint.

sql_variant

sql_variant способен хранить любой стандартный тип данных, кроме text, ntext, image, timestamp и себя самого. Этот тип данных очень напоминает тип данных variant в VB, позволяя хранить в колонках, параметрах или переменных значения других типов данных. Например, колонка типа sql_variant может содержать данные типов int, decimal, char, binary или nchar. Каждый экземпляр sql_variant содержит значение данных и метаданные – тип данных, максимальный размер и т.д. Применяя этот тип данных следует помнить, что хранимые данные нужно преобразовывать к оригинальному типу с помощью функции CAST или CONVERT.

DECLARE @my_var sql_variant
SET @my_var = 3.142
DECLARE @my_chr VARCHAR(12), @my_dec DECIMAL(5,4)
SET @my_chr = CAST(@my_var AS VARCHAR(12))
SET @my_dec = CAST(@my_var AS DECIMAL(5,4))

Для получения информации об оригинальном типе данных можно использовать новую функцию SQL_VARIANT_PROPERTY.

SQL_VARIANT_PROPERTY(выражение, свойство),

где свойство – имя свойства SQL_VARIANT, например, BaseType, Precision, Scale, TotalBytes, Collation или MaxLength.

Этот тип данных очень полезен там, где управление метаданными можно возложить на приложение.

table

table – особый тип данных, позволяющий хранить результат выполнения SQL-запроса для дальнейшей обработки. Главная его задача – временное хранение набора строк, который может использоваться в SQL-запросах как таблица или возвращаемое значение пользовательской функции.

Этот тип данных может использоваться вместо временных таблиц, хранящихся в базе данных tempdb.

Определив локальную переменную этого типа, ее можно использовать так же, как временную таблицу. Разумеется, к ней неприменимы такие выражения, как:

INSERT INTO table_variable EXEC stored_procedure
SELECT select_list INTO table_variable statements

Чтобы определить локальную таблицу, нужно использовать обычное выражение DECLARE:

DECLARE @local_variable TABLE <table_defintion>

Покажем на примере, как это делается. Определим и заполним локальную переменную, содержащую данные о территориях из БД Northwind:

DECLARE @territory TABLE (territory_id INT, territory_desc NVARCHAR(50))
INSERT INTO @territory
SELECT TerritoryId, TerritoryDescription FROM Territories

Над переменными типа table можно выполнять операции SELECT, INSERT, UPDATE, DELETE, но операции ALTER, DROP, TRANCATE TABLE недопустимы. Основные отличия табличного типа от временных таблиц состоят в области видимости (локальная табличная переменная видна только внутри процедуры или функции, где была объявлена, но может возвращаться как out-параметр или в качестве возвращаемого значения функции) и в том, что для переменных типа table нельзя создавать неуникальные индексы.

Тип данных table крайне полезен при использовании в сочетании с пользовательскими функциями, которые мы рассмотрим в следующем разделе.

Пользовательские функции

В SQL Server 2000 появилась поддержка пользовательских функций (User-Defined Functions, UDF). Такие функции давно знакомы пользователям серверов Oracle или Informix. Теперь они появились и в SQL Server. Transact-SQL расширен операторами CREATE FUNCTION, ALTER FUNCTION и DROP FUNCTION.

Пользовательские функции сходны с хранимыми процедурами. Однако, в отличие от хранимых процедур, они могут использоваться в запросах так же, как и системные функции. Как и хранимые процедуры, они могут иметь один или несколько параметров, но возвращают скалярные типы данных, например, int, decimal, varchar, sql_variant – или тип данных table.

Операторы, создающие пользовательские функции, сходны с аналогичными для хранимых процедур. Главные различия – требование указать значение RETURNS и заканчивать функцию выражением RETURN.

Пользовательская функция, возвращающая тип данных table может объявить внутреннюю табличную переменную и вернуть содержимое этой переменной. Такие функции называют rowset-функциями. Они могут использоваться в запросах вместо таблиц и view там, где Transact-SQL это допускает.

Пользовательские функции, возвращающие таблицы, могут стать достойной альтернативой view. View ограничены одним выражением select, а пользовательские функции способны включать дополнительные выражения, что позволяет создавать более сложные и мощные конструкции.

Простой пример пользовательской функции, возвращающей таблицу, можно привести на основе view для БД Northwind, возвращающего продажи за 1997 год. Листинг 2 показывает, как можно создать функцию, возвращающую продажи за год, указанный как параметр функции.

Использовать эту функцию можно, так же, как и обыкновенное view. Единственное различие – теперь можно указать параметр - нужный год:

SELECT * FROM ProductSalesByYear(1996)

Расширяя этот простой пример, предположим, что нужно получить продажи за 1997 год вместе с информацией о категории, но только для сумм, превышающих $15 000. Это тоже несложно:

SELECT Product.ProductID, Product.ProductName, Product.ProductSales,
Categories.*
FROM ProductSalesByYear(1997) AS Product
INNER JOIN Categories ON Product.CategoryID = Categories.CategoryID
WHERE Product.ProductSales > 15000

Если пользовательская функция возвращает скалярный тип данных, все, что нужно – определить тип возврата и указать значение в выражении return. Листинг 1 показывает пример, возвращающий целое, представляющее число заказов, полученных в указанный день. Эту функцию можно использовать в выражениях select или set:

DECLARE @count INT
SET @count = dbo.SalesForSpecifiedDate('12/12/97')

Листинг 1. Пользовательская функция – продажи за указанную дату

CREATE FUNCTION dbo.SalesForSpecifiedDate (@date DATETIME)
RETURNS INT
AS
BEGIN
DECLARE @ordercount INT
DECLARE @startdate DATETIME, Senddate DATETIME
DECLARE @txtdate VARCHAR(12)
SET @txtdate - CAST(
DATENAME(year, @date) + '/' +
CAST(DATEPART(month, @date) AS VARCHAR(2)) + '/' +
DATENAME(day, @date) AS DATETIME
)
SET @startdate - CAST(@txtdate AS DATETIME)
SET @enddate - CAST(@txtdate AS DATETIME) + 1
SET @ordercount - (SELECT COUNT(*) FROM Orders
WHERE OrderDate >- @startdate AND OrderDate < @enddate)
RETURN (@ordercount)
END
GO

Листинг 2. Пользовательская функция – продажи за год

CREATE FUNCTION dbo.ProductSalesByYear (@year INT = NULL)
RETURNS @Categories TABLE (
CategoryID INT,
CategoryName NVARCHAR(15),
ProductID INT,
ProductName NVARCHAR(40),
ProductSales MONEY
)
AS
BEGIN
IF @year IS NULL
SET @year - (SELECT MAX(DATEPART(year, ShippedDate)) FROM Orders)
INSERT INTO @Categories
SELECT Categories.CategorylD, Categories.CategoryName,
Products.ProductID, Products.ProductName,
SUM(CONVERT(MONEY,([Order Details].UnitPr1ce*Quantity*(1-Discount)/
100))*100)
AS ProductSales
FROM (Categories
INNER JOIN Products
OH Categories.CategoryID - Products.CategoryID)
INNER JOIN (Orders
INNER JOIN [Order Details]
OH Orders.OrderID - [Order Details].OrderID)
ON Products.ProductID - [Order Details].ProductID
WHERE (DATEPART(year, Orders.ShippedDate) - @year)
GROUP BY Categories.CategoryID, Categories.CategoryName,
Products.ProductID, Products.ProductName
RETURN
END
GO

В Листинге 2 показано, как вернуть значение табличной переменной. Явное определение таблицы как таковой позволяет осуществлять различные действия над этой таблицей (например, применять выражения типа insert) до того, как вернуть результат. Но есть, однако, особый тип пользовательских функций, возвращающих тип table, и называемых in-line функциями. Такие функции возвращают resultset единичного выражения select, без объявления табличных переменных и без определения таблицы в операторе RETURNS.

In-line функции подчиняются следующим правилам:

Вспомните хранимую процедуру БД Northwind, возвращающую 10 самых дорогих продуктов. Пример реализации того же в виде in-line функции может выглядеть так:

CREATE FUNCTION dbo.TenMostExpensiveProductsTable ()
RETURNS TABLE
AS
RETURN (SELECT TOP 10
ProductName AS TenMostExpensiveProducts,
UnitPrice, SupplierID, UnitsInStock, UnitsOnOrder
FROM Products
ORDER BY Products.UnitPrice DESC)

Преимущества этого подхода перед использованием хранимой процедуры - возможность использования функций в запросах. Если нужно выбрать 10 самых дорогих продуктов и информацию о поставщиках, можно написать такой запрос:

SELECT Products.*, Suppliers.*
FROM TenMostExpensiveProductsTable() AS Products
INNER JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID

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

Триггеры INSTEAD OF

В SQL Server 2000 появился новый вид триггеров – триггер INSTEAD OF. Триггер INSTEAD OF выполняется вместо какого-либо действия (INSERT, UPDATE, DELETE). Такие триггеры могут быть определены и для view, что позволяет изменить логику обновления view или делать обновляемыми не обновляемые view. По сути, такой триггер позволяет выполнить некий скрипт Transact SQL вместо физического изменения базовых таблиц. Вы можете вручную изменять данные таблиц БД, реализуя логику любой сложности. Отсутствие такой функциональности ставилось в укор Microsoft такими оппонентами, как Oracle.

Microsoft ввел еще один вид триггера – AFTER, но он ничем не отличается от триггеров, которые применялись в предыдущих версиях этой РСУБД, и по умолчанию используется именно он. Единственной альтернативой AFTER является INSTEAD OF. Microsoft так и не ввел аналога BEFORE-триггерам. А жаль, ведь все ограничения проверяются до запуска триггеров, и в случае их нарушения триггеры просто не запускаются. Кстати, это утверждение верно и для INSTEAD OF-триггеров. Это не дает вмешаться в логику записи изменений до проверки декларативных ограничений.

Если разобраться по существу, то AFTER вообще не соответствует действительности, так как у SQL Server в триггере доступны виртуальные таблицы inserted и deleted. С их помощью в триггере можно установить, какое состояние было в БД до выполнения действия, запустившего триггер и после, а такие триггеры соответствуют понятию ВОВРЕМЯ (On). По уму, Microsoft надо было просто добавить возможность выполнять триггер до проверки декларативных ограничений или после. Тогда надобность в BEFORE-триггерах вообще отпала бы, а пока есть два решения:

Примеры триггеров INSTEAD OF приведены в Листинг 3 и Листинг 4.

Листинг 3 INSTEAD OF триггер (instead)

CREATE TRIGGER dbo.trg region ins ON Region
INSTEAD OF INSERT
AS
BEGIN
-- Process records that require an update
UPDATE Region SET
Region.RegionDescription - inserted.RegionDescription
FROM Region INNER JOIN inserted
ON Region.RegionID - inserted.RegionID
-- Process records that require an insert
INSERT INTO Region
SELECT inserted.*
FROM inserted LEFT JOIN Region
ON inserted.RegionID - Region.RegionID
WHERE Region.RegionID IS NULL
END
GO
CREATE TRIGGER dbo.trg territories ins ON Territories
INSTEAD OF INSERT
AS
BEGIN
-- Process records that require an update
UPDATE Territories SET
Territories.TerritoryDescription - inserted.TerritoryDescription,
Territories.RegionID - inserted.RegionID
FROM Territories INNER JOIN inserted
ON Territories.TerritoryID - inserted.TerritoryID
-- Process records that require an insert
INSERT INTO Territories
SELECT inserted.*
FROM inserted LEFT JOIN Territories
ON inserted.TerritoryID - Territories.TerritoryID
WHERE Territories.TerritoryID IS NULL
END
GO
 

Листинг 4 INSTEAD OF триггер (update)

CREATE TRIGGER dbo.trg employeename update ON EmployeeName
INSTEAD OF UPDATE
AS
BEGIN
UPDATE Employees SET
FirstName - SUBSTRING(inserted.EmployeeName, 1,
(CHARINDEX(' '. inserted.Employeename) - 1)),
LastName - SUBSTRING(inserted.EmployeeName,
(CHARINDEX(' ', inserted.EmployeeName) + 1),
DATALENGTH(inserted.EmployeeName))
FROM Employees INNER JOIN inserted
ON Employees.EmployeeId - inserted.EmployeeId
END
GO

Каскадная ссылочная целостность

При задании декларативной ссылочной целостности появилась возможность добавлять выражения ON UPDATE CASCADE и ON DELETE CASCADE, что приводит к каскадному изменению связанных таблиц. Опытным разработчикам БД это вряд ли что даст, поскольку инструменты типа ERWin давно позволяют реализовать подобную функциональность с помощью триггеров, причем более гибко, чем то, что можно сделать декларативным способом. Однако все, что объявлено декларативно, автоматически становится метаданными, доступными другим приложениям. Это выгодно отличает такой способ от эмуляции функциональности с помощью триггеров.

Проще всего показать действие этой новой возможности на примере. Рассмотрим определения внешних ключей в таблице Order Details к таблицам Orders и Products БД Northwind:

ALTER TABLE dbo.[Order Details] ADD
CONSTRAINT FK_Order_Details_Orders FOREIGN KEY
(OrderID) REFERENCES dbo.Orders(OrderID),
CONSTRAINT FK_Order_Details_Products FOREIGN KEY
(ProductID) REFERENCES dbo.Products (ProductID)

Это определение предотвращает операции над Orders и Products, приводящие к появлению «потерянных» записей в таблице Order Details заказов. В новом стиле это можно записать с помощью нового ограничения NO ACTION, и наш пример будет выглядеть следующим образом:

ALTER TABLE dbo.[Order Details] ADD
CONSTRAINT FK_Order_Details_Orders FOREIGN KEY
(OrderID) REFERENCES dbo.Orders(OrderID)
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT FK_Order_Details_Products FOREIGN KEY
(ProductID) REFERENCES dbo.Products (ProductID)
ON UPDATE NO ACTION
ON DELETE NO ACTION

Но с точки зрения здравого смысла такое ограничение в данных условиях не слишком удачно. Если изменить код продукта, может потребоваться изменить этот код во всех заказах. Лучше всего это делать каскадно для всех связанных записей. Аналогично, если заказ удален, нужно удалить и соответствующие ему записи в Order Details. Теперь это просто:

ALTER TABLE dbo.[Order Details] ADD
CONSTRAINT FK_Order_Details_Orders FOREIGN KEY
(OrderID) REFERENCES dbo.Orders(OrderID)
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT FK_Order_Details_Products FOREIGN KEY
(ProductID) REFERENCES dbo.Products (ProductID)
ON UPDATE CASCADE
ON DELETE NO ACTION

Расширения порядка сортировки

При установке SQL Server 7.0 было необходимо указать кодовую страницу по умолчанию и порядок сортировки. Таким образом, все базы данных были связаны с определенной кодовой страницей и порядком сортировки. В SQL Server 2000 этот подход расширен за счет введения понятия collation — коллекции из трех свойств: порядка сортировки для Unicode-данных, порядка сортировки для не-Unicode-данных и кодовой страницы, используемой для хранения не-Unicode-строк.

Теперь при установке SQL Server 2000 задается язык по умолчанию, а в процессе работы можно задать язык на уровне базы данных или колонки, что существенно облегчает создание многоязычных приложений.

Для русских разработчиков это приводит только к лишним проблемам (например, при экспорте структуры с помощью SQL Server Enterprise Manager), но грамотное назначение collation по умолчанию сводит проблемы к минимуму. Можно рекомендовать перед установкой SQL Server удостовериться, что в системе выбрана русская локаль. Тогда русский язык автоматически будет выбран языком SQL Server 2000 по умолчанию. Для поддержки же многоязычности лучше и проще использовать Unicode, тогда зависимость от collations будет минимальна.

Indexed View (индексированные представления)

Одно из интереснейших нововведений MS SQL Server 2000 – Indexed View. Помните недавний спор Microsoft и Oracle? Потрясающие результаты Oracle, послужившие причиной предложения миллионного пари Ларри Элисона были основаны на материализованных view. Ларри Элисон заявил, что на одном из стандартных тестов Microsoft SQL Server будет работать не менее, чем в 100 раз медленнее. Подробнее об условиях пари можно прочитать в 1 номере нашего журнала за 1999 год, или на www.k-press.ru/KS/KS199/larry1.html. Изначально смысл теста TPC-D заключался в измерении производительности сервера на ресурсоемких операциях типа агрегирования данных в больших таблицах. Применение материализованных view привело к тому, что результаты таких запросов стали постоянно храниться в БД, а оптимизатор Oracle позволил неявно использовать эти результаты. Тогда Microsoft заявила, что тест является нечестным, и даже смогла продемонстрировать сходные по времени результаты с помощью не самого SQL Server 7.0, а входящего в его поставку SQL Server OLAP Services. Теперь же, видимо, Microsoft решила ответить той же крапленой картой, реализовав такую же функциональность под другим названием. Правда, мы вряд ли услышим предложение пари от Билла Гейтса. Учитывая предстоящий выход Windows 2000 Data Center, нам предстоит веселое время сравнений, тестирований и прочего. Можно надеяться, что Oracle опять укажет Microsoft на недочеты этой версии SQL Server, и Microsoft снова прислушается к этим справедливым замечаниям. Правда, непонятно, зачем Oracle заниматься решением проблем Microsoft.

Indexed view существенно увеличивают производительность некоторых типов запросов. Лучше всего они работают с редко обновляемыми данными. Однако стоимость использования Indexed view может быть выше цены поддержки индекса для таблицы, например, если данные, на основе которых построено view, часто обновляются.

Indexed view улучшают производительность следующих типов запросов:

Indexed view обычно не увеличивают производительности:

SELECT PriKey, SUM(SalesCol)
FROM ExampleTable
GROUP BY PriKey

Использование Indexed View в запросах

Oграничения типов индексируемых view могут не позволить создать view для решения конкретной проблемы. Однако всегда можно создать несколько меньших Indexed view, ускоряющих части процесса. Например:

Лучше всего создавать indexed view, удовлетворяющие нескольким операциям. Оптимизатор может использовать indexed view, даже если оно не указано в операторе FROM, и хорошо продуманное indexed view может ускорить обработку многих запросов. Например, рассмотрим создание индекса для следующего view:

CREATE VIEW ExampleView (PriKey, SumColx, CountColx, SquareColx)
AS
SELECT PriKey, SUM(Colx), COUNT_BIG(Colx)
FROM MyTable
GROUP BY PriKey

Это view может не только удовлетворять запросам, которые непосредственно ссылаются на его столбцы, но и использоваться для запросов, которые обращаются к базовой таблице и содержат выражения типа SUM(Colx), COUNT_BIG(Colx), COUNT(Colx) и AVG(Colx). Все такие запросы станут быстрее, потому что они должны всего лишь получить небольшое число записей из view вместо чтения всех записей базовых таблиц.

Создание Indexed View

View называют также виртуальными таблицами, потому что набор результатов, возвращаемый view, в общем имеет ту же самую форму, что и таблица со столбцами и строками. На view можно ссылаться из SQL-запроса так же, как и на таблицу. Набор результатов обычного view не сохраняется в базе данных. Каждый раз, когда запрос ссылается на view, Microsoft SQL Server 2000 динамически объединяет логику, необходимую для формирования набора результатов view c логикой, необходимой для формирования результатов всего запроса по данным основных таблиц. Процесс формирования результатов view Microsoft называет материализацией view (что-то знакомое...).

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

Еще одно преимущество создания индекса для view, это то, что оптимизатор начинает использовать этот индекс даже в тех запросах, которые не ссылаются на view напрямую. Уже существующие запросы могут выиграть от увеличения эффективности поиска данных в индексированных view без переписывания.

Создание кластерного индекса view сохраняет данные в том виде, в котором они существуют во время создания индекса. Indexed view автоматически отражает изменения данных основных таблиц так же, как и индекс, созданный для основной таблицы.

Для создания кластерного индекса view должно соответствовать следующим требованиям:

Сложная агрегатная функция 

Заменяющие простые агрегатные функции 

AVG(X)

SUM(X), COUNT_BIG(X) 

STDEV(X)

SUM(X), COUNT_BIG(X), SUM(X**2) 

STDEVP(X)

SUM(X), COUNT_BIG(X), SUM(X**2)

VAR(X)

SUM(X), COUNT_BIG(X), SUM(X**2)

VARP(X)

SUM(X), COUNT_BIG(X), SUM(X**2)

Первый индекс, создаваемый для view, должен быть уникальным кластерным индексом. После его создания можно создать дополнительные некластерные индексы. Соглашения о наименованиях для этих индексов те же, что и для индексов таблиц. Единственная разница - имя таблицы заменяется на имя view.

Требования при создании индексов view схожи с перечисленными ранее для самого view, но имеют и некоторые отличия. Так, выражение CREATE INDEX должно соответствовать следующим требованиям в дополнение к обычным для CREATE INDEX:

После того, как кластерный индекс создан, любое подключение к серверу, пытающееся изменить данные, на которых основывается view, должно иметь те же установки опций, что и требуемые для создания индекса. SQL Server генерирует ошибку и откатывает любые выражения INSERT, UPDATE, или DELETE, пытающиеся изменить набор результатов view, если подключение, их выполняющее, не имеет соответствующих установок опций.

Все индексы view удаляются, если удаляется view. Все некластерные индексы удаляются, если удаляется кластерный индекс. Некластерные индексы могут быть удалены индивидуально. Удаление кластерного индекса удаляет хранящиеся результаты, и оптимизатор возвращается к стандартной обработке.

В то время, как в выражении CREATE UNIQUE CLUSTERED INDEX определены только столбцы, которые составляют ключ кластерного индекса, в базе данных сохраняется полный набор результатов. Как и в кластерном индексе базовой таблицы, структура B-дерева кластерного индекса содержит только колонки ключа, а строки данных содержат все столбцы набора результатов view.

Если вы хотите добавить индексы к view в существующей системе, можно сбросить view и создать заново, указав WITH SCHEMABINDING. Другой способ - создать другое view с тем же текстом, что и существующее, но с другим именем. Оптимизатор учтет индексы нового view, даже если оно не указано напрямую в операторе FROM запроса.

Следует убедиться, что новое view соответствует всем требованиям к indexed view. Это может потребовать смены владельца view и всех базовых таблиц, чтобы все они имели одного владельца.

Indexed View для ROLAP-разделов

Если режим хранения раздела - реляционный OLAP (ROLAP), и исходные данные хранятся в Microsoft SQL Server 2000, SQL Server 2000 Analysis Services пытаются создавать indexed view, хранящие агрегаты раздела. Если Analysis Services не могут создать indexed view, вместо них автоматически генерируются и используются агрегированные таблицы. Создание и использование индексированных view для агрегирования требует соблюдения условий, обязательных для indexed view.

Расширенные свойства

Расширенные свойства представляют собой пары «имя/значение» типа sql_variant объемом до 7500 байт и могут использоваться для хранения различной информации. Реализация таких свойств опирается на системные хранимые процедуры sp_setextendedproperty, sp_dropextendedproperty, sp_updateextendedproperty и функцию fn_listextendedproperty для извлечения расширенных свойств объекта.

Ниже показан пример использования расширенных свойств

EXEC sp_addextendedproperty 'caption', 'Employee_Id', 'user', dbo, 'view', foo_view, 'column', id
SELECT * FROM ::fn_listextendedproperty ('caption', 'user', 'dbo', 'view', foo_view, 'column', NULL)

Поддержка XML

Разумеется, Microsoft выставляет на первый план поддержку языка XML и возможность работы с данными в этом формате. Вы рады? Это нововведение предназначено, конечно, для дальнейшего продвижения Интернета в массы, поскольку XML сейчас называют «универсальным форматом представления данных».

Для вывода результатов запроса в виде XML используется новое ключевое слово FOR XML. Предусмотрено три варианта вывода результатов: RAW, AUTO и EXPLICIT.

FOR XML RAW — в этом случае каждая запись возвращается как элемент документа с тэгом row, каждое поле является атрибутом элемента. Например, запрос:

SELECT Customers.CustomerID, Orders.OrderID
FROM Customers, Orders
WHERE Order.CustomerID= Customers.CustomerID
FOR XML RAW

возвращает

<row CustomerID="1" OrderDate="10.12.99" />
<row CustomerID="2" OrderDate="12.01.00" />

FOR XML AUTO — в этом случае каждая запись является элементом документа с тэгом, который несет имя таблицы. Каждое поле является атрибутом элемента. Например, запрос:

SELECT Customers.CustomerID, Orders.OrderID
FROM Customers, Orders
WHERE Order.CustomerID= Customers.CustomerID
FOR XML AUTO

возвращает

<Orders OrderDate="10.12.99" />
<Orders OrderDate="15.11.99" />
</Customers>

FOR XML EXPLICIT позволяет получить XML любой структуры, но требует специального построения запроса.

Ключевое слово FOR XML позволяет также получить DTD-схему документа.

В SQL Server 2000 введены расширения языка определения схем XDR (XML-Data Reduced).

Применение XML-view позволяет работать с таблицами БД как с ХМL-документами. Для выполнения SQL-запросов к XML-документам используется OpenXML, ключевое слово Transact-SQL, возвращающее набор данных по XML-документу. Это ключевое слово можно использовать совместно с выражениями SELECT, SELECT INTO там, где допускается использование таблиц, view или ключевого слова OPENROWSET. OpenXML требует перед созданием запроса создать внутреннее представление XML-документа с помощью хранимой процедуры sp_xml_preparedocument.

Работа через HTTP

Важный аспект поддержки XML в SQL Server 2000 – возможность доступа к реляционным данным через HTTP. Такой доступ реализуется через ISAPI-фильтр Microsoft Internet Information Services (IIS), который предоставляет виртуальные «корни» (virtual roots) (аналогичные виртуальным директориям IIS) для управления нижележащими данными SQL Server. Для их настройки предусмотрена графическая утилита, можно настраивать их и программно, через объектную модель SQL Server.

При доступе через HTTP поддерживаются SQL-запросы, шаблоны запросов и XPath-запросы.

 http://localhostNorthwind?sql=select+firstname,+lastname+from+employees+for+xml+auto&root=root
http://localhost/Northwind/templates/orderscustsql.xml?CustName=GROSR
http://localhost/Northwind/templates/orderscustxpath.xml?CustName=GROSR

Две последних строки используют шаблоны запросов, приведенные в Листинг 1. Шаблон – это XML-документ, состоящий из одного или более SQL-выражений или XPath-запросов. Шаблон действует как контейнер для результирующих фрагментов XML-документа, формируя законченный XML-документ. Кроме этого, можно определить параметры, передаваемые SQL-выражениям или XPath-запросам. Шаблоны предпочтительнее SQL-запросов по соображениям безопасности, поскольку скрывают от пользователя содержание запроса к БД.

Листинг 5 Файлы-шаблоны

ordercustsql.xml
<?xml version = "1.0" encoding="UTF-"?>
<ROOT xlmns:sql="urn:schemas-microsoft-com:xml-sql">
<sql:header>
<sql:param name='CustName"></sql:param>
</sql:header>
<sql:query>
SELECT oh.CustomerID, oh.OrderID, od.ProductID, odUnitPrice, od.Quantity
FROM Orders oh INNER JOIN [Order Details] od
ON oh.ordered = od.ordered
WHERE oh.CustomerID = @CustName
ORDER BY oh.CustomerID, oh.OrderID, od.ProductID
FOR XML AUTO
</sql:query>
</ROOT>
ordercustxpath.xml
<?xml version = "1.0" encoding="UTF-8"?>
<ROOT xlmns:sql="urn:schemas-microsoft-com:xml-sql">
<sql:header>
<sql:param name='CustName"></sql:param>
</sql:header>
<sql:xpath-query mapping-schema="orderschema.xml">
Order[@CustomerID=$CustName]
</sql:xpath-query>
</ROOT>

Если в URL указано имя шаблона, исполняются выражения SQL или XPath-запросы, хранимые в файле шаблона. Шаблон определяется в пространстве имен SQL. Необязательная заголовочная секция содержит определения параметров или определения XSL-файлов. Секция запроса должна содержать FOR XML, а секция XPath-запроса – ссылку на аннотированное определение схемы реляционных данных.

SQL Server поддерживает аннотированные XML Data Reduced (XDR)-схемы. Это позволяет создавать XML-view реляционных данных, хранящихся в БД. К таким XML-view можно обращаться с помощью языка XPath.

Еще о новинках

Ключевой целью любой новой версии РСУБД является улучшение производительности. Любой обзор новой версии РСУБД не может обойтись без рассмотрения этого вопроса. Итак, в SQL Server кроме архитектурных изменений и индексированных view сделано немало для улучшения производительности.
Некоторое улучшение производительности при работе с данными типов text, ntext и image должно проистечь из того, что их можно стало хранить в строке данных вместо отдельной страницы. По умолчанию эта опция выключена (на уровне таблицы). Включить ее можно с помощью системной хранимой процедуры sp_tableoption:

EXEC sp_tableoption 'Employees', 'text in row', 'ON'

Установки по умолчанию соответствуют 256 байтам. Этот размер можно изменить, указав число байтов, сохраняемых в строке, от 24 to 7000. Например, размер в 1KB можно задать следующим образом:

EXEC sp_tableoption 'Employees', 'text in row', '1024'

Все большее число операций SQL Server может выполняться параллельно. Если рагьше параллельно выполнялись только запросы, выбирающие данные, то теперь уменьшено время индексации. На многопроцессорных машинах появилась возможность построения планов запросов для создания индексов, что позволяет многопоточную параллельную индексацию. У нас, к сожалению, не было времени протестировать повышение производительности, проистекающее из такого параллелизма, но мы провели некоторые испытания параллельной обработки на операциях типа SELECT, и можем сказать, что SQL Server 2000 на платформе РС (по крайней мере, в двухпроцессорной конфигурации, на которой производились испытания) показывает самое большое увеличение производительности по сравнению с конкурирующими продуктами, причем с установками по умолчанию. SQL Server сам определяет возможность распараллеливания запроса. Обычно это запросы, сканирующие более одной большой таблицы, или запросы, обрабатывающие очень большие количества данных. Перед этим SQL Server строит план запроса с учетом параллельной обработки. Этот план можно увидеть в графическом виде через утилиту Query Analyser. При выполнении запроса, который SQL Server в силах распараллелить, оба процессора система параллельно загружались на 100%, при этом скорость выполнения запроса возрастала более, чем на 85%. Надеемся, что Enterprise-версия SQL Server 2000 будет так же гибко масштабироваться при большем количестве процессоров.

Можно заставить индексацию использовать БД tempdb для немедленной сортировки результатов, в отличие от обычного порядка, когда результаты записываются в назначенную группу файлов. Чтобы включить эту опцию, нужно использовать WITH SORT_IN_TEMPDB. Это увеличивает объем дискового пространства, необходимый для создания индекса, но может дать выигрыш во времени, если tempdb и основная БД находятся на разных дисках.

CREATE NONCLUSTERED INDEX IDX_NCT_ORDERS_CI_OD
ON Orders (CustomerID ASC, OrderDate DESC)
WITH SORT_IN_TEMPDB

Улучшена параллельная обработка служебных задач. Это включает ускорение дифференциального резервирования, параллельное выполнение DBCC и параллельное сканирование.

Параллельное сканирование, разумеется, применяется на многопроцессорных машинах. Параллельно сканировать можно даже одну таблицу, если группа файлов таблицы включает более одного файла. Из этого следует, что создание нескольких файлов в одной файловой группе может привести к повышению производительности – поскольку для параллельного сканирования нескольких файлов создается несколько потоков. Аналогично, когда запрос объединяет таблицы из разных файловых групп, таблицы будут читаться параллельно, ускоряя выполнение запроса.

Важно упомянуть поддержку Address Windowing Extensions (AWE) API Windows 2000. SQL Server 2000 Enterprise Edition поддерживает 8-гигабайтное адресное пространство при работе под Advanced Server и 64GB под Windows 2000 Datacenter Server.

В SQL Server 2000 изменен оптимизатор запросов, в частности, улучшена оптимизация обработки запросов с ТОР 'n'. Вместо полной сортировки, использовавшейся в SQL Server 7.0, в SQL Server 2000 применяется новый механизм Тор 'n' Engine.

В SQL Server 2000 появился ряд расширений в полнотекстовом поиске. Функция «change tracking» протоколирует все изменения в индексированных полнотекстовых данных, а фильтрация полей типа image (image filtering) позволяет индексировать и извлекать документы, хранимые в таких колонках. Поддерживаются фильтры для документов MSOffice и HTML.

Стоит упомянуть и еще одну новинку — Log Shipping. Этот механизм позволяет создавать резервные копии протоколов транзакций.

Протокол транзакций, выполняемых в одной базе данных на исходном сервере, копируется в базу данных на другом сервере, что позволяет организовать так называемый сервер теплого резерва (warm standby server) или разгрузить сервер за счет переноса части запросов на другой сервер. Для управления Log Shipping используется Log Shipping Monitor.

Существенно расширены возможности Data Transformation Services. Введена возможность использования ключей и ограничений. Кроме этого появилась возможность создания пользовательских задач. DTS Packages теперь можно сохранять в виде скриптов VB.

Расширенные средства администрирования

Средства администрирования SQL Server 2000 не поставят в тупик администраторов предыдущей версии. Изменения носят в основном косметический характер и сводятся к изменению названий и поддержке новых возможностей самого сервера.

Утилита трассировки SQL-запросов получила теперь название SQL Profiler. Она позволяет подключаться к серверу, как и SQL Query Analyzer. Появилась возможность трассировки по шаблонам, причем ряд шаблонов (например, Dead Lock, Replay, Tuning, Stored Procedure) уже входит в состав поставки.

В SOL Query Analyzer появился Object Browser, браузер объектов, предоставляющий информацию об объектах БД. Через Object Browser доступны описания пользовательских и системных таблиц, view, хранимых процедур, расширенных хранимых процедур и функций. Немного странно, что во всех средствах разработки Microsoft вывод такой метаинформации производится с помощью функций IntelliSence, а здесь это не поддерживается, хотя все необходимые для этого данные у Object Browser есть. Чувствуется, что в Microsoft правая и левая руки уже давно не обменивались информацией. Этих рук, кстати, куда больше, чем две. Краткий анализ, например, выявил в продуктах Microsoft более 6 реализаций текстовых редакторов с подсветкой синтаксиса, причем многие из них поддерживают синтаксис SQL. Одна из таких реализаций используется в средствах администрирования SQL Server. По возможностям она сильно уступает редактору, встроенному в MS Visual C. Почему его не использовали в средствах администрирования SQL Server, непонятно. Зачем было писать новый, худший редактор? SQL Server – достаточно дорогой продукт, чтобы выжимать из пользователей деньги, заставляя покупать дополнительные средства разработки. Впрочем, следует быть справедливыми. Только в поставку IBM DB2 входит редактор с подсветкой синтаксиса, остальные SQL-серверы обходятся без него, вынуждая пользователей покупать средства сторонних разработчиков.

Лучше было бы Microsoft вместо затрат на создание восьмого варианта цветного редактора встроить отладку T-SQL, поддержку IntelliSence и пользовательский интерфейс в стиле MS Office (с поддержкой VBA).

Расширения возможностей репликации

Ряд новинок, появившихся в SQL Server 2000, связан с репликацией. Так, в новой версии расширены возможности snapshot-репликации, transactional-репликации и merge-репликации:

Расширена также интеграция репликации и Data Transformation Services (DTS).

В частности, переносимые подписки (transformable subscriptions) могут использовать механизмы переноса данных, трансформации и фильтрации DTS.

Варианты поставки SQL Server 2000

В планы Microsoft входит выпуск нескольких вариантов поставки SQL Server 2000:

Хотелось бы еще раз попенять Microsoft на отсутствие поддержки Windows 2000 Professional и Windows NT Workstation нормальными версиями РСУБД. Понятно, что это корпоративная политика, направленная на увеличение продаж дорогих серверных ОС. Но, по крайней мере, в наших условиях это только увеличит сбыт пиратских копий – ведь сотни долларов за ОС заплатит практически любая фирма, нуждающаяся в SQL Server, а тысячи – в такие деньги обойдется серверная версия - многие предпочтут сэкономить.

Заключение

Конечно, в кратком обзоре нельзя подробно рассмотреть все новые возможности и изменения, появившиеся в Microsoft SQL Server 2000. Разумеется, многие затронутые в этом обзоре вопросы заслуживают отдельных статей. Эти статьи, скорее всего, появятся в ближайших номерах нашего журнала.

Намного интереснее подумать о назначении новой версии SQL Server. Не секрет, что большинство профессионалов БД говорят о SQL Server как о сервере масштаба подразделения. Однако новая версия однозначно претендует на завоевание верхней части корпоративного рынка, то есть рыночной ниши Oracle и DB2. По опыту можно сказать, что IBM не станет устраивать шоу из взаимных нападок (после OS/2 IBM ни разу не пыталась громко ругаться с конкурентами), а вот как поведет себя Oracle...

Драка больших дяденек нам, конечно, на руку. Остается только пожелать, чтобы она велась не на PR-уровне, а на уровне технологических решений. По всякому, нам предстоит интересная осень.

Сейчас SQL Server существует только в бета-версиях, кстати, сейчас проводится открытое бета-тестирование. Все желающие могут принять в нем участие – один раз увидеть и попробовать, несомненно, куда полезнее, чем прочитать любое количество статей.


Copyright © 1994-2016 ООО "К-Пресс"