SQL中WHERE變量IS NULL條件導(dǎo)致全表掃描問(wèn)題的解決方法
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開(kāi)發(fā)時(shí),這種寫(xiě)法是會(huì)導(dǎo)致全表掃描的,用不上索引,不知道Sql Server里是否也是一樣呢,于是做一個(gè)簡(jiǎn)單的測(cè)試
1、建立測(cè)試用的表結(jié)構(gòu)和索引:
CREATE TABLE aaa(id int IDENTITY, NAME VARCHAR(12), age INT)
go
CREATE INDEX idx_age ON aaa (age)
GO
2、插入1萬(wàn)條測(cè)試數(shù)據(jù):
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、先開(kāi)啟執(zhí)行計(jì)劃顯示:
在SQL Server Management Studio的查詢窗口里,右擊窗口任意位置,選擇“包含實(shí)際的執(zhí)行計(jì)劃”:

4、開(kāi)始測(cè)試,用下面的SQL進(jìn)行測(cè)試:
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
測(cè)試結(jié)果如下:

可以看到,即使@i有值,不管@i IS NULL是放在前面還是放在后面,都無(wú)法用到age的索引,另外age=ISNULL(@i,age)也用不上索引
最終結(jié)論,SQL Server跟ORACLE一樣,如果條件里加了 變量 IS NULL,都會(huì)導(dǎo)致全表掃描。
建議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
當(dāng)然,如果只有一個(gè)條件,可以設(shè)計(jì)成2條SQL,比如:
DECLARE @i INT;
SET @i=100
IF @i IS NOT NULL
SELECT * FROM aaa WHERE age = @i
ELSE
SELECT * FROM aaa
但是,如果條件多了,SQL數(shù)目也變得更多,所以建議用EXEC的方案
- MySQL Where 條件語(yǔ)句介紹和運(yùn)算符小結(jié)
- MYSQL WHERE語(yǔ)句優(yōu)化
- MySQL 存儲(chǔ)過(guò)程傳參數(shù)實(shí)現(xiàn)where id in(1,2,3,...)示例
- MySQL左聯(lián)多表查詢where條件寫(xiě)法示例
- MySQL 聯(lián)合索引與Where子句的優(yōu)化 提高數(shù)據(jù)庫(kù)運(yùn)行效率
- sql語(yǔ)句中where 1=1的作用
- MySQL中union和join語(yǔ)句使用區(qū)別的辨析教程
- SQL語(yǔ)句的并集UNION 交集JOIN(內(nèi)連接,外連接)等介紹
- 解析sql語(yǔ)句中l(wèi)eft_join、inner_join中的on與where的區(qū)別
- 解析mysql left( right ) join使用on與where篩選的差異
- SQL中JOIN和UNION區(qū)別、用法及示例介紹
- sql join on 用法
- SQL where條件和jion on條件的詳解及區(qū)別
相關(guān)文章
SQL Server 利用觸發(fā)器對(duì)多表視圖進(jìn)行更新的實(shí)現(xiàn)方法
這篇文章主要介紹了SQL Server 利用觸發(fā)器對(duì)多表視圖進(jìn)行更新的實(shí)現(xiàn)方法,需要的朋友可以參考下2016-10-10安裝sql server2008后再安裝sql 2005找不到本地服務(wù)器的解決方法
這篇文章主要介紹了安裝sql server2008后再安裝sql 2005找不到本地服務(wù)器的解決方法,需要的朋友可以參考下2015-01-01SQLServer獲取臨時(shí)表所有列名或是否存在指定列名的方法
本文介紹了SQLServer獲取臨時(shí)表所有列名或是否存在指定列名的方法,需要的朋友一起來(lái)看下吧2016-12-12數(shù)據(jù)庫(kù)復(fù)制性能測(cè)試 推送模式性能測(cè)試
使用了數(shù)據(jù)庫(kù)復(fù)制的人,首先擔(dān)心的就是主服務(wù)器和備份服務(wù)器的性能消耗問(wèn)題,本人也是對(duì)此十分擔(dān)憂,查了半天,基本上沒(méi)發(fā)現(xiàn)類(lèi)似的測(cè)試說(shuō)明,就自己測(cè)試了一下,下面為測(cè)試的結(jié)果,僅供參考2012-06-06一步步教你建立SQL數(shù)據(jù)庫(kù)的表分區(qū)
分區(qū)存儲(chǔ)提高了數(shù)據(jù)庫(kù)的性能,被分區(qū)存儲(chǔ)的數(shù)據(jù)物理上是多個(gè)文件,但邏輯上任然是一個(gè)表,對(duì)表的任何操作都跟沒(méi)分區(qū)之前一樣。插入、刪除、查詢、更新等操作的時(shí)候,數(shù)據(jù)庫(kù)會(huì)自動(dòng)為你找到對(duì)應(yīng)的分區(qū),然后執(zhí)行操作。2015-09-09談?wù)凾empdb對(duì)SQL Server性能優(yōu)化有何影響
由于tempdb是SQLServer的系統(tǒng)數(shù)據(jù)庫(kù)一直都是SQLServer的重要組成部分,用來(lái)存儲(chǔ)臨時(shí)對(duì)象,在數(shù)據(jù)庫(kù)中起到舉足輕重的作用,此篇文章給大家?guī)?lái)tempdb對(duì)sql server性能優(yōu)化的影響,感興趣的朋友參考下2015-11-11sql update 觸發(fā)器 可獲得被update的行的信息
sql update 觸發(fā)器 可獲得被update的行的信息,需要的朋友可以參考下。2010-06-06SQL SERVER數(shù)據(jù)庫(kù)的作業(yè)的腳本及存儲(chǔ)過(guò)程
本站文章旨在為該問(wèn)題提供解決思路及關(guān)鍵性代碼,并不能完成應(yīng)該由網(wǎng)友自己完成的所有工作,請(qǐng)網(wǎng)友在仔細(xì)看文章并理解思路的基礎(chǔ)上舉一反三、靈活運(yùn)用2015-10-10