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