我有一个表[MyTable],列[MyColumn] NVarchar(50)。我在此列上有一个非聚集索引,现在运行以下两个查询:
SELECT 1
FROM [MyTable] M
WHERE M.[MyColumn] = @MyColumn
SELECT 1
FROM [MyTable] M
WHERE M.[MyColumn] = COALESCE(@MyColumn, M.[MyColumn] )
我注意到第一个查询是使用 Index Seek(NonClustered),第二个查询是使用 Index Scan(Non Clustered)。我可以知道如何利用coalesce或isnull来使用索引搜索?
答案 0 :(得分:2)
我可以知道如何使用 索引寻求与coalesce或isnull?
也许不是您问题的答案,但您可以有两个不同的查询。一个用于@MyColumn is null
的情况和一个用于在where子句中使用@MyColumn
的情况。
IF @MyColumn IS NULL
BEGIN
SELECT 1
FROM [MyTable] M
END
ELSE
BEGIN
SELECT 1
FROM [MyTable] M
WHERE M.[MyColumn] = @MyColumn
END
答案 1 :(得分:0)
在where子句中使用COALESCE
或ISNULL
等函数要求服务器搜索这些函数的结果 - 这些函数在每次执行之前都是未知的结果集中的行,因此无法使用索引。
要充分利用索引,请不要使用WHERE子句中的函数,使用标准条件进行修改,例如: WHERE MyColumn = @MyColumn OR @MyColumn IS NULL
答案 2 :(得分:0)
这并不容易,因为Alex指出使用函数强制扫描,因为优化器知道它需要检查每一行。
您可以为Computed Column功能的结果and index that column创建{{3}}。
没有更好的方式来寻求。
修改强>
在重新阅读您的问题时,除非您重新考虑您的逻辑,否则这可能不是您的选择。您正在将一个变量集成到该函数中,并且绝对没有办法将其编入索引。
编辑2:
而不是当前的逻辑,尝试类似:
...
WHERE (M.[MyColumn] = @MyColumn
OR @MyColumn IS NULL)
答案 3 :(得分:0)
我猜您会在更复杂的问题中使用此查询,可能使用EXISTS
:
EXISTS
( SELECT 1
FROM [MyTable] M
WHERE M.[MyColumn] = COALESCE(@MyColumn, M.[MyColumn] )
)
请改为尝试:
EXISTS
( SELECT 1
FROM [MyTable] M
WHERE M.[MyColumn] = @MyColumn
)
OR EXISTS
( SELECT 1
FROM [MyTable] M
WHERE @MyColumn IS NULL
)
或者这个:
CASE WHEN @MyColumn IS NULL
THEN 1
ELSE
( SELECT 1
FROM [MyTable] M
WHERE M.[MyColumn] = @MyColumn
)
END
答案 4 :(得分:0)
在带有coalesce子句的查询中,优化器知道“MyColumn”是一系列值,因此它将决定对索引使用扫描。传入非null变量时使用搜索的唯一方法是编写两个存储过程,并通过变量的逻辑测试调用适当的过程。
如果您的情况与示例一样简单,并且您希望在变量为NOT NULL时使用Index Seek,则应将查询编码为:
If @MyColumn is NULL
Begin
EXEC MyStoredProcWithMyColumn=Mycolumn
END
ELSE
Begin
EXEC MyStoredProcWithMyColumn=Variable @MyColumn
END
创建两个存储过程之后,使用带有变量的where子句返回数据,使用where cluase返回数据等于自身。