Процессор запросов Microsoft SQL Server. Часть 3

3. Распределенные и гетерогенные запросы.

3.1 Универсальный доступ к данным

Рассмотрим типичную СУБД с позиций способа хранения информации и набора сервисов для ее обработки и выборки. Никто не мешает нам написать СОМ-сервер, инкапсулирующий основные сервисы по доступу и обработке данных, причем не обязательно реляционных, а, например, иерархических, таких как электронная почта, служба каталогов и т.д., или вообще неструктурированных. Как внутри него эти службы будут реализованы - личное дело СОМ-сервера, поскольку никто, кроме самих данных, не знает, как их лучше всего обрабатывать. Единственным требованием к нему будет поддержка стандартных интерфейсов, своего рода обязательство объекта обеспечивать декларируемый набор методов с описанными параметрами и типами возвращаемых значений. Это необходимо, чтобы клиентское приложение с помощью одинаковых методов могло одновременно работать с разными типами данных, не требуя переделки. Такой набор стандартных интерфейсов был разработан и получил название OLE DB ([7]). Наш СОМ-сервер в этой ситуации будет называться OLE DB-провайдером. Отталкиваясь от привычных аналогий, провайдер можно уподобить драйверу ODBC. Однако необходимо иметь в виду различия на прикладном и системном уровне. Первое - технология OLE DB нацелена на обеспечение доступа к данным любой природы, а не обязательно реляционным. Во вторых, ODBC - это набор Сшных функций. Если мы пишем приложение, скажем, на VB и хотим вместо RDO (Remote Data Objects - тонкая обертка над ODBC для придания более дружественного интерфейса) использовать ODBC в чистом виде, никаких проблем нет. Сделаем declare соответствующих функций - и вперед. OLE DB, как уже упоминалось, есть совокупность интерфейсов, построенных в соответствии с СОМ, поэтому они принципиально не достижимы из Automation-языков программирования. Для того, чтобы функциональность OLE DB была доступна из ASP, Visual Basic (VBScript, VBA), Visual FoxPro и др., была написана IDispatch-обертка вокруг OLE DB, получившая название ADO (ActiveX Data Objects). В ADO 1.5 была включена служба удаленного доступа (RDS), позволяющая располагать объекты на промежуточном слое между клиентом и сервером. RDS поддерживает прикладные протоколы HTTP и DCOM, то есть в качестве сервера приложений может использоваться Internet Information Server (IIS) или Microsoft Transaction Server (MTS). Компоненты ADO 2.0, входящие в состав Visual Studio 6, дополнены возможностями асинхронной обработки событий, локального кэша на клиенте, иерархического множества записей (с помощью провайдера MSDataShape) и элементами управления для поддержки ADODB.Recordset. Еще одно отличие заключается в том, что ODBC-драйвер для источника, не поддерживающего SQL (например, текстовый файл), должен нести в себе эквивалент SQL-машины, даже если клиенту не потребуется никакой другой функциональности, кроме простого множества записей. Нулевой уровень OLE DB предполагает лишь самые общие базовые возможности. Для их расширения применяются сервисные компоненты, которые могут реализовывать, например, процессор запросов, механизм поддержки курсоров и т.д. Так, механизм курсоров принимает rowset, который нулевой уровень поставляет в строго последовательном виде и дополняет его возможностями прокрутки в обоих направлениях. Нулевой уровень и сервисные компоненты под управлением SCM (Service Control Manager) образуют первый уровень. Таким образом, архитектура OLE DB включает провайдера, потребителя и слой сервисных компонент между ними.

