如何使带有多值参数的查询运行得更快?

时间:2018-08-21 19:25:04

标签: sql-server optimization ssrs-2008

我的以下查询运行得很慢:

SELECT 
    DISTINCT a.Role as Role
FROM 
    [Table_A] a 
JOIN 
    [Table_B] b ON (a.Key = b.Key)
WHERE 
    b.Date BETWEEN @StartDate AND @EndDate
    AND ISNULL(a.ID, -1) IN (@People)

变量@StartDate@EndDate@People的值来自SSRS报告中的参数。日期参数只是日期。 @People参数是一个多值参数。

问题是@People包含3000多个值。因此,查询必须使用IN子句来遍历。在SSRS中运行查询时,这确实会减慢查询速度。

我想用一个现存子句代替IN子句,但在这种情况下我似乎无法使它起作用。我需要以某种方式从@People子句中的EXISTS变量中选择值,并将其重新连接到第一个表,但是我什至不知道这是否可行。

在这种情况下,尝试使用EXISTS可能使我走错了方向。但是我仍然需要修复查询,以便它运行得更快。

任何人都可以帮忙吗?

1 个答案:

答案 0 :(得分:1)

select r.acctnbr, r.modnbr, r.modtypcd, r.moddate, u.userfieldcd, case when modnbr = max(r.modnbr ) over (partition by r.acctnbr) then u.value else null end as value from loanrestructuretracking r LEFT JOIN acctuserfield u on u.acctnbr = r.acctnbr and u.userfieldcd = 'LOMO' 将使查询不可SARG。您最好使用ISNULL(a.ID, -1),但是,带有这么多参数的(a.ID IN (@People) OR a.ID IS NULL)不太可能很好地运行。

我在这里运行内存(我在家中没有SSRS),但是如果我记得SSRS使用多值参数和IN做一些“魔术”,那么扩展性就不好。也许您最好尝试使用IN和分隔符(例如DelimitedSplit8k)。此特定示例依赖于EXISTS少于8000个字符。

@People

但是,考虑到这里的顺序位置无关紧要,则可以使用其他拆分器。例如XML Splitter

为完整起见,快速编写了XML Splitter函数:

SELECT DISTINCT a.Role
FROM [Table_A] a 
     JOIN [Table_B] b ON a.Key = b.Key
WHERE b.Date BETWEEN @StartDate AND @EndDate
  AND (EXISTS (SELECT 1
               FROM dbo.DelimitedSplit8K(@People,',') DS
               WHERE DS.Item = a.ID)
   OR  a.ID IS NULL);

添加了不带功能的完整示例:

CREATE FUNCTION dbo.XMLSplitter (@DelimitedString varchar(MAX))
RETURNS TABLE AS RETURN

    SELECT n.d.value('.','varchar(MAX)') AS Item
    FROM (VALUES(CONVERT(xml,'<d>'+ REPLACE(@DelimitedString,',','</d><d>') + '</d>'))) V(X)
         CROSS APPLY V.X.nodes('d') n(d);

GO