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

复制代码 代码如下:

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

时间: 2025-01-25 03:55:40

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

sql 2000 无法执行查询,因为一些文件缺少或未注册&amp;quot;的解决方法_MsSql

给朋友安装了一台演示机,系统是Windows Server 2003,数据库为SQL Server2000,安装完成之后,系统也没问题,SQL 企业管理器也能正常打开,数据库以及表也能正常加载,但打开表查看表数据时却无法返回行,提示如下错误: 无法执行查询,因为一些文件缺少或未注册.再次运行安装程序确保要求的文件已注册. 但实际上重装SQL 2000也无济于事,实际上按以下几个步骤解决即可. 1.注册以下的四个dll文件,重启机器即可. 复制代码 代码如下: regsvr32 "C:\Progr

SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析

在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index Scan))呢?是否所有情况都是如此?又该如何优化呢? 下面我们通过一些简单的例子来分析理解这些现象.下面的实验环境为SQL SERVER 2008,如果在不同版本有所区别,欢迎指正.   堆表单索引 首先我们构建我们测试需要实验环境,具体情况如下所示: DROP TABLE TEST    CRE

库表字符集不一致导致的全表扫描问题

背景: 当数据库的建库字符集和表不一样时,在库下针对表创建存储过程可能导致全表扫描 如下例: drop database if exists xx1; drop database if exists xx2; create database xx1 character set utf8; create database xx2 character set gbk;   然后分别在xx1 和 xx2下执行: CREATE TABLE t1 ( `col1` varchar(10) NOT NULL

SQL Server中参数化SQL写法遇到parameter sniff ,导致不合理执行计划重用的快速解决方法_MsSql

parameter sniff问题是重用其他参数生成的执行计划,导致当前参数采用该执行计划非最优化的现象.想必熟悉数据的同学都应该知道,产生parameter sniff最典型的问题就是使用了参数化的SQL(或者存储过程中使用了参数化)写法,如果存在数据分布不均匀的情况下,正常情况下生成的执行计划,在传入在分布数据较多的参数的情况下,重用了正常参数生成的执行计划,而这种缓存的执行计划并非适合当前参数的一种情况. 这种情况,在实际业务中,出现的频率还是比较高的,因为存储过程一般都是采用参数化的写法

cursor-PL/SQL中什么变量必须定义?它属于强类型语言还是弱类型语言

问题描述 PL/SQL中什么变量必须定义?它属于强类型语言还是弱类型语言 declare begin for i in 0..5 loop for k in 1..i loop dbms_output.put(' '); end loop; for j in 1..11-2*i loop dbms_output.put('*'); end loop; dbms_output.put_line(''); end loop; end; i,j,k都不必先申明再使用 declare pename em

电脑中CPU超频导致声卡爆音/无声的解决方法

电脑中CPU超频导致声卡爆音/无声的解决方法   1.如果该CPU可以超频到100Mz外频,这时由于主板自动会使用1/3分频,所以PCI总线频率会自动返回到33Mz,该故障现象就会自动消失; 2.如果CPU无法超到100MHz外频,那么只能更换一块质量好的声卡,但这样也有较大的危险性,最好的做法就是不使用非标准外频,将CPU外频重新调回66 MHz. 注:如果主板无法锁定AGP/PCI频率,那么当CPU外频处于非标准外频时,大多数声卡都有可能出现这样的问题.

大幅提升MySQL中InnoDB的全表扫描速度的方法_Mysql

 在 InnoDB中更加快速的全表扫描 一般来讲,大多数应用查询的时候都会用索引,查找很少的几行数据(主键查找或百行内的查询),但有时候我们需要全表查询.典型的全表扫描就是逻辑备份  (mysqldump) 和 online schema changes( 注:在线上对大表 schema 的操作,也是 facebook 的一个开源项目) (SELECT ... INTO OUTFILE).  在 Facebook我们用 mysqldump 来备份数据库. 正如你所知MySql提供两种备份方式,提

一条全表扫描sql语句的分析

今天在对生产系统做监控的时候,发现一个process的cpu消耗很高,抓取了对应的session和执行的sql语句. 发现是一个简单的update语句,这样一条如果CPU消耗较大,很可能是由于全表扫描的. UPDATE COMM_ACTIVITY SET COMM_ACTIVITY.EXTRACT_STATUS = NVL(:1 , EXTRACT_STATUS), COMM_ACTIVITY.SOURCE_TYPE = NVL(:2 , SOURCE_TYPE), OPERATOR_ID =

Sql Server之旅——第二站 理解万恶的表扫描

原文:Sql Server之旅--第二站 理解万恶的表扫描 很久以前我们在写sql的时候,最怕的一件事情就是sql莫名奇妙的超级慢,慢的是撸一管子回来,那个小球还在一直转...这个着急也只有当事人才 明白,后来听说有个什么"评估执行计划",后来的后来才明白应该避免表扫描... 一:表扫描 1.现象 "表扫描"听起来很简单,不就是一行一行的扫嘛,你要说"执行计划"的话,我也会玩,为了更可观,我build一个表,再插入三行数据,如下图:   上面的P