描述 大家通常禁止在生產環境直接使用select * 已成常識了,也常常在開發規範中就會規定不允許直接使用select *,那麼我們為什麼不允許使用select * ,在一些什麼場景下select * 會出問題?能否控制不能直接使用select *?出於這些疑問,我們特別測試記錄一下。 測試環境 M ...
描述
大家通常禁止在生產環境直接使用select * 已成常識了,也常常在開發規範中就會規定不允許直接使用select *,那麼我們為什麼不允許使用select * ,在一些什麼場景下select * 會出問題?能否控制不能直接使用select *?出於這些疑問,我們特別測試記錄一下。
測試環境
Microsoft SQL Server 2012 - 11.0.2100.60 (X64) Feb 10 2012 19:39:15 Copyright (c) Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: )select * 可能會造成業務功能出錯
假設我們有一個視圖 V_test 代碼如下:1 CREATE VIEW v_test 2 AS 3 SELECT * 4 FROM test
你在web前端調用直接使用如下腳本並對應好顯示的欄位,當時功能是正常的。
SELECT * FROM v_test
test 表結構如下: 後來因為業務調整,有人調整了test表 ,並加一個欄位F ,那麼接下來的後果就會前端相應的功能因新增的欄位F直接報錯。
select * 可能會造成性能方面的問題
測試數據準備1 --新建測試表 2 IF OBJECT_ID('test', 'U') IS NOT NULL 3 DROP TABLE test; 4 CREATE TABLE test 5 ( 6 id int IDENTITY(1, 1) , 7 a nvarchar(20) , 8 b nvarchar(15) , 9 c nvarchar(20) , 10 d int , 11 e float 12 );
1 --造測試數據 2 DECLARE @i INT; 3 SET @i = 10000; 4 WHILE ( @i > 0 ) 5 BEGIN 6 INSERT INTO test 7 ( a , 8 b , 9 c , 10 d , 11 e 12 ) 13 SELECT RAND() * 1000 , 14 RAND() * 1000 , 15 REPLICATE('a', 3) , 16 @i , 17 @i - 1; 18 SELECT @i = @i - 1; 19 END;
1 --新建索引(主鍵、非聚集索引) 2 ALTER TABLE dbo.test ADD CONSTRAINT PK_test_id PRIMARY KEY(ID); 3 CREATE INDEX IX_test_1 ON dbo.test(a);
查詢條件使用主鍵欄位的執行計劃,主鍵是預設覆蓋全部欄位。 如直接使用欄位a做查詢條件 還是聚集索引掃描,全表掃,無法使用我們已新建好的非聚集索引IX_test_1,在上述語句中因該索引未覆蓋到非a 的欄位。假設實際場景我們只需取a欄位,那麼執行計劃又是怎麼樣的? 如上圖,就會走我們期望的索引,同時也可以減少因select * 而多讀的欄位(id、b、c、d、e)的網路傳輸,所以,儘量指定自己所需的欄位名,可以避免一些無謂的性能開銷。
如何控制不讓 select *
假設我們不允許在上述測試表test上執行select * 可以如何處理1 --新建測試表 2 IF OBJECT_ID('test', 'U') IS NOT NULL 3 DROP TABLE test; 4 CREATE TABLE test 5 ( 6 id int IDENTITY(1, 1) , 7 a nvarchar(20) , 8 b nvarchar(15) , 9 c nvarchar(20) , 10 d int , 11 e float, 12 abort_select_all AS (1/0) ---新增控制欄位 13 ); 14 --造測試數據 15 DECLARE @i INT; 16 SET @i = 10000; 17 WHILE ( @i > 0 ) 18 BEGIN 19 INSERT INTO test 20 ( a , 21 b , 22 c , 23 d , 24 e 25 ) 26 SELECT RAND() * 1000 , 27 RAND() * 1000 , 28 REPLICATE('a', 3) , 29 @i , 30 @i - 1; 31 SELECT @i = @i - 1; 32 END; 33 --新建索引 (主鍵、非聚集索引) 34 ALTER TABLE dbo.test ADD CONSTRAINT PK_test_id PRIMARY KEY(ID); 35 CREATE INDEX IX_test_1 ON dbo.test(a);
如下圖,如果select * 因讀取了abort_select_all欄位(1/0)就會直接報錯,從而達到不能直接select *的效果;
直接按欄位名查詢沒有問題(非abort_select_all欄位)。 直接按欄位名查詢沒有問題。