SQL中WHERE 變數 IS NULL 條件導致全表掃描的問題

來源:互聯網
上載者:User

今天在評審接手的項目中的預存程序時,發現存在大量的在條件裡判斷變數是否NULL的寫法,如:
    And (@ProjectIds Is Null or ProjectId = @ProjectIds)
    And (@Scores is null or Score =@Scores)'

印象中記得,以前在做Oracle開發時,這種寫法是會導致全表掃描的,用不上索引,不知道Sql Server裡是否也是一樣呢,於是做一個簡單的測試

1、建立測試用的表結構和索引:
go
CREATE INDEX idx_age ON aaa (age)
GO

2、插入1萬條測試資料:
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進行測試:
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改成:
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,比如:
SET @i=100
IF @i IS NOT NULL
    SELECT * FROM aaa WHERE age = @i
ELSE
    SELECT * FROM aaa
 

但是,如果條件多了,SQL數目也變得更多,所以建議用EXEC的方案

首發:http://beinet.cn

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.