在xml列中查询优化

时间:2011-08-12 15:10:21

标签: sql xml

我们有一个包含text数据类型的xml数据的列。我的查询有大约10个连接。我想优化查询。以下是案例陈述。有没有更好的方法来查询xml节点,以便我们可以提高该查询的性能?

假设表名是XYZ。使用SQL Server 2005/2008

CASE 
   WHEN CONVERT(xml,CAST(XYX as nvarchar(MAX))).value('count(//CurrentStudents)','nvarchar(max)')=1 
      THEN 'All Students'
   WHEN CONVERT(xml,CAST(XYZ as nvarchar(MAX))).value('count(//CurrentStudents/Value)','nvarchar(max)') = 0 AND CONVERT(xml, CAST(XYZ as nvarchar(MAX))).value('(//previousStudent/Value/text())[1]','nvarchar(max)') LIKE '%Studied Before%' OR CONVERT(xml,CAST(XYZ as nvarchar(MAX))).value('(//previousStudent/Value/text())[1]','nvarchar(max)') LIKE '%Studied Before but transferred%' OR CONVERT(xml,CAST(XYZ as nvarchar(MAX))).value('(//previousStudent/Value/text())[1]','nvarchar(max)') LIKE '%Have taken admission but didnt study%' 
      THEN 'Some Students'
   WHEN CONVERT(xml,CAST(XYZ as nvarchar(MAX))).value('count(//CurrentStudents/Value)', 'nvarchar(max)') = 0 AND CONVERT(xml, CAST(XYZ as nvarchar(MAX))).value('count(//CurrentStudents)','nvarchar(max)') = 0 AND CONVERT(xml,CAST(XYZ as nvarchar(MAX))).value('count(//previousStudent)','nvarchar(max)') = 0 
      THEN 'No Students'
   ELSE
      'Bla Bla'
END

还有如何在此查询中添加DISTINCT。当我尝试它时会抛出错误,说xml数据不能用作不同的。

2 个答案:

答案 0 :(得分:1)

  

有没有更好的方法来查询xml节点,以便我们可以提高该查询的性能?

由于您的数据以文本格式存储,因此您应该使用字符串解析函数(例如PATINDEX)而不是xml函数来避免不必要的转换。在罗马的时候......

如果必须使用xml函数,请创建一个子查询以进行一次转换,并多次使用转换后的值。 DRY ...

SELECT sub.myXml.value(....
(
SELECT CONVERT(xml,CAST(XYX as nvarchar(MAX))) myXml
FROM ...
) as sub

答案 1 :(得分:1)

使用distinct获得的错误不在此case语句中。您正在返回XML列的列。

当您执行此.value('count(//CurrentStudents)','nvarchar(max)')之类的计数查询时,您可以使用数据类型int来避免隐式转换为int .value('count(//CurrentStudents)','int')

扩展整个路径而不是使用//更有效。将//CurrentStudents更改为'/ SomeRoot / itemWhatever / CurrentStudents'。如果CurrentStudents的所有节点都位于XML中的相同位置,则这是可行的。

您要多次查询相同的值。使用cross apply可以避免这种情况。您还可以使用cross apply来避免多次将文本列转换为XML。像这样的东西。

declare @T table(XMLCol text)

insert into @T values ('<root><i></i><i></i><i></i></root>')

select R.N
from @T
  cross apply (select cast(cast(XMLCol as varchar(max)) as xml)) as X(Col)
  cross apply (select X.Col.query('count(/root/i)').value('.', 'int')) as R(N)

如果您可以将表更改为保留XML列,那也会更好。这对性能和一致性都有好处。没有列中无效XML的风险。