优化SQL函数

时间:2018-01-24 16:53:59

标签: sql-server optimization

我试图优化或完全重写此查询。目前运行大约需要1500毫秒。我知道不同的联盟和联盟一样效率很低。但我正在努力弄清楚从这里到底要去哪里。

我认为可能不需要第一个select语句来返回;

的输出
[Key | User_ID,(User_ID)]

请注意;程序和程序方案都使用聚簇索引。如果需要,我可以提供执行计划的屏幕截图。

ALTER FUNCTION [dbo].[Fn_Get_Del_User_ID] (@_CompKey INT)

RETURNS VARCHAR(8000)

AS

BEGIN

    DECLARE @UseID AS VARCHAR(8000);

    SET @UseID = '';

    SELECT @UseID = @UseID + ', ' + x.User_ID
    FROM 
        (SELECT DISTINCT (UPPER(p.User_ID)) as User_ID FROM  [dbo].[Program] AS p WITH (NOLOCK) 
        WHERE p.CompKey = @_CompKey
        UNION
        SELECT DISTINCT (UPPER(ps.User_ID)) as User_ID FROM  [dbo].[Program] AS p WITH (NOLOCK) 
        LEFT OUTER JOIN [dbo].[Program_Scenario] AS ps WITH (NOLOCK) ON p.ProgKey = ps.ProgKey
        WHERE p.CompKey = @_CompKey
        AND ps.User_ID IS NOT NULL) x 

    RETURN Substring(@UserIDs, 3, 8000);
END

2 个答案:

答案 0 :(得分:3)

此查询中发生了两件事

1.在[Program]表中查找与指定的CompKey(@_CompKey)匹配的行

2.在[Program_Scenario]表中查找与上面(1)中的行具有相同ProgKey的行。

最后,来自这两组行的非空UserID被连接成一个标量。

要使第1步有效,您需要CompKey列上的索引(群集或非群集) 为了使第2步有效,你需要一个关于连接键的索引,它是Program_Scenario表上的ProgKey(这可能是一个非聚集索引,因为我无法想象ProgKey是PK)。可能,SQL将采用循环连接策略 - 即,对于匹配CompKey标准的[Program]中找到的每一行,它需要使用相同的ProgKey在[Program_Scenario]中查找相应的行。但这是一个猜测,因为没有足够的关于基数和数据分布的信息。

确保存在上述两个索引。

另外,正如其他人所指出的那样,第二个左外连接有点混乱,因为内连接是处理它的正确方法。

根据我的解释,查询的内部部分可以通过这种方式重写。此外,这是您在添加字符串连接部分之前理想地运行和优化的查询。 DISTINCT被删除,因为它是UNION自动的。尝试此版本的查询以及上面的索引,如果它提供必要的提升,则包括字符串连接或xml STUFF方法以返回标量。

SELECT UPPER(p.User_ID) as User_ID 
FROM 
   [dbo].[Program] AS p WITH (NOLOCK) 
WHERE
   p.CompKey = @_CompKey
UNION
SELECT UPPER(ps.User_ID) as User_ID 
FROM  
   [dbo].[Program] AS p WITH (NOLOCK) 
   INNER JOIN [dbo].[Program_Scenario] AS ps WITH (NOLOCK) ON p.ProgKey = ps.ProgKey
WHERE 
    p.CompKey = @_CompKey
    AND ps.User_ID IS NOT NULL

答案 1 :(得分:1)

我在黑暗中拍摄。我猜你发布的最后一个代码仍然是一个标量函数。它也没有原始查询的所有逻辑。同样,这是一个黑暗中的镜头,因为没有发布表格定义或样本数据。

这可能就像内联表值函数一样。

ALTER FUNCTION [dbo].[Fn_Get_Del_User_ID] 
(
    @_CompKey INT
) RETURNS TABLE AS RETURN
    select MyResult = STUFF(
    (
        SELECT distinct UPPER(p.User_ID) as User_ID 
        FROM dbo.Program AS p 
        WHERE p.CompKey = @_CompKey
        group by p.User_ID

        UNION

        SELECT distinct UPPER(ps.User_ID) as User_ID 
        FROM dbo.Program AS p 
        LEFT OUTER JOIN dbo.Program_Scenario AS ps ON p.ProgKey = ps.ProgKey
        WHERE p.CompKey = @_CompKey
            AND ps.User_ID IS NOT NULL
        for xml path ('')
    ), 1, 1, '') 
    from dbo.Program