Сглаживание иерархического XML в SQL с помощью метода node () - PullRequest
5 голосов
/ 27 апреля 2011

У меня есть хранимая процедура, которая принимает XML-документ в качестве параметра, похожего по структуре на следующее:

<grandparent name="grandpa bob">
  <parent name="papa john">
    <children>
      <child name="mark" />
      <child name="cindy" />
    </children>
  </parent>
  <parent name="papa henry">
    <children>
      <child name="mary" />
    </children>
  </parent>
</grandparent>

Мое требование состоит в том, чтобы "сгладить" эти данные, чтобы их можно было вставить во временную таблицу и манипулировать ими далее в процессе, так что приведенный выше XML становится:

Grandparent Name Parent Name     Child Name
---------------- --------------- ---------------
grandpa bob      papa john       mark
grandpa bob      papa john       cindy
grandpa bob      papa henry      mary

В настоящее время это выполняется с использованием узлов SQL Server XML:

SELECT
    VIRT.node.value('../../../@name','varchar(15)') 'Grandparent Name',
    VIRT.node.value('../../@name','varchar(15)') 'Parent Name',
    VIRT.node.value('@name','varchar(15)') 'Child Name'
FROM
    @xmlFamilyTree.nodes('/grandparent/parent/children/child') AS VIRT(node)

Это прекрасно работает до тех пор, пока я не начну выбрасывать большие объемы данных в процедуру (то есть 1000+ child узлов), после чего это останавливается и занимает от 1 до 2 минут. Я думаю, это может быть связано с тем, что я начинаю с самого низкого уровня (<child), а затем перебираю обратно документ XML для каждого случая. Будет ли разделение этого единственного запроса на 3 блока (по одному на узел, с которого мне нужны данные) повысить производительность? Учитывая, что ни на одном из этих узлов нет «ключей», которые я мог бы использовать для подключения, не мог бы кто-нибудь предложить какие-либо указатели, как я мог бы сделать это?

1 Ответ

7 голосов
/ 27 апреля 2011

Я, кажется, уже ответил на свой вопрос, немного посмотрев в Интернете:

SELECT
    grandparent.gname.value('@name', 'VARCHAR(15)'),
    parent.pname.value('@name', 'VARCHAR(15)'),
    child.cname.value('@name', 'VARCHAR(15)')
FROM
    @xmlFamilyTree.nodes('/grandparent') AS grandparent(gname)
CROSS APPLY
    grandparent.gname.nodes('*') AS parent(pname)
CROSS APPLY
    parent.pname.nodes('children/*') AS child(cname)

Используя CROSS APPLY Я могу выбрать узел верхнего уровня grandparent и использовать его для выбора дочерних узлов parent и так далее. Используя этот метод, я взял запрос от выполнения за 1 минуту 30 секунд до 6 секунд .

Интересно, что если я использую «старый» метод OPEN XML для извлечения тех же данных, запрос выполняется за 1 секунду !

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...