Best-Practices

‘SELECT *’ 為什麼它是反模式

  • October 16, 2018

關於這裡的多個問題和堆棧溢出,我看到人們在評論和答案中說select * from table幾乎總是一種反模式,沒有任何解釋為什麼。雖然我可以推斷出為什麼它一種反模式。我可能正在查看其他對問題有更好理解的人注意到的細節。

所以這是我的問題,為什麼人們說這select *是一種反模式。

我發現最有說服力不在SELECT *SQL Server 中使用的兩個原因是

  1. 記憶體補助
  2. 索引使用

記憶體補助

當查詢需要排序、散列或併行時,它們會為這些操作請求記憶體。記憶體授予的大小基於數據的大小,包括行和列。

字元串數據對此尤其有影響,因為優化器將定義長度的一半猜測為列的“填充度”。所以對於 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…’ 未定義返回列的數量和返回列的順序。

數據庫的許多程式介面取決於返回值的數量和順序。

引用自:https://dba.stackexchange.com/questions/220216