SQL中WHERE变量IS NULL条件导致全表扫描问题的解决方法
程序员文章站
2023-12-04 23:51:04
复制代码 代码如下:set @sql = 'select * from comment with(nolock) where 1=1 a...
复制代码 代码如下:
set @sql = 'select * from comment with(nolock) where 1=1
and (@projectids is null or projectid = @projectids)
and (@scores is null or score =@scores)'
印象中记得,以前在做oracle开发时,这种写法是会导致全表扫描的,用不上索引,不知道sql server里是否也是一样呢,于是做一个简单的测试
1、建立测试用的表结构和索引:
复制代码 代码如下:
create table aaa(id int identity, name varchar(12), age int)
go
create index idx_age on aaa (age)
go
2、插入1万条测试数据:
复制代码 代码如下:
declare @i int;
set @i=0;
while @i<10000
begin
insert into aaa (name, age)values(cast(@i as varchar), @i)
set @i=@i+1;
end
go
3、先开启执行计划显示:
在sql server management studio的查询窗口里,右击窗口任意位置,选择“包含实际的执行计划”:
4、开始测试,用下面的sql进行测试:
复制代码 代码如下:
declare @i int;
set @i=100
select * from aaa where (@i is null or age = @i)
select * from aaa where (age = @i or @i is null)
select * from aaa where age=isnull(@i, age)
select * from aaa where age = @i
测试结果如下:
可以看到,即使@i有值,不管@i is null是放在前面还是放在后面,都无法用到age的索引,另外age=isnull(@i,age)也用不上索引
最终结论,sql server跟oracle一样,如果条件里加了 变量 is null,都会导致全表扫描。
建议sql改成:
复制代码 代码如下:
declare @i int;
set @i=100
declare @sql nvarchar(max)
set @sql = 'select * from aaa'
if @i is not null
set @sql = @sql + ' where age = @i'
exec sp_executesql @sql, n'@i int', @i
当然,如果只有一个条件,可以设计成2条sql,比如:
复制代码 代码如下:
declare @i int;
set @i=100
if @i is not null
select * from aaa where age = @i
else
select * from aaa
但是,如果条件多了,sql数目也变得更多,所以建议用exec的方案