Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

A consulta xml de aplicação cruzada tem um desempenho exponencialmente pior à medida que o documento xml cresce


O que faz com que a consulta de aplicação cruzada tenha um desempenho tão ruim nesse documento XML simples e um desempenho exponencialmente mais lento à medida que o conjunto de dados cresce?

É o uso do eixo pai para obter o ID do atributo do nó do item.

É essa parte do plano de consulta que é problemática.



Observe as 423 linhas que saem da função com valor de tabela inferior.

Adicionar apenas mais um nó de item com três nós de campo fornece isso.



732 linhas retornadas.

E se dobrarmos os nós da primeira consulta para um total de 6 nós de itens?



Estamos até uma enorme linha 1602 retornada.

A figura 18 na função superior são todos os nós de campo em seu XML. Temos aqui 6 itens com três campos em cada item. Esses 18 nós são usados ​​em uma junção de loops aninhados com a outra função, de modo que 18 execuções retornando 1602 linhas fornecem 89 linhas por iteração. Esse é o número exato de nós em todo o XML. Bem, na verdade é um a mais do que todos os nós visíveis. Eu não sei por quê. Você pode usar essa consulta para verificar o número total de nós em seu XML.
select count(*)
from @XML.nodes('//*, //@*, //*/text()') as T(X)  

Portanto, o algoritmo usado pelo SQL Server para obter o valor quando você usa o eixo pai .. em uma função de valores é que ela primeiro encontra todos os nós nos quais você está destruindo, 18 no último caso. Para cada um desses nós, ele fragmenta e retorna todo o documento XML e verifica no operador de filtro o nó que você realmente deseja. Aí você tem o seu crescimento exponencial. Em vez de usar o eixo pai, você deve usar uma aplicação cruzada extra. Primeiro triturar no item e depois no campo.
select I.X.value('@name', 'varchar(5)') as item_name,
       F.X.value('@id', 'uniqueidentifier') as field_id,
       F.X.value('@type', 'int') as field_type,
       F.X.value('text()[1]', 'nvarchar(15)') as field_value
from #temp as T
  cross apply T.x.nodes('/data/item') as I(X)
  cross apply I.X.nodes('field') as F(X)

Também alterei como você acessa o valor de texto do campo. Usando . fará com que o SQL Server procure por nós filhos no field e concatenar esses valores no resultado. Você não tem valores filho, então o resultado é o mesmo, mas é bom evitar ter essa parte no plano de consulta (o operador UDX).

O plano de consulta não tem o problema com o eixo pai se você estiver usando um índice XML, mas ainda se beneficiará alterando a forma como busca o valor do campo.