‘SELECT *’ 為什麼它是反模式
關於這裡的多個問題和堆棧溢出,我看到人們在評論和答案中說
select * from table
幾乎總是一種反模式,沒有任何解釋為什麼。雖然我可以推斷出為什麼它是一種反模式。我可能正在查看其他對問題有更好理解的人注意到的細節。所以這是我的問題,為什麼人們說這
select *
是一種反模式。
我發現最有說服力不在
SELECT *
SQL Server 中使用的兩個原因是
- 記憶體補助
- 索引使用
記憶體補助
當查詢需要排序、散列或併行時,它們會為這些操作請求記憶體。記憶體授予的大小基於數據的大小,包括行和列。
字元串數據對此尤其有影響,因為優化器將定義長度的一半猜測為列的“填充度”。所以對於 VARCHAR 100,它是 50 字節 * 行數。
以 Stack Overflow 為例,如果我對 Users 表執行這些查詢:
SELECT TOP 1000 DisplayName FROM dbo.Users AS u ORDER BY u.Reputation; SELECT TOP 1000 DisplayName, u.Location FROM dbo.Users AS u ORDER BY u.Reputation;
DisplayName 是 NVARCHAR 40,Location 是 NVARCHAR 100。
如果沒有 Reputation 索引,SQL Server 需要自行對數據進行排序。
但它的記憶體幾乎翻了一番。
顯示名稱:
顯示名稱,位置:
這變得更糟
SELECT *
,要求 8.2 GB 記憶體:它這樣做是為了處理需要通過 Sort 運算符傳遞的大量數據,包括具有 MAX 長度的 AboutMe 列。
索引使用
如果我在使用者表上有這個索引:
CREATE NONCLUSTERED INDEX ix_Users ON dbo.Users ( CreationDate ASC, Reputation ASC, Id ASC );
我有這個查詢,其中有一個與索引匹配的 WHERE 子句,但不涵蓋/包括查詢選擇的所有列……
SELECT u.*, p.Id AS [PostId] FROM dbo.Users AS u JOIN dbo.Posts AS p ON p.OwnerUserId = u.Id WHERE u.CreationDate > '20171001' AND u.Reputation > 100 AND p.PostTypeId = 1 ORDER BY u.Id
優化器可能選擇不使用帶鍵查找的窄索引,而只掃描聚集索引。
您要麼必須創建一個非常寬的索引,要麼嘗試重寫以選擇窄索引,即使使用窄索引會產生更快的查詢。
客戶體驗:
SQL Server Execution Times: CPU time = 6374 ms, elapsed time = 4165 ms.
數控:
SQL Server Execution Times: CPU time = 1623 ms, elapsed time = 875 ms.
這是一個控制問題。
使用 ‘select * from…’ 未定義返回列的數量和返回列的順序。
數據庫的許多程式介面取決於返回值的數量和順序。