За довольно короткий срок различными фирмами были написаны OLE DB-провайдеры для большинства распространенных серверов баз данных, настольных СУБД, ODBC, Active Directory, Index Server и др. Этот список продолжает пополняться (см., например, http://www.microsoft.com/data/oledb/products/product.htm). Многие из них вместе с примерами их использования распространяются вместе с Data Access SDK 2.0 (http://www.microsoft.com/data/download.htm). Там же можно найти инструментарий для написания собственного OLE DB-провайдера с помощью Visual C++, Visual J++, Visual Basic и т.д. (OLE DB Simple Provider Toolkit). Все они входят в OLE DB SDK 1.5. Расширение OLE DB for OLAP используется в качестве средства доступа к многомерной информации, например, к Microsoft OLAP Services, входящих в состав SQL Server 7.0. Более того, OLE DB является "родным" интерфейсом SQL Server 7.0, т.е. тем интерфейсом, посредством которого процессор запросов общается с механизмом хранения. DB-Library поддерживается путем эмуляции через OLE DB, но развиваться, по-видимому, в дальнейшем уже не будет. Механизм хранения SQL Server 7.0 представляется для процессора запросов просто источником данных, одним из многих OLE DB-достижимых, не более того. Если мы запустим sp_linkedservers, то увидим, что наш собственный сервер рассматривается процессором запросов как еще один присоединенный сервер. На момент написания этих строк в SQL Server 7.0 поддерживались следующие внешние источники: ODBC, MS Access и ISAM, AS/400 и VSAM, Oracle 7.3 и выше , MS Index Server , OLE DB for OLAP и, собственно, OLE DB-провайдер для SQL Server 7.0 (в ранних документах, посвященных тематике универсального доступа, может значиться как Luxor). Здесь необходимо отметить, что провайдер к SQL Server 7.0 можно использовать в версиях 6.х, предварительно запустив на них скрипт instcat.sql, находящийся в mssql7\install. Этот скрипт, очевидно, не требуется запускать, если вы планируете осуществлять связь с предыдущими версиями через OLE DB поверх ODBC.

3.2 Работа с внешними источниками в SQL Server 7.0

В SQL Server 7.0 существуют два основных способа работы с удаленным источником: через прилинкованный сервер (linked server) и через имя, данное по ходу дела (ad hoc name). Прилинкованный сервер есть определяемый заранее виртуальный сервер, описание которого включает в себя информацию об OLE DB-провайдере данного источника и свойства соединения, указывающие провайдеру, где находится источник. Прилинкованные сервера являются единицами администрирования внешних источников данных. Они могут определяться как in-process (исполняющиеся в процессе SQL Server) или out-of-process (как самостоятельные exe-модули). Сервер in-process работает, очевидно, быстрее, однако его целесообразно выбирать для проверенных провайдеров. Несмотря на стандартный характер большинства свойств соединения, каждый провайдер обладает возможностью приема дополнительных значимых параметров (например, для геопространственных данных). Эти параметры также прописываются в прилинкованном сервере и называются атрибутами.

Предположим, в разных доменах у нас находятся два сервера: alexeysh_desk версии 7.0 и alexeysh_lapt версии 6.5. Если между доменами не установлены доверительные отношения, то named pipes, по умолчанию являющиеся основным прикладным протоколом взаимодействия, следует заменить на, скажем, TCP/IP Sockets. Для этого с помощью Client Network Utility следует добавить alexeysh_lapt в список серверов и указать, что конкретно для него мы выбираем сетевую библиотеку TCP/IP. Соединимся с alexeysh_lapt и запустим скрипт instcat.sql, который добавит новые типы и системные таблицы в SQL Server 6.5. Теперь мы можем определить его как прилинкованный сервер по отношению к alexeysh_desk. На соединении с alexeysh_desk выполним следующий скрипт:
sp_addlinkedserver @server= N"alexeysh_lapt", @srvproduct= "SQL Server"

Параметрами процедуры служат: @server - имя, под которым источник будет значиться в списке прилинкованных серверов и через которое мы будем к нему обращаться (N перед именем означает формат Unicode); @srvproduct - название продукта: например, если это SQL Server, то @srvproduct="SQL Server"; если Oracle, то "Oracle". Для Jet и ODBC это пустая строка. Указание @srvproduct в явном виде избавляет нас в данном случае от необходимости ввода других параметров. Аналогичные действия могли бы быть выполнены, например, так:

     sp_addlinkedserver @server="MySQL65", @srvproduct="", @provider="SQLOLEDB",
  
       @datasrc="alexeysh_lapt", @catalog="pubs"

К другим параметрам относятся: @provider - кодовое обозначение провайдера (SQLOLEDB - SQL Server, MSDASQL - ODBC, MSDAORA - Oracle, Microsoft.Jet.OLEDB.3.51, Microsoft.Jet. OLEDB.4.0 - Access, MSIDXS - Index Server и т.д.); @datasrc - имя источника данных (для SQL Server это серверное имя линкуемого сервера, для Access - имя .mdb-файла с указанием полного пути, для ODBC - DSN и т.д.). Имя источника данных может быть также задано среди передаваемых провайдеру свойств. Например, вместо @datasrc="alexeysh_lapt", мы могли бы передать его через параметр @provstr:
sp_addlinkedserver @server=N"MySQL65", @srvproduct="", @provider="SQLOLEDB", @provstr="server=alexeysh_lapt;", @catalog="pubs"

Точно так же в случае ODBC мы можем передать DSN или строку соединения (для так называемого DSNless source). В частности, соединение с alexeysh_lapt может идти не напрямую через провайдера для SQL Server, а через провайдера для ODBC и ODBC-драйвер для SQL Server. Рассмотрим примеры. С помощью ODBC заведем системный DSN по имени ааа для драйвера SQL Server и сервера alexeysh_lapt. Протестируем его и убедимся в работе соединения. Тогда alexeysh_lapt может быть прилинкован как

      sp_addlinkedserver @server="MySQL65ODBC", 

      @srvproduct="", @provider="MSDASQL", @datasrc="aaa"

      или то же самое без создания DSN:

      sp_addlinkedserver @server="MySQL65ODBC", 

      @srvproduct="", @provider="MSDASQL", @provstr="driver={SQL Server};

      server=alexeysh_lapt;uid=sa;pwd=;

      database=pubs"

В общем случае в @provstr оговаривается специфичная для провайдера информация, уникально идентифицирующая источник данных. Параметр @catalog cоответствует свойству DBPROP_INIT_CATALOG при инициализации OLE DB-провайдера. Для SQL Server - это активная база данных. Более подробное описание параметров процедуры sp_addlinkedserver можно найти в документации по Transact-SQL.

Когда прилинкованный сервер участвует в распределенном запросе, локальный SQL Server должен залогиниться на него под какой-то авторизующей информацией, например, от имени действующего пользователя. Отображение локальных логинов на удаленные осуществляется при помощи хранимой процедуры sp_addlinkedsrvlogin. Примеры:
sp_addlinkedsrvlogin @rmtsrvname= "MySQL65", @useself="true" - все пользователи alexeysh_desk будут ходить на alexeysh_lapt под их собственными именами и паролями на alexeysh_desk, т.е. преобразование отсутствует (@useself="true") .

sp_addlinkedsrvlogin @rmtsrvname= "MySQL65", @useself="false", @locallogin=NULL, @rmtuser= "sa", @rmtpassword="" - все логины alexeysh_desk (@locallogin=NULL) будут авторизовываться на alexeysh_lapt как sa с пустым паролем. Если в @rmtpassword указать какой-нибудь левый пароль, то при попытке обратиться к MySQL65 будет выдано сообщение login failed. При аутентификации пользователей SQL Server средствами Windows NT сервер alexeysh_desk попытается прикинуться для alexeysh_lapt NTвым пользователем. Способность SQL Server 7.0 эмулировать аутентифицирующую информацию пользователей Windows NT носит название делегирования и доступна только когда и локальный, и прилинкованный сервер работают под NT 5.0.

Обратная операция (удаление отображения локального логина) выполняется с помощью sp_droplinkedsrvlogin. Sp_dropserver @server= "MySQL65", @droplogins="droplogins" удаляет сервер из списка прилинкованных с одновременным удалением отображенных на него пользователей.

Проиллюстрируем распределенные запросы на примере. В качестве объекта эксперимента выберем модельную базу данных pubs, устанавливающуюся вместе с SQL Server. Экспортируем таблицу titles в Excel. В состав SQL Server 7.0 включены службы преобразования данных (Data Transformation Services), основным назначением которых является извлечение данных из операционных источников, их очистка, унификация, проверка на непротиворечивость и промежуточное агрегирование перед погружением их в хранилище. В среде Microsoft Datawarehousing Framework, обеспечивающей жизненный цикл хранилища, DTS управляют потоками данных и метаданных между MS SQL Server и многомерным кубом OLAP Server, но в принципе они могут работать с любыми OLE DB-источниками. Основной административной единицей DTS служит пакет (package). По своей идеологии пакет DTS родственен заданию (job) SQL Agent (бывший SQL Executive). Он состоит из шагов, логика выполнения которых может ветвится в зависимости от результата работы предыдущих шагов. Шаг соответствует элементарной операции DTS, например, создание таблицы, копирование данных и т.д. В качестве шагов могут использоваться операторы SQL, ActiveX-скрипты, исполняемые файлы (.exe), насосы данных (data pumps) или какие-то пользовательские действия в соответствии с интерфейсом IDTSCustomStep. Сами пакеты хранятся в MS Repository, SQL Server или в виде persistent СОМ-объектов. Поскольку нам требуется просто перекачать данные из SQL Server в другой формат, проще всего прибегнуть к DTS Wizard (контекстное меню таблицы в SQL Enterprise Manager -> task -> Export from SQL). Аналогично, перенесем таблицу sales в предварительно подготовленную базу данных fox_sales в Visual FoxPro 6.0, а таблицу stores - в базу access_stores в MS Access 97. Что у нас еще доступно? Текстовый файл. Давайте экспортируем таблицу publishers в publishers.txt. Ниже приведен файл schema.ini для текстового драйвера ODBC.

[publishers.txt]

      ColNameHeader=False

      Format=FixedLength

      MaxScanRows=25

      CharacterSet=OEM

      Col1=PUB_ID Char Width 4

      Col2=PUB_NAME Char Width 40

      Col3=CITY Char Width 20

      Col4=STATE Char Width 2

      Col5=COUNTRY Char Width 30

Создадим прилинкованные сервера для каждого из перечисленных источников. Таблицу Excel можно присоединять как через OLE DB-провайдера для ODBC:

if exists (select srvname from master.dbo.sysservers where srvname="MyExcel97")

      exec sp_dropserver @server= "MyExcel97", @droplogins="droplogins"

      go

      exec sp_addlinkedserver @server= "MyExcel97", @srvproduct="", @provider="MSDASQL.1",

       @provstr="Driver={Microsoft Excel Driver (*.xls)};",@catalog="d:\temp\HetQueries\titles.xls"

(указание @catalog в явном виде, как мы помним, не является обязательным и может быть передано в свойствах провайдера:

@provstr="Driver={Microsoft Excel Driver (*.xls)}; DBQ=D:\TEMP\HetQueries\titles.XLS;"),

так и через OLE DB-провайдера для Jet:

exec sp_addlinkedserver 

      @server="MyExcel97", 

      @srvproduct="Jet 4.0", @provider= "Microsoft.Jet.OLEDB.4.0", 

       @datasrc="d:\temp\HetQueries\Titles.xls", @location=NULL, @provstr="Excel 5.0;"

В случае прилинковки через Jet, требуется задать отображение пользователя:

 exec sp_addlinkedsrvlogin "MyExcel97", false, sa, "Admin", NULL 

С текстовым файлом и таблицей FoxPro соединимся с помощью провайдера для ODBC:

exec sp_addlinkedserver

      @server="MyText", @srvproduct="", @provider="MSDASQL.1",

       @provstr="Driver={Microsoft Text Driver (*.txt; *.csv)};

       DefaultDir=D:\TEMP\HetQueries"



      exec sp_addlinkedserver

      @server="MyVFP6", @srvproduct="", @provider="MSDASQL.1",

       @provstr="Driver={Microsoft Visual FoxPro Driver};

       UID=;PWD=;SourceDB=D:\TEMP\HetQueries\fox_sales.dbc; SourceType=DBC; Exclusive=No;

      BackgroundFetch=Yes;Collate=Machine;"

а с базой данных в Access - через провайдера для Jet:

exec sp_addlinkedserver 

      @server="MyAccess97", 

      @srvproduct="Access 97", @provider ="Microsoft.Jet.OLEDB.4.0",

       @datasrc="d:\temp\HetQueries\Access_stores.mdb"

В случае ODBC перед нами везде пример соединения без создания DSN, когда вся необходимая информация (название драйвера, местоположение файла) тут же передается провайдеру. Если вид строки @provstr для какого-либо ODBC-драйвера заранее неизвестен, его легко выяснить экспериментально, временно создав соответствующий DSN и посмотрев, какие свойства передаются провайдеру при DSN-соединении. Допустим, мы не знаем, как должна выглядеть @provstr для ODBC-драйвера для Excel. Создадим на таблицу Excel DSN по имени ааа. Cледующий код

Dim cnn As New ADODB.Connection

      cnn.Provider = "MSDASQL"

      cnn.Open ("DSN=aaa")

      Debug.Print cnn.ConnectionString

      cnn.Close

даст нам строку соединения

Provider=MSDASQL.1;Connect Timeout=15;Extended Properties="DSN=aaa;

       DBQ=D:\TEMP\HetQueries\titles.XLS;DefaultDir=D:\TEMP\HetQueries;

       DriverId=790;FIL=excel 5.0; MaxBufferSize=512;PageTimeout=5;"; Locale Identifier=1049

В ней следует обратить внимание на Extended Properties. Вместо DSN=aaa нужно поставить Driver={...}, в фигурных скобках ставится название ODBC-драйвера точно в таком виде, как оно значится в ODBC Data Source Administrator, закладка Drivers.

Механизм разрешения имен SQL Server 7.0 поддерживает названия, состоящие из 4-х частей: <имя прилинкованного сервера>.<каталог>.<схема>. <имя объекта>, например, MySQL65.pubs.dbo. authors. Некоторые провайдеры не требуют обязательного присутствия всех частей или имеют для них значения по умолчанию, такие части могут опускаться. Например, если мы прилинковываем Excel через провайдера для ODBC, то имя листа (Sheet) titles может выглядеть так: MyExcel97.[d:\temp\HetQueries\ titles]..[titles], если же через провайдера для Jet, то его можно указать в виде MyExcel97...[titles]. По имени прилинкованного сервера SQL Server на основе информации, прописанной в системные таблицы при его (прилинкованного сервера) создании, идентифицирует провайдера и отсылает ему оставшиеся три части имени. Этих сведений провайдеру должно быть достаточно, чтобы однозначно определить объект в источнике.

Запросы к прилинкованным серверам могут быть двух типов: с использованием имени из 4-х частей, либо сквозные (passthrough). В качестве примера с именами из 4-х частей преобразуем сообразно ситуации запрос на Лист.1.1.2

select a.au_fname, a.au_lname, t.title, p.pub_name, s.qty, st.stor_name from authors a

      inner join MySQL65.pubs.dbo.titleauthor ta on a.au_id=ta.au_id

      inner join MyExcel97...[titles] t on ta.title_id=t.title_id 

      inner join MyText.[D:\TEMP\HetQueries]..[publishers.txt] p on t.pub_id=p.pub_id

      inner join MyVFP6.[fox_sales]..[sales] s on s.title_id=t.title_id

      inner join MyAccess97...[stores] st on s.stor_id=st.stor_id

Можно его выполнить и убедиться, что результат будет в точности таким же, как и у его прототипа на Лист.1.1.2, где все данные хранились на локальном сервере.

Сквозные запросы создаются при помощи функции OpenQuery(). Первым аргументом этой функции выступает имя прилинкованного сервера, вторым - собственно текст запроса: select * from OpenQuery(Monarch, "select FileName from scope(""c:\Program Files"")"). Запрос внутри OpenQuery() не проверяется и не анализируется SQL Server"ом, а напрямую передается прилинкованному источнику так, как есть. Отсутствие предобработки позволяет сэкономить время, но требует аккуратности при составлении запроса. Пример: запросы

select * from OpenQuery(MyExcel97, "select * from titles where type=""business""") и

      select * from OpenQuery(MyExcel97, "select * from titles") where type="business"

дают один и тот же результат, однако во втором запросе проверку условия фильтрации выполняет SQL Server, а в первом - OLE DB-провайдер. Первый запрос следует признать более эффективным, поскольку в этом случае пересылать приходится меньшее количество данных.

Третий вариант построения распределенного запроса (ad hoc name) позволяет вообще обойтись без прилинкованного заранее сервера. Вызов функции OpenRowset подменяет обращение к таблице. В параметрах должна быть указана информация, позволяющая установить соединение с удаленным источником, и сама таблица в виде <каталог>.<схема>.<объект>, либо запрос. Пример:

select * from OpenRowset("MSDASQL", "Driver={Microsoft Excel Driver (*.xls)};

       DBQ=D:\TEMP\HetQueries\titles.XLS;", "select * from titles where type=""business""")

При совместной работе с данными, относящимися как к SQL Server, так и к удаленным источникам следует иметь в виду, что внешние данные всегда доступны на чтение. Поддержка операций обновления внешних данных зависит от уровня обслуживающего их провайдера. Над входящими в тот же запрос данными, принадлежащими SQL Server, возможны любые допустимые операции. Следовательно, внешние данные всегда могут быть использованы для создания представлений и статических курсоров. Обновление внешних данных через представления или keyset-курсоров определяется возможностями провайдера. Динамические курсоры и операторы DDL над внешними данными не поддерживаются. Конвертация данных осуществляется путем приведения к ближайшему соответствующему типу, определенному в стандартах OLE DB. Сортировка выполняется в соответствии с порядком, заданным на локальном SQL Server. Участие внешних данных в транзакциях зависит от того, реализованы ли в провайдер интерфейсы поддержки транзакций. Например, если провайдер поддерживает интерфейс ITransactionLocal, но не поддерживает ITransactionJoin, данные удаленного источника можно включать в локальные транзакции, но они не смогут наследовать контекст внешней транзакции и, следовательно, не будут участвовать в распределенных транзакциях ([7]). Поддержка провайдером интерфейса IDBSchemaRowset позволяет SQL Server"у получать информацию о метаданных. Для этого можно использовать системные хранимые процедуры sp_catalogs, sp_tables_ex, sp_columns_ex, sp_table_privileges, sp_column_privileges, sp_primarykeys, sp_foreignkeys, sp_indexes и др. Если провайдер предоставляет информацию об имеющихся индексах, процессор запросов SQL Server сможет точнее оценить распределенный запрос и оптимизировать его выполнение. В плане запроса

select st.stor_name, st.city, s.ord_num, s.qty from stores st, 

       MyOracle..klm.sales s where s.stor_id=st.stor_id and s.qty>50

      ---------------- 

      /-Merge Join(Inner Join, 

      MANY-TO-MANY MERGE:(s.stor_id)= (Expr1002) 

       ESIDUAL:(s.stor_id=Convert(st.stor_id)))

           /-Remote Query(SELECT `s`.`ord_num` AS Col1007,`s`.`qty` AS Col1008,`s`.`stor_id` 

              AS Col1006 FROM `sales` s WHERE `s`.`qty`>(50) ORDER BY `s`.`stor_id` ASC)

           /-Sort(ORDER BY: (Expr1002 asc))

                /-Compute Scalar(Expr1002=Convert(st.stor_id))

                     /-Clustered Index Scan(pubs..stores.UPK_storeid AS st)

выделенным шрифтом показан подзапрос, который в действительности SQL Server отсылает на сервер Oracle. Шаг Merge Join получает от провайдера Oracle отфильтрованные по qty и отсортированные по stor_id результаты запроса. Если бы таблица sales находилась, скажем, в виде текстового файла, то в плане вместо Remote Query стояло бы сканирование всей удаленной таблицы (выполняется провайдером) с последующими шагами фильтрации и сортировки (выполняется процессором запросов SQL Server).

3.3 Полнотекстовый поиск

Одним из частных примеров применения технологии универсального доступа может служить возможность полнотекстового поиска в SQL Server 7.0. Полнотекстовый провайдер (full-text provider) представляет собой промежуточное звено, посредством которого клиентское приложение взаимодействует со службой полнотекстового поиска (Microsoft Search Service). Служба полнотекстового поиска устанавливается как комопонент SQL Server 7.0 стандартной (Standard) и коропоративной (Enterprise) редакции и функционирует как сервис Windows NT. Настольная (Windows 9x) редакция SQL Server способна использовать полнотекстовый поиск подобно клиентам SQL Server, установившим соединение с сервером стандартной или корпоративной редакции. Служба полнотекстового поиска создает каталоги и полнотекстовые индексы. Каждая запись индекса содержит указатель на запись таблицы, слова, ассоциированные с этой записью за вычетом незначащих (noisy words), информацию о поле, которому они принадлежат, и месте их нахождения в этом поле. В качестве указателя записи используется первичный ключ (primary key) или кандидат (candidate). На таблицу можно создать не более, чем один полнотекстовый индекс. Каждый индекс находится в своем каталоге. База данных может иметь несколько индексных каталогов, но каждый каталог должен соответствовать только одной базе данных. Полнотекстовые индексы не допускаются над представлениями, а также системными или временными таблицами. Возможны два способа наполнения полнотекстовых индексов - Full Population (применяется при начальном создании индекса, либо при существенном изменении содержания индексированных полей) и Incremental Population. Последний доступен для таблиц, имеющих поле timestamp. Изменение содержания индексированных полей не влечет за собой немедленной поправки полнотекстового индекса, так как последние довольно объемны и при их постоянной модификации происходила бы заметная задержка. Вместо этого можно оформить Incremental Population как задание (job), выполняющееся с некоторой периодичностью с помощью SQL Agent. Каталог является минимальной единицей обновления полнотекстовых индексов. Кроме того, в функции службы полнотекстового поиска входит обработка специальных конструктов в запросах (предикаты CONTAINS и FREETEXT), с помощью которых осуществляется поиск отдельных слов и фраз, учет расстояния между словами (NEAR), распознавание словоформ (FORMSOF) и взвешивание по значимости (ISABOUT). В качестве примера создадим таблицу с полем pgh типа text, в каждую запись которой положим отдельный абзац этой статьи. Это можно сделать с помощью макроса:

Sub Macro1()

      Dim cnn As Object

      Set cnn = CreateObject("ADODB. Connection")

      Dim rst As Object

      Set rst = CreateObject("ADODB.Recordset")

      With cnn

      .Open "Provider=SQLOLEDB; Data Source=alexeysh_desk; User ID=sa; Password=; 

      Initial Catalog=pubs"

      .Execute "CREATE TABLE MySQLPaper (id int IDENTITY (1, 1) CONSTRAINT 

      [PK_MySQLPaper] PRIMARY KEY NONCLUSTERED (id) ON [PRIMARY], pgh ntext, ts timestamp) 

       ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]"

      For Each pgh In ActiveDocument.Paragraphs

       .Execute "insert into mysqlpaper (ts) values (default)"

       rst.Open "select pgh from MySQLPaper where id=@@identity", cnn, 1, 3, -1

       rst.Fields(0) = pgh

       rst.Update

       rst.Close

      Next

      .Close

      End With

      End Sub

Таблица готова. Ассоциируем список незначащих слов (noisy words) с файлом noise.dat:

 sp_configure "Language neutral full-text", 1 
    
      go

      reconfigure

      go 

Делаем текущую базу данных доступной для полнотекстового поиска:
exec sp_fulltext_database @action="enable"

Создаем новый полнотекстовый каталог SQLPaper по заданному пути:
exec sp_fulltext_catalog @ftcat= "SQLPaper", @action="create", @path="d:\mssql7b3_dat\FTData"

Создаем метаданные полнотекстового индекса и указываем, что идентификация записей в таблице MySQLPaper должна происходить по ключу PK_MySQLPaper:
exec sp_fulltext_table @tabname="MySQLPaper", @action= "create", @ftcat="SQLPaper", @keyname="PK_MySQLPaper"

Добавляем поле pgh как одно из тех, по которому будет происходить полнотекстовый поиск (индекс пока неактивен):

 exec sp_fulltext_column @tabname="MySQLPaper", @colname="pgh", @action="add" 

Регистрируем таблицу в каталоге полнотекстового поиска файловой системы:
exec sp_fulltext_table @tabname="MySQLPaper", @action="activate"

Все вышеперечисленные действия интерактивно удобнее выполнять с помощью программы-мастера полнотекстовых индексов, которая создает каталог и структуру индекса. Нам остается лишь наполнить индексы в данном каталоге:
exec sp_fulltext_catalog @ftcat="SQLPaper", @action="start_full"

После чего к таблице можно обращаться с запросами типа:
select id, pgh from MySQLPaper where contains(pgh, ""полнотекст*" near "поиск"")

Из плана выполнения следует, что процессор запросов SQL Server проверяет, определен ли на поле pgh полнотекстовый индекс и преобразует оператор SQL в последовательность действий над множеством записей. Обычно эти действия через OLE DB-провайдера передаются механизму хранения SQL Server. Однако действия, относящиеся к контекстному поиску, передаются OLE DB-провайдеру службы полнотекстового поиска. Эта служба осуществляет поиск по своим каталогам и содержащимся в них полнотекстовым индексам и возвращает набор указателей на записи, отвечающим условию поиска. Процессор запросов комбинирует его с наборами, полученными от других провайдеров, в частности, механизма хранения и строит окончательное множество результатов, которое возвращается клиентскому приложению. Каталоги и индексы, находящиеся под управлением службы полнотекстового поиска, не хранятся в базе данных SQL Server, следовательно, их не охватывают операции резервного копирования и восстановления. Подробнее об архитектуре и синтаксических конструкциях полнотекстового поиска можно узнать, обратившись к документации.

Служба полнотекстового поиска, входящая в состав SQL Server 7.0 обеспечивает поиск по строковым и текстовым полям (в том числе Unicode). Контекстный поиск по документам файловой системы или опубликованным на Web-сервере осуществляется с помощью индексных механизмов Microsoft Index Server или Microsoft Site Server и рассмотренной нами технологии гетерогенных запросов (например, через прилинкованные сервера). Для доступа к этим индексам используются OLE DB-провайдеры (соответственно, для Index Server или Site Server), так что описанная выше схема полнотекстового поиска сохраняется с точностью до провайдера. Базовые синтаксические расширения полнотекстового поиска в Transact-SQL одинаковы и поддерживаются каждым из трех упомянутых провайдеров.

Список литературы

1. Byrne, Jeffry L. "Microsoft SQL Server: What Database Administrators Need To Know", Prentice Hall, 1997, ISBN 0-13-495409-2. (Джеффри Л.Бирн. "Microsoft SQL Server 6.5. Руководство администратора". Лори, 1997)

2. Debetta, P. "Microsoft SQL Server 6.5 Programming Unleashed". SAMS Publishing, 1998, ISBN 0-67231-244-1

3. England, Ken. "The SQL Server 6.5 Performance Optimization and Tuning Handbook". Digital Press, ISBN 1-5558-180-3

4. Fushimi, Sh., Kitsuregawa, M., Tanaka, H. "An Overview of The System Software of A Parallel Relational Database Machine GRACE". VLDB Conf. 1986: 209-219

5. Graefe, G., Bunker, R., Cooper S. "Hash joins and hash teams in Microsoft SQL Server". VLDB Conf., 1998

6. Graefe G. "Query Evaluation Techniques for Large Databases". ACM Computing Surveys 25(2): 73-170 (1993).

7. "Microsoft OLE DB 1.1 Programmer"s Reference and Software Development Kit". Microsoft Press, 1997, ISBN 1-57231-612-8. ("Справочник по Microsoft OLE DB 1.1". Русская Редакция, 1997)

8. Rankins, R.; Solomon, D. "Microsoft SQL Server 6.5 Unleashed". SAMS Publishing, 1998, ISBN 0-672-31190-9. (Д.Соломон и др. "Microsoft SQL Server 6.5. Энциклопедия пользователя". Диасофт, 1998)

9. Schneider, Robert D. "Microsoft SQL Server: Planning and Building a High Performance Database". Prentice Hall, 1997, ISBN 0-13-266222-1. (Роберт Д.Шнайдер. "Microsoft SQL Server. Проектирование высокопроизводительных баз данных". Лори, 1997)

10. Soukup, Ron. "Inside Microsoft SQL Server 6.5". Microsoft Press, 1997, ISBN 1-57231-331-5.

11. Spenik, M., Sledge, O. "Microsoft SQL Server 6.5 DBA Survival Guide". SAMS Publishing, 1996, ISBN 0-672-30959-9

12. Vaughn, William R.. "Hitchhiker"s Guide to Visual Basic and SQL Server". Microsoft Press, 1998, ISBN 1-57231-848-1

13. Zeller, H., Gray J. "An Adaptive Hash Join Algorithm for Multiuser Environments". VLDB Conf. 1990: 186-197

14. Горев А., Макашарипов С., Владимиров Ю. "Microsoft SQL Server 6.5 для профессионалов". Изд-во "Питер", 1997, ISBN 5-88782-427-1

15. Макашарипов С. "Программирование баз данных на Visual Basic 5 в примерах". Изд-во "Питер", 1997, ISBN 5-88782-315-1

Алексей Шуленин, Microsoft, системный инженер, тел. 967-85-85

Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=25333