欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SQL中WHERE变量IS NULL条件导致全表扫描问题的解决方法

程序员文章站 2023-11-04 20:30:22
复制代码 代码如下: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的查询窗口里,右击窗口任意位置,选择“包含实际的执行计划”:
SQL中WHERE变量IS NULL条件导致全表扫描问题的解决方法

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

测试结果如下:
SQL中WHERE变量IS NULL条件导致全表扫描问题的解决方法

可以看到,即使@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的方案