![]() |
Технология Клиент-Сервер 2000'3 |
||||||
|
Итак, время 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 — это 64-битное целое, поддерживающее значения от -263 до 263-1. Использовать его предлагается там, где недостаточно обычного целого (231-1). Соответственно появились и новые функции: count big() и rowcount big0, которые соответствуют функции COUNT и переменной @@ROWCOUNT, но возвращают значение типа bigint.
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 – особый тип данных, позволяющий хранить результат выполнения 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, нельзя модифицировать данные в таблицах, не являющихся локальными переменными. Нельзя также создавать временные хранимые функции.
В 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 будет минимальна.
Одно из интереснейших нововведений 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 улучшают производительность следующих типов запросов:
Соединяющих (joins) и/или агрегирующих большое количество строк.
Часто выполняемые операции соединения и агрегирования. Например, в OLTP-базе, хранящей складскую информацию, множество запросов будет соединять таблицы Parts, PartSupplier и Suppliers. Каждый из запросов может обрабатывать всего несколько строк, но суммарные затраты на обработку сотен и тысяч мелких запросов будут весьма существенны. Поскольку эти связи вряд ли будут часто обновляться, общая производительность системы может улучшиться после создания indexed view, хранящего объединенные результаты. Правда, такое положение вещей свидетельствует о неидеальной работе оптимизатора запросов. Например, для Oracle соединение большого количества таблиц практически не сказывается на скорости выполнения самого запроса. У SQL Server порог чувствительности к соединению большого количества таблиц был поднят еще в 7 версии, и для большинства реальных запросов значения не имеет, но, всё же, он ниже, чем у Oracle8i.
Системы поддержки решений. Для аналитических систем характерно хранение обобщенных и агрегированных, нечасто обновляемых данных. Хотя до выхода SQL Server 2000 Microsoft и заявлял, что отсутствие в SQL Server поддержки OLAP не является серьезной проблемой, в жизни встретить аналитическую систему, не интегрированную с OLTP-системой, трудно. Копирование данных, необходимое при старом подходе Microsoft, очевидно, не лучшее решение проблемы.
Indexed view обычно не увеличивают производительности:
OLTP-систем.
Часто обновляемых БД.
Запросов, не содержащих агрегирования или соединений.
Расширяющих соединений (expanding joins), то есть view, чьи результаты шире, чем исходные данные базовых таблиц.
Запросов, агрегирующих данных с большой кардинальностью ключа. Под кардинальностью ключа в виду имеется ключ, содержащий множество различных значений. Уникальный ключ имеет наивысшую кардинальность, поскольку все ключи имеют разные значения. Indexed view повышают производительность, уменьшая число строк, к которым должен обращаться запрос. Если результат запроса ко view имеет столько же строк, сколько и базовая таблица, выигрыш в производительности будет невелик. Например, в случае запроса к таблице, содержащей 1000 записей:
SELECT PriKey, SUM(SalesCol) FROM ExampleTable GROUP BY PriKey
Если кардинальность ключа таблицы – 100, Indexed view, построенное на результатах этого запроса будет включать только 100 записей. Запросы, использующие это view, в среднем читают в десять раз меньше, чем использующие базовую таблицу в случае отсутствия Indexed view. Если же ключ уникален, его кардинальность равна 1000, и Indexed view будет включать 1000 записей. Запрос не получит выигрыша в производительности от чтения Indexed view вместо базовой таблицы.
Oграничения типов индексируемых view могут не позволить создать view для решения конкретной проблемы. Однако всегда можно создать несколько меньших Indexed view, ускоряющих части процесса. Например:
Представьте часто выполняемый запрос, агрегирующий данные в одной БД, агрегирующий данные в другой БД и объединяющий результаты. Поскольку Indexed view не может ссылаться на таблицы нескольких БД, создать единое view для такого процесса нельзя. Но можно создать Indexed view, выполняющее агрегирование в каждой БД. Если оптимизатор сможет использовать indexed view в существующих запросах, будет ускорено хотя бы агрегирование – без переписывания существующих запросов. Объединение результатов не ускоряется, но в целом запрос будет выполняться быстрее за счет использования агрегированных данных, хранящихся в indexed view.
Представьте, что часто выполняемый запрос соединяет данные из нескольких таблиц, и затем использует UNION для объединения результатов. UNION неприменим в indexed view. Вы опять же можете разработать indexed view для каждой из индивидуальных операций агрегирования. Оптимизатор может затем выбирать indexed view, чтобы ускорить запросы без потребности в переписывании запросов. Процессы агрегирования ускоряются, хотя сама обработка UNION - нет.
Лучше всего создавать 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 вместо чтения всех записей базовых таблиц.
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 должно соответствовать следующим требованиям:
При создании View Опции ANSI_NULLS и QUOTED_IDENTIFIER должны быть установлены в ON.
Опция ANSI_NULLS должна иметь значение ON при создании всех таблиц, вызываемых view.
View не должно ссылаться на другие view, только на базовые таблицы.
Все таблицы, вызываемые view, должны находиться в той же самой базе данных, что и view, и иметь того же самого владельца.
View следует создавать с опцией SCHEMABINDING. SCHEMABINDING связывает view со схемой базовых таблиц, на которых основывается view.
Пользовательские функции, используемые в Indexed view, должны быть созданы с опцией SCHEMABINDING.
Таблицы и пользовательские функции должны вызываться по названиям, состоящим из 2-х частей. Названия из 1-, 3- или 4-х частей недопустимы.
Все функции, используемые выражениями view, должны быть детерминированы. IsDeterministic, свойство функции OBJECTPROPERTY, сообщает, детерминирована ли определяемая пользователем функция.
Выражение SELECT во view не может содержать следующие элементы синтаксиса Transact-SQL:
В списке колонок SQL-запроса нельзя использовать синтаксис * или table_name. * для определения колонок. Названия колонок должны быть заданы явно.
Имя столбца таблицы, используемое как простое выражение, не может быть указано более чем в одном столбце view. Однако столбец может быть вызван множество раз как часть сложного выражения или параметра функции. Например, этот список выбора запрещен:
- SELECT ColumnA, ColumnB, ColumnA
А эти - нет:
- SELECT ColumnA, AVG(ColumnA), ColumnA + Column B AS AddColAColB
- SELECT SUM(ColumnA), ColumnA % ColumnB AS ModuloColAColB
Rowset -функций
Выражений UNION
Подзапросов
Outer или self joins
TOP
ORDER BY
DISTINCT
COUNT(*) (вместо него можно использовать COUNT_BIG(*))
Агрегатных функций AVG, MAX, MIN, STDEV, STDEVP, VAR или VARP. Если в запросах, использующих indexed view, используются AVG, MAX, MIN, STDEV, STDEVP, VAR или VARP, оптимизатор зачастую может вычислить необходимый результат, если список выбора 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) |
Например, Indexed view не может иметь колонок, содержащих выражение AVG(SomeColumn), но если view содержит колнку с выражениями SUM(SomeColumn) и COUNT_BIG(SomeColumn), SQL Server может вычислить среднее для запроса, который ссылается на view и использует AVG(SomeColumn).
Функции SUM, ссылающейся на колонки, допускающие NULL-значение.
Текстовые предикаты CONTAINS или FREETEXT
COMPUTE, COMPUTE BY
Если GROUP BY не применяется, колонки Indexed view не могут содержать агрегатных выражений.
Если применяется GROUP BY, колонки Indexed view должны содержать выражение COUNT_BIG(*), а view не может определять HAVING, CUBE, or ROLLUP.
Индексируемая колонка Indexed view не может иметь тип float.
Первый индекс, создаваемый для view, должен быть уникальным кластерным индексом. После его создания можно создать дополнительные некластерные индексы. Соглашения о наименованиях для этих индексов те же, что и для индексов таблиц. Единственная разница - имя таблицы заменяется на имя view.
Требования при создании индексов view схожи с перечисленными ранее для самого view, но имеют и некоторые отличия. Так, выражение CREATE INDEX должно соответствовать следующим требованиям в дополнение к обычным для CREATE INDEX:
Пользователь, выполняющий выражение CREATE INDEX, должен быть владельцем view.
Следующие опции сессии должны быть включены (ON):
ANSI_NULLS
ANSI_PADDING
ANSI_WARNINGS
ARITHABORT
CONCAT_NULL_YIELDS_NULL
QUOTED_IDENTIFIERS
Опция сессии NUMERIC_ROUNDABORT должна быть выключена (OFF).
View не может включать колонок text, ntext или image, даже если они не вкходят в выражение CREATE INDEX.
Если выражение SELECT в определении view содержит оператор GROUP BY, то ключ уникального кластерного индекса может ссылаться только на колонки, указанные в операторе GROUP BY.
После того, как кластерный индекс создан, любое подключение к серверу, пытающееся изменить данные, на которых основывается 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)
Разумеется, 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.
Важный аспект поддержки 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-запросов по соображениям безопасности, поскольку скрывают от пользователя содержание запроса к БД.
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-репликации:
за счет введения альтернативных местоположений snapshot’ов, они теперь могут сохраняться в файлах на локальной сети, на FTP-узле, на сменных носителях и т.п.;
присоединяемые базы данных подписчиков позволяют переносить базы данных с реплицируемыми данными и одной или более подпиской от одного подписчика к другому;
изменения схемы позволяют добавлять или удалять поля в публикуемой таблице и распространять изменения подписчикам;
поддержка новых возможностей SQL Server, включая пользовательские функции, индексированные view, новые типы данных и т.п.;
ActiveX-компонент Snapshot Control, позволяющий создавать snapshot из пользовательских приложений.
Расширена также интеграция репликации и Data Transformation Services (DTS).
В частности, переносимые подписки (transformable subscriptions) могут использовать механизмы переноса данных, трансформации и фильтрации DTS.
Варианты поставки SQL Server 2000
В планы Microsoft входит выпуск нескольких вариантов поставки SQL Server 2000:
SQL Server 2000 Enterprise Edition. Наиболее полная версия продукта, рассчитанная на обеспечение потребностей крупных предприятий и организаций. Этот вариант поддерживает до 32 процессоров и 64 Гбайт памяти благодаря использованию механизма AWE (Address Windowing Extensions), появившегося в Windows 2000 Advanced Server и, конечно, DataCenter Server, который мы также сможем вскоре увидеть).
SQL Server 2000 Standard Edition - вариант для малых и средних (по американским меркам) организаций, который может использоваться в SMP-системах и поддерживать до четырех процессоров и 2 Гбайт памяти.
SQL Server 2000 Personal Edition – облегченная версия, содержащая тем не менее полный набор административных средств и реализующая практически всю функциональность стандартной версии. В отличие от других версий она сможет функционировать под Windows 2000 Professional, Windows NT Workstation и Windows 9х. Ограничения у нее такие: хотя Microsoft и декларирует поддержку двух процессоров, на практике нам не удалось добиться более, чем 50% загрузки обоих процессоров, что говорит о том, что в код встроена некотрая заглушка, не позволяющая использовать параллельных операций. эта версия рассчитана на одновременную работу не более чем пяти пользователей. Хотя физически к БД может подключаться любое количество пользователей, при превышении числа подключений (5) в Event Log помещается сообщение о возможной потере производительности, и такая потеря, причем нелинейная, действительно случается. В этой версии отсутствуют самые интересные новинки SQL Server 2000 – Indexed View и полнотекстовая индексация. Эти ограничения приводят к тому, что программисты будут вынуждены или писать куски кода, эмулирующие отсутствующие функциональность, или делать урезанные версии для работы с этой версией продукта.
SOL Server 2000 Developer Edition - вариант для разработчиков, представляющий собой версию Enterprise Edition, но без лицензии на внедрение созданных приложений.
SQL Server 2000 Desktop Engine (MSDE) – это просто ядро базы данных без пользовательского интерфейса, средств администрирования, OLAP-средств, библиотек и Books Online. Кроме того, ограничен размер создаваемой базы данных. Учитывая, что размер БД многих российских фирм невелики, совместное использование средств администрирования trial-версии клиента SQL Server и MSDE может дать великолепный экономический эффект.
SQL Server 2000 Windows СЕ Edition. Версия SQL Server 2000 для устройств, работающих под управлением Windows СЕ. Обеспечивает программную совместимость с другими версиями SQL Server 2000, позволяя создавать приложения для широкого класса устройств — от компьютеров high-end до мобильных устройств. Довольно загадочное нововведение – поскольку трудно представить сервер под управлением Windows СЕ. Впрочем, на рынке встраиваемых БД такая версия вполне может прийтись ко двору – хотя бы, чтобы Centura/Gupta не чувствовала себя одиноко.
Хотелось бы еще раз попенять 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 ООО "К-Пресс"