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

时间:2024-01-13 12:58:24 


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的方案

标签:sql,ISNULL,全表扫描
0
投稿

猜你喜欢

  • python程序中调用其他程序的实现

    2021-08-07 12:33:16
  • js中更短的 Array 类型转换

    2024-04-28 09:47:22
  • python爬虫urllib中的异常模块处理

    2022-12-06 10:42:33
  • python提取word文件中的图片并上传阿里云OSS

    2021-02-01 10:52:25
  • Python海象运算符超详细讲解

    2023-08-04 17:26:19
  • win2008下mysql8.0.11升级mysql8.0.17版本详细步骤

    2024-01-13 18:04:32
  • Python爬取新型冠状病毒“谣言”新闻进行数据分析

    2021-06-14 04:47:33
  • Python合并pdf文件的工具

    2021-09-09 23:28:47
  • python 进程 进程池 进程间通信实现解析

    2022-07-05 07:38:28
  • 详解Python_shutil模块

    2023-06-24 00:32:19
  • MySQL下载安装、配置与使用教程详细版(win7x64)

    2024-01-22 16:44:50
  • 使用SAE部署Python运行环境的教程

    2021-02-21 14:26:54
  • Python实现随机生成手机号及正则验证手机号的方法

    2021-05-30 01:41:27
  • Mysql使用kill命令解决死锁问题(杀死某条正在执行的sql语句)

    2024-01-24 06:36:03
  • Go操作redis与redigo的示例解析

    2024-04-28 09:12:38
  • mysql如何通过当前排序字段获取相邻数据项

    2024-01-13 02:24:25
  • PHP开发中常见的安全问题详解和解决方法(如Sql注入、CSRF、Xss、CC等)

    2023-10-02 23:03:06
  • mysql中普通索引和唯一索引的效率对比

    2010-12-08 16:03:00
  • golang设置http response响应头与填坑记录

    2024-05-21 10:22:24
  • MySQL prepare语句的SQL语法

    2024-01-20 03:14:08
  • asp之家 网络编程 m.aspxhome.com