不确定从哪里开始 - 不确定问题是我是在欺骗查询优化器,还是在涉及空值时索引的工作方式是内在的.
我遵循的一个编码约定是编写这样的存储过程:
declare procedure SomeProc
@ID int = null
as
select
st.ID,st.Col1,st.Col2
from
SomeTable st
where
(st.ID = @ID or @ID is null) --works, but very slow (relatively)
Run Code Online (Sandbox Code Playgroud)
当然,在这个简单的测试用例中不是很有用,但是当您希望存储过程对整个表或符合某些条件的行进行操作时,在其他情况下非常有用.但是,当在较大的表上使用时,这是非常慢的...比我用以下内容替换where子句大约慢3-5倍:
where
st.ID = @ID --3-5x faster than first example
Run Code Online (Sandbox Code Playgroud)
我更加困惑的是,用-1替换null使我的速度几乎与上面的"修复"WHERE子句相同:
declare procedure SomeProc
@ID int = -1
as
select
st.ID,st.Col1,st.Col2
from
SomeTable st
where
(st.ID = @ID or @ID=-1) --much better... but why?
Run Code Online (Sandbox Code Playgroud)
很明显,这是无效的,这使得事情变得古怪,但为什么呢?通过检查执行计划,我不清楚答案.这是我多年来在SQL Server的各种数据库,表格和版本上注意到的,所以我认为这不是我当前环境的怪癖. 我已经通过将默认参数值从null切换到-1来解决了这个问题.我的问题是为什么这样做.
笔记
最有可能的是问题的组合
但是,如果没有看到计划,这些都是有根据的猜测.
参数嗅探
...的默认值为"NULL".尝试使用不同的默认值,例如-1或无默认值.
@ID = -1,默认值为NULL,参数sniffing =普通检查,因此速度更快.
您还可以在SQL Server 2008中尝试OPTIMIZE FOR UNKNOWN
OR运算符
一些想法......
如果列不可为空,则在大多数情况下,优化程序会忽略该条件
st.ID = ISNULL(@ID, st.ID)
Run Code Online (Sandbox Code Playgroud)
此外,您可以使用IF语句
IF @ID IS NULL
SELECT ... FROM...
ELSE
SELECT ... FROM... WHERE st.ID
Run Code Online (Sandbox Code Playgroud)
或UNION ALL以类似的方式.
就个人而言,我在大多数情况下都会使用参数屏蔽(总是)和ISNULL(我先试试)
alter procedure SomeProc
@ID int = NULL
AS
declare @maskID int
select @maskID = @ID
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1670 次 |
| 最近记录: |