提高SQL查询性能.在这种情况下,UNION vs OR



问题

因此,我在使用这个SQL查询时面临的情况是,运行大约需要12秒,这使得屏幕速度非常慢。

目标

进行必要的更改以提高性能并加快速度。我想用UNION代替Where子句中的OR

SELECT Tool.*, Interview.*
FROM Tool
INNER JOIN Interview ON Interview.Id = Tool.InterviewId
WHERE (Tool.ToolTypeId = @ToolTypeId 
AND Tool.Is_Active = 1
AND Tool.InterviewId = @InterviewId
AND Tool.ToolId = @ToolId
AND Tool.CustomerId = @CustomerId)
OR Tool.Id = (
SELECT TOP 1 SubTool.Id
FROM Tool SubTool
INNER JOIN Interview subInterview ON subInterview.Id = SubTool.ToolId 
WHERE SubTool.ToolTypeId = @ToolTypeId
AND SubTool.Is_Active = 1  
AND SubTool.InterviewId != @InterviewId  
AND SubTool.ToolId = @ToolId
AND subTool.CustomerId = @CustomerId
AND convert(datetime, subTool.DateTime, 120) < @ToolDateTime
ORDER BY subTool.DateTime DESC, subTool.StartDate DESC, 
subTool.EndDate, subTool.Id DESC
)

ORDER BY Tool.StartDate, Tool.Id

注意:我认为在这种情况下不需要实际的查询输出,因为我们正在寻找一些可能影响性能的结构问题。

我建议重新表述查询以消除WHERE子句中的子查询。

如果您在结果集中寻找一行,而不管条件如何,您可以使用:

SELECT TOP (1) Tool.*, Interview.*
FROM Tool JOIN
Interview
ON Interview.Id = Tool.InterviewId
WHERE Tool.ToolTypeId = @ToolTypeId AND
Tool.Is_Active = 1
Tool.ToolId = @ToolId AND
Tool.CustomerId = @CustomerId AND
(Tool.InterviewId = @InterviewId OR
convert(datetime, Tool.DateTime, 120) < @ToolDateTime
)
ORDER BY (CASE WHEN Tool.InterviewId = @InterviewId THEN 1 ELSE 2 END),
Tool.DateTime DESC, sTool.StartDate DESC, Tool.EndDate, Tool.Id DESC;

您的最终ORDER BY表明您期望第一个条件有多行。因此,您可以使用子查询和窗口函数:

SELECT ti.*
FROM (SELECT Tool.*, Interview.*,
COUNT(*) OVER (PARTITION BY (CASE WHEN Tool.InterviewId = @InterviewId THEN 1 ELSE 0 END)) as cnt_interview_match,
ROW_NUMBER() OVER (ORDER BY subTool.DateTime DESC, subTool.StartDate DESC, subTool.EndDate, subTool.Id DESC) as seqnum
FROM Tool JOIN
Interview
ON Interview.Id = Tool.InterviewId
WHERE Tool.ToolTypeId = @ToolTypeId AND
Tool.Is_Active = 1
Tool.ToolId = @ToolId AND
Tool.CustomerId = @CustomerId AND
(Tool.InterviewId = @InterviewId OR
convert(datetime, Tool.DateTime, 120) < @ToolDateTime
)
) ti
WHERE InterviewId = @InterviewId OR
(cnt_interview_match = 0 AND seqnum = 1);

请注意,子查询要求列具有不同的名称,因此您可能需要对此进行处理。

然后,您需要TOOL(ToolTypeId, Is_Active, ToolId, CustomerId, InterviewId, DateTime)上的索引。我假设Interview(Id)已经被索引为表的主键。

我对查询的作用(以及由此推断出的您希望它做什么)的解释与@GordonLinoff的不同。


Gordon的查询可以解释为…

  • 如果有Tool.InterviewId = @InterviewId的行。。。
    • 只返回那些行
  • 如果没有这样的行可返回。。。
    • 返回其他InterviewId的最新一行

我对查询的实际作用的理解是,您希望始终同时返回这两种可能性。

  • 这个模糊性是为什么真的应该包括示例数据的一个例子

例如,这将是一个重新措辞或您现有的查询(根据您自己的建议使用UNION)。。。

WITH
filter_tool_customer AS
(
SELECT Tool.*, Interview.*
FROM Tool
INNER JOIN Interview ON Interview.Id = Tool.InterviewId
WHERE Tool.ToolTypeId = @ToolTypeId 
AND Tool.Is_Active  = 1
AND Tool.ToolId     = @ToolId
AND Tool.CustomerId = @CustomerId
),
matched AS
(
SELECT *
FROM filter_tool_customer
WHERE InterviewId = @InterviewId
),
mismatched AS
(
SELECT TOP 1 *
FROM filter_tool_customer
WHERE InterviewId <> @InterviewId
AND DateTime    <  CONVERT(VARCHAR(20), @ToolDateTime, 120)
ORDER BY DateTime DESC,
StartDate DESC,
EndDate,
Id DESC
),
combined AS
(
SELECT * FROM matched
UNION ALL
SELECT * FROM mismatched
)
SELECT * FROM combined ORDER BY StartDate, Id

最新更新