在 SQL Server 2008 中使用 FOR XML PATH 提高 SQL 查询的性能

Posted

技术标签:

【中文标题】在 SQL Server 2008 中使用 FOR XML PATH 提高 SQL 查询的性能【英文标题】:Improve performance of SQL query with a FOR XML PATH in SQL Server 2008 【发布时间】:2018-04-17 01:28:34 【问题描述】:

我正在尝试使用 For XML 路径为用户连接 LoadIds,这是我整个查询的一部分,我验证了在计算这个连接的 LoadId 列时已经过最长时间。下面是语法,有人可以建议一种有效地重写它的方法吗?

SELECT 
    Col1, col2, 
    LoadIds = STUFF((SELECT ' , ' + CAST([LoadId] AS varchar(5))
                     FROM Table1 AS t1
                     WHERE t1.[UserId] = [t2].[UserId]
                     FOR XML PATH ('')), 1, 2, '')
FROM 
    Table1 AS t2
GROUP BY 
    [UserId]

【问题讨论】:

性能对您来说到底是什么问题?这看起来像是 SQL Server 中一个非常典型的 FOR XML PATH 查询。你有UserId 的索引吗? @TimBiegeleisen 如果我评论 LoadIds 的计算,查询的性能在 20 秒内,而使用 LoadIds 最多可以达到一分钟。我没有关于 UserId 的索引,也没有创建权限 @Naina... 发布的查询中有错字吗?因为我在group by 子句中只看到userid,但select 语句没有expression 如果您没有创建索引的权限,这可能对您没有帮助,但有机会使用CLR function。 @Naina,这个对SQL CLR也不错GROUP_CONCAT 【参考方案1】:

1)。我会尝试在临时表或表变量中收集所需的数据,在其上创建索引,然后使用连接。

2)。 FOR XML PATH 适用于小型记录集,对于大型记录集我会尝试递归。

declare @T table (
    UserId     int        not null,
    RowNumber  int        not null,
    LoadId     varchar(5) not null

    primary key clustered (UserId, RowNumber)
);

insert into @T
select
    UserId,
    row_number() over(partition by UserId order by LoadId),
    CAST(LoadId AS varchar(5))    
from
    Table1 ;


with cte (UserId, RowNumber, LoadIds) as 
(
    select 
        UserId, 
        RowNumber,
        LoadIds = convert(varchar(8000), LoadId)
    from @T
    where RowNumber = 1

    union all

    select 
        t.UserId, 
        t.RowNumber,
        convert(varchar(8000), cte.LoadIds + ', ' + t.LoadId)
    from 
        cte inner join @T t on t.UserId = cte.UserId and t.RowNumber = cte.RowNumber + 1
)
select UserId, LoadIds = max(LoadIds) from cte group by UserId;

【讨论】:

也许你应该看看这个,sqlperformance.com/2014/08/t-sql-queries/… 但我听到了相反的意见,也看到了其他结果。这就是为什么我写了“我会尝试......” 我通常会随身携带一些备忘单,例如解决此类问题的常用技术,对于分组连接,最好的方法是 xml(您应该牢记一些注意事项)和 CLR。已故 Dwain 营地的精彩读物在这里High perf T SQL code patterns 即使我尝试了 r-cte 几次,直到我遇到了这个。这就是为什么指出它,现在开始你将密切关注 r-cte :) 对于寻求解决方案的其他人,我发现按照@VadimLoboda 的建议在临时表上创建索引确实加快了我的查询速度【参考方案2】:

您可以做的一件事是在进行字符串聚合之前选择不同的用户ID:

SELECT t2.UserId, 
        STUFF((SELECT ' , ' + CAST([LoadId] AS varchar(8000))
               FROM Table1 t1
               WHERE t1.[UserId] = [t2].[UserId]
               FOR xml PATH ('')
              ), 1, 2, ''
             ) as LoadIds
FROM (SELECT DISTINCT userId
      FROM Table1 t2
     ) t2;

为了提高性能,table1(UserId, LoadId) 上的索引也会有所帮助。

【讨论】:

感谢您的建议,但没有帮助

以上是关于在 SQL Server 2008 中使用 FOR XML PATH 提高 SQL 查询的性能的主要内容,如果未能解决你的问题,请参考以下文章

ORM - 特定于用于 .NET 的 SQL Server 2008+

Eclipse IDE for Java Developers(4.10.0)建立与SQL Server 2008数据库的连接

DbVisualizer 连接 SQL Server 2008配置

在 SQL Server 2008 中使用 PIVOT

在 SQL Server 2008 中使用休眠

Query (SQL Server 2008 Express) 在 SQL Server Management Studio 中有效,但在 Delphi 中使用 ADODB 无效