如何更快地使用多值参数 运行 进行查询?

How to make query with multi value parameter run faster?

我有以下查询 运行 非常慢:

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 中查询时,这真的、真的减慢了我的查询速度。

我想使用 exists 子句来替换 IN 子句,但我似乎无法在这种情况下使用它。我需要以某种方式 select EXISTS 子句中 @People 变量的值并将其连接回第一个 table,但我什至不知道是否这是可能的。

也许我在这种情况下尝试使用 EXISTS 时走错了方向。但我仍然需要修复查询以使其运行得更快。

有人可以帮忙吗?

ISNULL(a.ID, -1) 将使查询不可 SARGable。您最好使用 (a.ID IN (@People) OR a.ID IS NULL),但是,带有那么多参数的 IN 不太可能 运行 好。

我运行记忆在这里(我家里没有SSRS)但是如果我记得SSRS做了一些"magic"多值参数和IN没有很好地扩展。也许您最好尝试使用 EXISTS 和拆分器(例如 DelimitedSplit8k)。此具体示例依赖于 @People 少于 8000 个字符。

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);

然而,考虑到这里的序数位置并不重要,那么可以使用其他分离器。例如 XML Splitter.

为了完整起见,快速编写了一个 XML 拆分器函数:

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

添加了没有函数的完整示例:

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 (VALUES(CONVERT(xml,'<d>'+ REPLACE(@DelimitedString,',','</d><d>') + '</d>'))) V(X)
                       CROSS APPLY V.X.nodes('d') n(d)
                 WHERE n.d.value('.','varchar(MAX)') = a.ID)
    OR  a.ID IS NULL);