【问题标题】:How to optimise the 'XQuery' SQL如何优化“XQuery”SQL
【发布时间】:2011-08-15 11:04:13
【问题描述】:

我在一个有 10,000 条记录的表的 XML 类型列中有一个这样的 XML 层次结构-

<Root>
     <Elem1>
         <Parent1>
              <Separator>
                  <Child1/>
              </Separator>
         </Parent1>
     </Elem1>
</Root>

我有一个这样的查询 -

DECLARE @Root VARCHAR(50)
DECLARE @Entity VARCHAR(50)
DECLARE @ParentNode VARCHAR(50)
DECLARE @Separator VARCHAR(50)
DECLARE @ChildNode VARCHAR(50)


SET @Root = 'Root'
SET @Entity = 'Elem1'
SET @ParentNode = 'Parent1'
SET @Separator = 'separator'
SET @ChildNode = 'Child1'

select Parent.P.value('.', 'varchar(max)') as MyValue, 
T.uniqueId, T.XMLCol
from [XMLTable] as T
cross apply 
 (SELECT
         XMLTable.XMLCol.query('(/*[local-name()=sql:variable("@Root")]/*[local-name(.)=sql:variable("@Entity")]/*[local-name(.)=sql:variable("@ParentNode")]/*[local-name(.)=sql:variable("@Separator")]/*[local-name(.)=sql:variable("@ChildNode")])[1]'
 )  as Parent(P)

如何进一步优化此查询。目前,它需要 2 秒,如果我做进一步的 INNER JOINS,它会增加时间。我尝试在 XML 列上创建 PRIMARY 索引,但这需要更多时间!

编辑——如果我硬编码路径而不是使用变量,那么它只需要不到一秒钟的时间。但是,我希望它在表值函数中并且不能硬编码路径?


编辑 - 解决方案

select x.value('(Parent1/Separator1/Child1)[1]', 'varchar(max)') as Col1,
x.value('(Parent2/Separator2/Child2)[1]', 'varchar(max)') as Col2,
x.value('(Parent3)[1]', 'varchar(max)') as Col3
from [XMLTable] T 
cross apply T.XMLCOL.nodes('/Root/Elem1') a(x)

上述查询只需要 一秒。它似乎是最快的。因此,可以使用ADO.NET 功能动态准备和执行上述查询,而不是使用带有参数的表值函数

请纠正我...?

【问题讨论】:

    标签: sql-server sql-server-2008 query-optimization sql-server-2008-r2 xquery-sql


    【解决方案1】:

    如果您只想要每一行中的一个值,则无需使用cross apply

    select XMLCol.value('(/*[local-name()=sql:variable("@Root")]
                          /*[local-name(.)=sql:variable("@Entity")]
                          /*[local-name(.)=sql:variable("@ParentNode")]
                          /*[local-name(.)=sql:variable("@Separator")]
                          /*[local-name(.)=sql:variable("@ChildNode")])[1]', 'varchar(max)')
    from XMLTable
    

    另一种方法是使用FLWOR。在我有限的测试中,这会运行得更快一些。

    select XMLCol.value('(for $n1 in /*,
                              $n2 in $n1/*,
                              $n3 in $n2/*,
                              $n4 in $n3/*,
                              $n5 in $n4/*
                          where $n1[local-name(.) = sql:variable("@Root")] and
                                $n2[local-name(.) = sql:variable("@Entity")] and
                                $n3[local-name(.) = sql:variable("@ParentNode")] and
                                $n4[local-name(.) = sql:variable("@Separator")] and
                                $n5[local-name(.) = sql:variable("@ChildNode")]
                          return $n5
                         )[1]', 'varchar(max)')
    from XMLTable
    

    【讨论】:

    • 使用 FLOWR 有 2 秒的增益。感谢那。不过,我需要把它弄下来。很快,将发布更新。
    • @SeeSharp - 当然。我认为这没有错。如果您可以动态构建查询,它将比使用 local-name() 搜索 XML 更快。
    • 谢谢米凯尔。你的建议真的很摇滚!学到了很多。感谢您为社区做出这样的贡献。
    猜你喜欢
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2014-01-07
    • 2019-09-28
    • 2023-03-05
    • 2012-03-04
    • 2018-08-24
    • 1970-01-01
    相关资源
    最近更新 更多