SQL Server每一個表中各列的數據類型的有各類形式,產生的效果也各有不一樣,咱們主要根據效率兼顧性能的狀況下討論下如何規定類型。數據庫
在SQL Server中,數據的存儲以頁爲單位。八個頁爲一個區。一頁爲8K,一個區爲64K,這個意味着1M的空間能夠容納16個區。 SQL Server中的分配單元分爲三種,分別爲存儲行內數據的In_Row_Data,存儲Lob對象的LOB_Data,存儲溢出數據的Row_Overflow_data。下面咱們經過一個更具體的例子來理解這三種分配單元。函數
我創建如圖2所示的表。性能
圖2.測試表測試
圖2的測試表不難看出,經過插入數據使得每一行的長度會超過每頁所能容納的最大長度8060字節。使得不只產生了行溢出(Row_Overflow_Data),還須要存儲LOB的頁.測試的插入語句和經過DBCC IND看到的分配狀況如圖3所示。優化
圖3.超過8060字節的行所分配的頁編碼
除去IAM頁,這1行數據所須要三個頁來存儲。首先是LOB頁,這類是用於存儲存在數據庫的二進制文件所設計,當這個類型的列出現時,在原有的列會存儲一個24字節的指針,而將具體的二進制數據存在LOB頁中,除去Text以外,VarBinary(max)也是存在LOB頁中的。而後是溢出行,在SQL Server 2000中,一行超過8060字節是不被容許的,在SQL Server 2005以後的版本對這個特性進行了改進,使用Varchar,nvarchar等數據類型時,當行的大小不超過8060字節時,所有存在行內In-row data,當varchar中存儲的數據過多使得整行超過8060字節時,會將額外的部分存於Row-overflow data頁中,若是update這列使得行大小減小到小於8060字節,則這行又會所有回到in-row data頁。設計
在瞭解了一些基礎知識以後。咱們知道SQL Server讀取數據是以頁爲單位,更少的頁不只僅意味着更少的IO,還有更少的內存和CPU資源消耗。因此對於數據選擇的主旨是:指針
儘可能使得每行的大小更小對象
這個聽起來很是簡單,但實際上還須要對SQL Server的數據類型有更多的瞭解。blog
好比存儲INT類型的數據,按照業務規則,能用INT就不用BIGINT,能用SMALLINT就不用INT,能用TINYINT就不用SMALLINT。
因此爲了使每行的數據更小,則使用佔字節最小的數據類型。
1.好比不要使用DateTime類型,而根據業務使用更精確的類型,以下表:
類型
所佔字節
Date(僅日期)
3
Time(僅時間)
5
DateTime2(時間和日期)
8
DateTimeOffSet(外加時區)
10
2.使用VarChar(Max),Nvarchar(Max),varbinary(Max)來代替text,ntext和image類型
根據前面的基礎知識能夠知道,對於text,ntext和image類型來講,每一列只要不爲null,即便佔用很小的數據,也須要額外分配一個LOB頁,這無疑佔用了更多的頁。而對於Varchar(Max)等數據類型來講,當數據量很小的時候,存在In-row-data中就能知足要求,而不用額外的LOB頁,只有當數據溢出時,纔會額外分配LOB頁,除此以外,Varchar(Max)等類型支持字符串操做函數好比:
3.對於僅僅存儲數字的列,使用數字類型而不是Varchar等。
由於數字類型佔用更小的存儲空間。好比存儲123456789使用INT類型只須要4個字節,而使用Varchar就須要9個字節(這還不包括Varchar還須要佔用4個字節記錄長度)。
4.若是沒有必要,不要使用Nvarchar,Nchar等以「字」爲單位存儲的數據類型。這類數據類型相比varchar或是char須要更多的存儲空間。
5.關於Char和VarChar的選擇
這類比較其實有一些了。若是懶得記憶,大多數狀況下使用Varchar都是正確的選擇。咱們知道Varchar所佔用的存儲空間由其存儲的內容決定,而Char所佔用的存儲空間由定義其的長度決定。所以Char的長度不管存儲多少數據,都會佔用其定義的空間。因此若是列存儲着像郵政編碼這樣的固定長度的數據,選擇Char吧,不然選擇Varchar會比較好。除此以外,Varchar相比Char要多佔用幾個字節存儲其長度,下面咱們來作個簡單的實驗。
首先咱們創建表,這個表中只有兩個列,一個INT類型的列,另外一個類型定義爲Char(5),向其中插入兩條測試數據,而後經過DBCC PAGE來查看其頁內結構,如圖4所示。
下面咱們再來看改成Varchar(5),此時的頁信息,如圖5所示。
圖5.Varchar(5),每行所佔用的空間爲20字節
所以能夠看出,Varchar須要額外4個字節來記錄其內容長度。所以,當實際列存儲的內容長度小於5字節時,使用char而不是varchar會更節省空間。
關於Null的使用也是略有爭議。有些人建議不要容許Null,所有設置成Not Null+Default。這樣作是因爲SQL Server比較時就不會使用三值邏輯(TRUE,FALSE,UNKNOWN),而使用二值邏輯(True,False),而且查詢的時候也再也不須要IsNull函數來替換Null值。
但這也引出了一些問題,好比聚合函數的時候,Null值是不參與運算的,而使用Not Null+Default這個值就須要作排除處理。
所以Null的使用還須要按照具體的業務來看。
稀疏列是對 Null 值採用優化的存儲方式的普通列。 稀疏列減小了 Null 值的空間需求,但代價是檢索非 Null 值的開銷增長。 當至少可以節省 20% 到 40% 的空間時,才應考慮使用稀疏列。
稀疏列在SSMS中的設置如圖6所示。
圖6.稀疏列
更具體的稀疏列如何能節省空間,請參看MSDN。
對於主鍵的選擇是表設計的重中之重,由於主鍵不只關係到業務模型,更關係到對錶數據操做的的效率(由於主鍵會處於B樹的非葉子節點中,對樹的高度的影響最多)。這個咱們得結合主鍵索引的選擇來具體分析,以前寫過一篇關於索引的,之後有須要再進一步延伸來說
總結
本篇文章對於設計表時,數據列的選擇進行了一些探尋。好的表設計不只僅是能知足業務需求,還可以知足對性能的優化。