问题
因此,我在使用这个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