当条件包含 IS NULL OR LEN(@localvariable) 时,SQL 非常慢
Posted
技术标签:
【中文标题】当条件包含 IS NULL OR LEN(@localvariable) 时,SQL 非常慢【英文标题】:SQL very slow when where condition contains IS NULL OR LEN(@localvariable) 【发布时间】:2021-10-08 23:45:31 【问题描述】:当我在where
条件中包含以下行时,我的查询要慢得多:
-- @locCandidates IS NULL OR LEN(@locCandidates) = 0
我将订单号(可选)和候选人姓名(可选)作为过滤器传递。
可以用逗号分隔多个候选人的姓名搜索。
谁能指出性能缓慢的原因,我还能怎么写我的最终选择?
这里是 SQL:
DECLARE @Candidates NVARCHAR(MAX) = 'ann'
DECLARE @locCandidates NVARCHAR(max) = @Candidates
create table #Temp
(
CandidateName Varchar(50)
)
DECLARE @candidateFiltered AS TABLE(Id INT);
IF @locCandidates IS NOT NULL AND LEN(@locCandidates) > 0
BEGIN
Insert Into #Temp SELECT * FROM dbo.fn_Split(@locCandidates, ',')
Insert into @candidateFiltered
SELECT w.Id FROM dbo.Workers w, #Temp WHERE CONCAT(LOWER(w.FirstName), ' ', LOWER(w.LastName)) LIKE CONCAT('%',LOWER(CandidateName),'%');
If(OBJECT_ID('tempdb..#temp') Is Not Null)
Begin
Drop Table #Temp
End
END
SELECT oc.OrderId
FROM dbo.Orders o
INNER JOIN dbo.OrderCandidates oc ON oc.OrderId = o.Id
WHERE oc.WorkerId IN (SELECT [Id] FROM @candidateFiltered)
OR (@locCandidates IS NULL OR LEN(@locCandidates) = 0 )--Alternative to this??
【问题讨论】:
像您突出显示的那样进行标量比较很快。您确定 if 语句控制的不是 CTE 吗?考虑将 fn_split 的结果放入临时表中。 visualstudiomagazine.com/articles/2015/04/01/… Bad habits to kick : using old-style JOINs - 旧式 逗号分隔的表格列表 样式已替换为 ANSI 中的 proper ANSIJOIN
语法-92 SQL 标准(差不多 30 年前),不鼓励使用它
由于@LocCandidates
是固定的并且您已经在测试它,您可以添加一个else
并在每个if
分支中有两个版本的查询,并且不需要在@LocCandidates
内联测试全部。
OR
通常会很慢...试试LEN(COALESCE(@locCandidates,'')) = 0
本文详细解释:sqlservercentral.com/blogs/revisiting-catch-all-queries
【参考方案1】:
@locCandidates 是一个文本字段。文本操作成本很高。如果您拥有的二维连接有很多记录,例如 100 000 000,那么无论评估 LEN 操作的成本是多少,例如,它都会执行 100 000 000 次。假设它需要 0.000001 秒。然后需要0.000001 * 100000000秒,也就是100秒,一分钟多。取而代之的是,您可以使用 if-else 条件,因此这种循环评估只执行一次,而不是 100 000 000 次左右。
【讨论】:
您还可以预先计算条件并将逻辑结果添加到更适合您的查询中。 你是这个意思吗? @Anna 抱歉,我不明白这个问题。你能详细说明一下吗?【参考方案2】:您可以在 WHERE
子句中使用 IF 语句代替 OR
:
IF @locCandidates IS NULL OR LEN(@locCandidates) = 0
BEGIN
SELECT oc.OrderId
FROM dbo.Orders o
INNER JOIN dbo.OrderCandidates oc ON oc.OrderId = o.Id
END
ELSE
BEGIN
SELECT oc.OrderId
FROM dbo.Orders o
INNER JOIN dbo.OrderCandidates oc ON oc.OrderId = o.Id
WHERE oc.WorkerId IN (SELECT [Id] FROM @candidateFiltered)
END
【讨论】:
这个答案和我的有什么不同?以上是关于当条件包含 IS NULL OR LEN(@localvariable) 时,SQL 非常慢的主要内容,如果未能解决你的问题,请参考以下文章
DataFrame 列(数组类型)包含 Null 值和空数组(len =0)。如何将 Null 转换为空数组?