我试图优化或完全重写此查询。目前运行大约需要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
答案 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