23 июля 2012 г.

Работа с XML данными в Microsoft SQL Server 2008. Особенности работы с XML.


В прошлой статье мы познакомились с типом данных «XML» в Microsoft SQL Server 2008, научились писать разнообразные запросы для выборки данных из XML документов. Однако на этом возможности этого типа данных не исчерпываются. Кроме операций для выборки данных, также предоставляются функции для добавления, обновления и удаления XML данных.
Все вышеперечисленные операции можно выполнить при помощи функции modify().

В качестве тестовых данных, во всех примерах, мы будет использовать следующий XML документ:
   1:  DECLARE @xmlData XML =N'
   2:  <Shops> 
   3:      <Shop id="1">
   4:          <device name="Sensation" vendor="HTC" id="1" />
   5:          <device name="iPhone" vendor="Apple" id="2" />
   6:      </Shop>
   7:      <Shop id="2">
   8:          <device name="Mozart" vendor="HTC" id="3" />
   9:          <device name="Lumia" vendor="Nokia" id="4" />
  10:      </Shop>
  11:  </Shops>';
Начнем с операции вставки данных, общий синтаксис команды следующий:
            insert Expression1 ( { as first | as last } into | after | before Expression2 )
Допустим, мы хотим добавить новое устройство во второй магазин – выполним команду modify() и запросим результат:
   1:  SET @xmlData.modify('
   2:      insert <device name="Xperia" vendor="Sony" id="5" />
   3:      into (/Shops/Shop[@id=2])[1]
   4:  ');
   5:   
   6:  SELECT @xmlData;
Результат будет следующим:
   1:  <Shops>
   2:    <Shop id="1">
   3:      <device name="Sensation" vendor="HTC" id="1" />
   4:      <device name="iPhone" vendor="Apple" id="2" />
   5:    </Shop>
   6:    <Shop id="2">
   7:      <device name="Mozart" vendor="HTC" id="3" />
   8:      <device name="Lumia" vendor="Nokia" id="4" />
   9:      <device name="Xperia" vendor="Sony" id="5" />
  10:    </Shop>
  11:  </Shops>
Как видно из структуры результата, новый элемент встроился в конец поддерева. Используя модификатор ‘as first ‘ перед ключевым словом into, можно изменить это поведение по умолчанию.
Также существуют еще несколько способов для определения места вставки нового элемента в документ: используя модификаторы after или before вместо into.
Вставка нескольких элементов. В предыдущем примере показано, как вставить один элемент, однако, что если требуется вставить сразу набор данных? Такую задачу можно выполнить, внедрив в код дополнительную переменную. Давайте добавим в наш документ новый магазин, с набором товаров:
   1:  DECLARE @newShop XML = N'
   2:      <Shop id="3">
   3:          <device name="Xperia" vendor="Sony" id="5" />
   4:          <device name="Optimus" vendor="LG" id="6" />
   5:      </Shop>
   6:  ';
   7:   
   8:  SET @xmlData.modify('
   9:      insert sql:variable("@newShop")      
  10:      into (/Shops)[1]
  11:  ');
  12:   
  13:  SELECT @xmlData;
Результат показан ниже:
   1:  <Shops>
   2:    <Shop id="1">
   3:      <device name="Sensation" vendor="HTC" id="1" />
   4:      <device name="iPhone" vendor="Apple" id="2" />
   5:    </Shop>
   6:    <Shop id="2">
   7:      <device name="Mozart" vendor="HTC" id="3" />
   8:      <device name="Lumia" vendor="Nokia" id="4" />
   9:    </Shop>
  10:    <Shop id="3">
  11:      <device name="Xperia" vendor="Sony" id="5" />
  12:      <device name="Optimus" vendor="LG" id="6" />
  13:    </Shop>
  14:  </Shops>
Добавление новых атрибутов к элементам документа. Добавим к устройству с id = 4 атрибут «reserved»:
   1:  SET @xmlData.modify('
   2:      insert attribute reserved { 1 }
   3:      into (/Shops/Shop/device[@id=4])[1]
   4:  ');
   5:   
   6:  SELECT @xmlData;
Результат показан ниже:
   1:  <Shops>
   2:    <Shop id="1">
   3:      <device name="Sensation" vendor="HTC" id="1" />
   4:      <device name="iPhone" vendor="Apple" id="2" />
   5:    </Shop>
   6:    <Shop id="2">
   7:      <device name="Mozart" vendor="HTC" id="3" />
   8:      <device name="Lumia" reserved="1" vendor="Nokia" id="4" />
   9:    </Shop>
  10:  </Shops>
Обновление данных. Теперь посмотрим, как можно обновить данные XML типа. Допустим, необходимо элементу «device» с id = 4 установить производителя «HTC». Выполним следующий код:
   1:  SET @xmlData.modify('
   2:      replace value of (/Shops/Shop/device[@id=4]/@vendor)[1]
   3:      with ( "HTC" )    
   4:  ');
   5:   
   6:  SELECT @xmlData;
Результат показан ниже:
   1:  <Shops>
   2:    <Shop id="1">
   3:      <device name="Sensation" vendor="HTC" id="1" />
   4:      <device name="iPhone" vendor="Apple" id="2" />
   5:    </Shop>
   6:    <Shop id="2">
   7:      <device name="Mozart" vendor="HTC" id="3" />
   8:      <device name="Lumia" vendor="HTC" id="4" />
   9:    </Shop>
  10:  </Shops>
Стоит отметить, что данная команда может проводить обновление только одного узла документа.
Удаление данных. Последняя команда, доступная типу данных XML – удаление узлов из документа. Давайте удалим все устройства производителя HTC:
   1:  SET @xmlData.modify('
   2:      delete /Shops/Shop/device[@vendor="HTC"]
   3:  ');
   4:   
   5:  SELECT @xmlData;
Результат приведен ниже:
   1:  <Shops>
   2:    <Shop id="1">
   3:      <device name="iPhone" vendor="Apple" id="2" />
   4:    </Shop>
   5:    <Shop id="2">
   6:      <device name="Lumia" vendor="Nokia" id="4" />
   7:    </Shop>
   8:  </Shops>
Необходимо сказать, что запросы к XML данным не отличаются особой производительностью (особенно это можно заметить при фильтрации элементов по какому-то значению или при доступе к родительскому элементу). В связи с этим, решения на основе XML в SQL Server необходимо использовать с осторожностью, не забывая анализировать свои запросы на предмет производительности.
Также, среда SQL Server предоставляет нам механизм оптимизации производительности обращения к XML – специальные XML индексы. Такой индекс может быть эффективен, если вы пишите запросы к данным XML, которые являются колонкой типа «xml» в вашей таблице. Процедура создания XML индекса следует далее:
  1. Сначала создается главный индекс на столбце типа «xml»:
       1:  CREATE PRIMARY XML INDEX PXML_ShopDevices ON dbo.Shop (Devices);
  2. Далее необходимо создать специализированный индекс, на основе главного:
       1:  CREATE XML INDEX IXML_ShopDevices_Path 
       2:             ON dbo.Shop (Devices)   
       3:             USING XML INDEX PXML_ShopDevices 
       4:             FOR [MODE];
Параметр [MODE] может принимать следующие значения:
  • PATH – используется для оптимизации производительности, когда в XML запросе учувствуют длинные (глубокие) XML структуры, либо если в запросе присутствует фильтрация по атрибутам, например: «device[@vendor="HTC"]» ;
  • PROPERTY – оптимизирует производительность в том случае, если запрос возвращает большое количество атрибутов XML элементов;
  • VALUE – используется, когда в запросе идет доступ к данным элемента или когда применяется фильтр на основе шаблона, например: «device[@*="HTC"]».
В зависимости, от специфики ваших запросов, выбор нужного режима для индекса может существенно оптимизировать скорость их выполнения.
В данной статье мы познакомились с набором команд, предназначенных для модификации XML данных в среде Microsoft SQL Server 2008. А также, научились правильно составлять запросы для добавления, удаления и модификации данных. Были кратко рассмотрены вопросы оптимизации производительности при работе с типом данных XML.

3 комментария: