SQL中WHERE變量IS NULL條件導致全表掃描問題的解決方法
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開發(fā)時,這種寫法是會導致全表掃描的,用不上索引,不知道Sql Server里是否也是一樣呢,于是做一個簡單的測試
1、建立測試用的表結(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萬條測試數(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、先開啟執(zhí)行計劃顯示:
在SQL Server Management Studio的查詢窗口里,右擊窗口任意位置,選擇“包含實際的執(zhí)行計劃”:

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
測試結(jié)果如下:

可以看到,即使@i有值,不管@i IS NULL是放在前面還是放在后面,都無法用到age的索引,另外age=ISNULL(@i,age)也用不上索引
最終結(jié)論,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數(shù)目也變得更多,所以建議用EXEC的方案
- MySQL Where 條件語句介紹和運算符小結(jié)
- MYSQL WHERE語句優(yōu)化
- MySQL 存儲過程傳參數(shù)實現(xiàn)where id in(1,2,3,...)示例
- MySQL左聯(lián)多表查詢where條件寫法示例
- MySQL 聯(lián)合索引與Where子句的優(yōu)化 提高數(shù)據(jù)庫運行效率
- sql語句中where 1=1的作用
- MySQL中union和join語句使用區(qū)別的辨析教程
- SQL語句的并集UNION 交集JOIN(內(nèi)連接,外連接)等介紹
- 解析sql語句中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ū)別
相關文章
SQL Server 利用觸發(fā)器對多表視圖進行更新的實現(xiàn)方法
這篇文章主要介紹了SQL Server 利用觸發(fā)器對多表視圖進行更新的實現(xiàn)方法,需要的朋友可以參考下2016-10-10安裝sql server2008后再安裝sql 2005找不到本地服務器的解決方法
這篇文章主要介紹了安裝sql server2008后再安裝sql 2005找不到本地服務器的解決方法,需要的朋友可以參考下2015-01-01SQLServer獲取臨時表所有列名或是否存在指定列名的方法
本文介紹了SQLServer獲取臨時表所有列名或是否存在指定列名的方法,需要的朋友一起來看下吧2016-12-12一步步教你建立SQL數(shù)據(jù)庫的表分區(qū)
分區(qū)存儲提高了數(shù)據(jù)庫的性能,被分區(qū)存儲的數(shù)據(jù)物理上是多個文件,但邏輯上任然是一個表,對表的任何操作都跟沒分區(qū)之前一樣。插入、刪除、查詢、更新等操作的時候,數(shù)據(jù)庫會自動為你找到對應的分區(qū),然后執(zhí)行操作。2015-09-09談談Tempdb對SQL Server性能優(yōu)化有何影響
由于tempdb是SQLServer的系統(tǒng)數(shù)據(jù)庫一直都是SQLServer的重要組成部分,用來存儲臨時對象,在數(shù)據(jù)庫中起到舉足輕重的作用,此篇文章給大家?guī)韙empdb對sql server性能優(yōu)化的影響,感興趣的朋友參考下2015-11-11sql update 觸發(fā)器 可獲得被update的行的信息
sql update 觸發(fā)器 可獲得被update的行的信息,需要的朋友可以參考下。2010-06-06SQL SERVER數(shù)據(jù)庫的作業(yè)的腳本及存儲過程
本站文章旨在為該問題提供解決思路及關鍵性代碼,并不能完成應該由網(wǎng)友自己完成的所有工作,請網(wǎng)友在仔細看文章并理解思路的基礎上舉一反三、靈活運用2015-10-10