使用較小的 varchar 或 nvarchar 大小而不是像 4000 這樣的大值是否可以節省任何東西?
在將數據導入 SQL Server 時,通常無法考慮導入的字元串欄位會有多大。我可以懶洋洋地繼續為 char 欄位定義使用較大的值嗎?如果我努力尋找合適的 char 欄位的最大大小,它對性能和速度有什麼影響嗎?
如果重要的話,我有 SQL Server 2016 和 2019。
SQL Server 通常必須分配工作記憶體來執行查詢。授予的記憶體量取決於許多因素,包括列數據類型和長度。對於 (n)varchar,它猜測實際值平均是聲明長度的一半,並相應地計算所需的記憶體。
因此,過大的列可能會導致記憶體預留過大、吞吐量降低和系統性能下降。
為了說明這一點,我創建了一系列表格。都是形式
create table dbo.t10(c varchar(10) null); : create table dbo.t2000(c varchar(2000) null);
列的長度因表而異。最短的是 10(如圖所示),最長的是 2,000。
每個表都填充了一百萬行。每行由單個字母“a”組成。因此,所有表都保存相同數量的數據並佔用相同數量的磁碟空間 (
exec sp_spaceused 'dbo.t10';
)。我使用一個非常簡單的查詢
select c from dbo.t10 order by c option(maxdop 1);
排序意味著將請求記憶體授予。使用 maxdop 1 可以避免某些計劃並行執行並使比較複雜化的風險。
我為每個表 t10 到 t2000 執行此程序,擷取實際執行計劃並記錄 MemoryGrantInfo。這是所需記憶體(以 KB 為單位)如何隨列長度變化的圖。我認為這很有說服力。
在 10 到 2,000 的大小範圍內沒有任何意義。它們只是隨意的,是為了方便而選擇的,而不是為了說明任何特定點。
同樣,字母“a”是我手指輸入的第一件事。
我的系統有足夠的記憶體。Desired、Requested 和 Granted 在每個測試中都是相同的。我選擇繪製所需的記憶體,因為如果有差異,它將是最大的。
據推測,導入數據的目的是讓某人使用它。如果是這樣,那麼有人必須弄清楚要分配多少空間。在絕大多數情況下,在導入過程中執行一次比在下游執行幾次更有意義,因為報告、應用程序和其他服務試圖確定它們是否真的需要允許 4000 個字元。通常,這些下游應用程序將根據聲明的列大小分配記憶體緩衝區,在這種情況下,您可能會為它們創建性能和可伸縮性問題。
忽略下游使用者的痛苦,將一切定義為
[n]varchar(4000)
使索引成為痛苦。對於 SQL Server 2016,聚集索引鍵中只能有 900 字節,非聚集索引鍵中只能有 1700 字節。如果您定義具有適當長度的列,您將知道要創建的索引是否會超出這些限制。如果您將所有內容定義為[n]varchar(4000)
,您今天可以定義索引,但明天您的載入將失敗,因為它試圖插入一個鍵太長的行。設計和調試列長度告訴您實際限制的系統比使用隨機索引組定義該限制的系統要容易得多。