在大量拆分结果上进行SQL连接时性能下降

时间:2011-09-01 14:20:15

标签: sql performance tsql join

我有大约30个字符串被传递给我的存储过程,它充当我需要操作的表的列。每个字符串都是分隔的,我使用split函数将这些字符串中的每一个分成适当的行,这些行通常由20行或更少的行组成。 split函数非常快并返回一个表结果,其中一列是一个ID,它是一个主键,另一列是拆分值,从检查执行计划开始,三十个拆分只占用了我的一小部分时间。似乎会破坏我的表现的部分是这三十个分割结果集中的实际连接。

DECLARE @WorkingTab TABLE ([ID] INT PRIMARY KEY, [Col1] VARCHAR(255), [Col2] VARCHAR(255), ...)

INSERT INTO @WorkingTab ([ID], [Col1], [Col2], ...)
SELECT
    splitStr1.ID,
    splitStr1.VALUE,
    splitStr2.VALUE,
    .
    .
    .
FROM
    dbo.Split(@Str1, '~') splitStr1
    LEFT JOIN
        dbo.Split(@Str2, '~') splitStr2
    ON splitStr1.ID = splitStr2.ID
    LEFT JOIN
        dbo.Split(@Str3, '~') splitStr3
    .
    .
    .

我尝试过使用内连接而不是左连接,这会略微降低性能。我尝试将第一个拆分结果插入到索引临时表中,然后将其余的列值更新到临时表中的相应列中,这再次导致性能下降。我已经尝试将所有结果插入到持久表中,这也没有提高性能。如果有人对其他方法有任何建议或只是一般的性能提示,我会全力以赴。提前谢谢。

2 个答案:

答案 0 :(得分:1)

这在性能方面确实不是一个好策略。用户定义的函数永远不会是高性能的。您是否考虑过将数据作为XML文档提交并在存储过程中解析?我以前做过这件事,而且通常是一个不错的表演者。

关于您的实际问题,可能有一些优化表值函数的能力,以便它返回一个定义了主键的表变量,这可以提高性能,但实际上,我建议您更改上传策略。< / p>

答案 1 :(得分:0)

对于30个表变量,连接效率非常低,因为它必须为每个连接扫描每个变量。您需要将其运行到更像O(N)或O(N log N)的操作 - 实际上,我认为这意味着将所有输出排序并识别为由查询优化器排序。我想不出一种简单,干净,紧凑的方法。但是,以下方法之一可能有效:

  • 将每个拆分函数的输出加载到一组临时表中,并为每个表的ID创建聚簇索引。这可能会获得一个合理有效的合并连接计划,并且聚集索引构建将是O(N log N),并且具有有效的O(N)合并连接操作。

  • 按照ID的顺序打开每个表上的游标,并在程序上循环遍历它们(即每次循环迭代从每个游标中获取一行)。如果函数输出的行数相当小,则可能不会太昂贵。游标ops会有些昂贵,但查询实际上是O(N log N),循环操作是O(N)。

更好的计划可能是在程序上完成整个过程(即避免表值拆分函数)。如果字符串可以在获取它们时按ID排序(或者可能作为初步步骤),您可以使用字符串操作完成所有操作。从每个字符串中剥离第一个记录并存储字符串的尾部以供下一次迭代。