[SQL][問題處理]真的不能用 1=1 嗎 ?

[SQL][問題處理]真的不能用 1=1 嗎 ?

這一陣子因為工作原因,換到不同的領域之後都忙著寫 Java 程式,也就比較沒有接觸 SQL Server。就在要下班的時候,同事傳個訊息說能否幫他看一篇文章(網址),他想知道是否真的要全面修改程式才有辦法解決文章中所說的問題。

 

其實這個問題最早發生是在一些程式中,會讓使用者去組合一些查詢調整,為了簡化一些 SQL 在組合的時候,不想去寫一些判斷,因此就會在 SQL 語法後面直接加上一個 1=1 的條件,這樣後面有其他條件加入的時候,就只要在寫上 「AND 附加的條件」,不用去管到底前面有沒有下過 WHERE 的一種變通的寫法。

 

但這樣的寫法會有問題嗎 ? 我們做個簡單的測試,先產生一個十萬筆的資料表

   1: -- 建立資料表
   2: CREATE TABLE [BigTable]
   3: (
   4:     A1    INT PRIMARY KEY,
   5:     A2    NVARCHAR(10),
   6:     A3    VARCHAR(10),
   7:     A4    NCHAR(200),
   8: )
   9: GO
  10:  
  11: DECLARE @I INT;
  12: DECLARE @J INT;
  13: DECLARE @K INT;
  14:  
  15: SET @J = 0;
  16:  
  17: -- 產生十萬筆的資料,為了避免交易記錄檔過大,每一萬筆資料放在一個 Transaction 內
  18: SET NOCOUNT ON;
  19: WHILE @J < 10
  20: BEGIN
  21:     SET @I = 0;
  22:     BEGIN TRAN
  23:     WHILE @I < 10000
  24:     BEGIN
  25:         SET @K = @J*10000+@I ;
  26:         INSERT INTO [BigTable] ( A1,A2,A3,A4 ) VALUES ( @K, RIGHT('0000000000'+LTRIM(STR(@K)),10), RIGHT('0000000000'+LTRIM(STR(@K)),10), NEWID())
  27:         SET @I += 1; 
  28:     END    
  29:     COMMIT
  30:     SET @J += 1; 
  31: END
  32: GO

 

那我們如果用文章中所寫的方式來下指令試試看

   1: DECLARE @A INT;
   2: SET @A = ROUND( RAND()*100000,0 );
   3:  
   4: SELECT * FROM [BigTable] WHERE A1 = @A OR 1=1
   5:  

image

看起來真的如同文章中所言,不會使用 INDEX 去找資料,效能看來真的很不好。但是我們仔細思考一下,我們會用 OR 去串這個條件嗎 ? 答案應該不會吧,如同一開始所言,我們只是用來界接後面的指令,因此應該會是用 AND 條件才對,因此我們調整一下指令,改成 AND 來試試看

   1: DECLARE @A INT;
   2: SET @A = ROUND( RAND()*100000,0 );
   3:  
   4: SELECT * FROM [BigTable] WHERE A1 = @A AND 1=1

image

 

看起來就會從原本的「索引掃描」換成「索引搜尋」了,時間也縮短了不少。因此我想應該不能說 SQL Server 2008 之後我們就一定要把 SQL 指令內的 1=1 的指令給拿掉才可以,當然如果可以把這個拿掉,在可讀性上面是比較好的,但從效能上來看,實際是沒有太大的影響,你可以仔細看一下執行計畫的 Hint,會發現 SQL Server 其實會自己幫你把那個條件給過濾掉,而當你是用 OR 的時候,它就變成把你後面接的條件省略掉了,因為這時候前面 1=1 的條件會讓每一筆資料都會符合條件,所以問題不在於 1=1 ,而是在 AND 和 OR 的上面。

image

 

所以聰明的你就可以去思考看看,到底你是否真的是需要調整程式囉。