對於表列資料型別選擇的一點思考

2021-09-30 21:25:25 字數 3661 閱讀 1074

簡介

sqlserver每個表中各列的資料型別的選擇通常顯得很簡單,但是對於具體資料型別的選擇的不同對效能的影響還是略有差別。本篇文章對sql server表列資料型別的選擇進行一些探索。

一些資料儲存的基礎知識

在sql server中,資料的儲存以頁為單位。八個頁為乙個區。一頁為8k,乙個區為64k,這個意味著1m的空間可以容納16個區。如圖1所示:

圖1.sql server中的頁和區

如圖1(ps:發現用windows自帶的畫圖程式畫部落格中的也不錯)可以看出,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的資料型別有更多的了解。

比如儲存int型別的資料,按照業務規則,能用int就不用bigint,能用smallint就不用int,能用tinyint就不用smallint。

所以為了使每行的資料更小,則使用佔位元組最小的資料型別。

1、比如不要使用datetime型別,而根據業務使用更精確的型別,如下表:

2、使用varchar(max),nvarchar(max),varbinary(max)來代替text,ntext和image型別

根據前面的基礎知識可以知道,對於text,ntext和image型別來說,每一列只要不為null,即使占用很小的資料,也需要額外分配乙個lob頁,這無疑占用了更多的頁。而對於varchar(max)等資料型別來說,當資料量很小的時候,存在in-row-data中就能滿足要求,而不用額外的lob頁,只有當資料溢位時,才會額外分配lob頁,除此之外,varchar(max)等型別支援字串操作函式比如:

● col_length

● charindex

● patindex

● len

● datalength

● substring

3、對於僅僅儲存數字的列,使用數字型別而不是varchar等。

因為數字型別占用更小的儲存空間。比如儲存123456789使用int型別只需要4個位元組,而使用varchar就需要9個位元組(這還不包括varchar還需要占用4個位元組記錄長度)。

4、如果沒有必要,不要使用nvarchar,nchar等以「字」為單位儲存的資料型別。這類資料型別相比varchar或是char需要更多的儲存空間。

5、關於char和varchar的選擇

首先我們建立表,這個表中只有兩個列,乙個int型別的列,另乙個型別定義為char(5),向其中插入兩條測試資料,然後通過dbcc page來檢視其頁內結構,如圖4所示。

圖4.使用char(5)型別,每行所佔的空間為16位元組

下面我們再來看改為varchar(5),此時的頁資訊,如圖5所示。

圖5.varchar(5),每行所占用的空間為20位元組

因此可以看出,varchar需要額外4個位元組來記錄其內容長度。因此,當實際列儲存的內容長度小於5位元組時,使用char而不是varchar會更節省空間。

關於null的使用

關於null的使用也是略有爭議。有些人建議不要允許null,全部設定成not null+default。這樣做是由於sql server比較時就不會使用三值邏輯(true,false,unknown),而使用二值邏輯(true,false),並且查詢的時候也不再需要isnull函式來替換null值。

但這也引出了一些問題,比如聚合函式的時候,null值是不參與運算的,而使用not null+default這個值就需要做排除處理。

因此null的使用還需要按照具體的業務來看。

考慮使用稀疏列(sparse)

稀疏列是對 null 值採用優化的儲存方式的普通列。 稀疏列減少了 null 值的空間需求,但代價是檢索非 null 值的開銷增加。 當至少能夠節省 20% 到 40% 的空間時,才應考慮使用稀疏列。

稀疏列在ssms中的設定如圖6所示。

圖6.稀疏列

對於主鍵的選擇

對於主鍵的選擇是表設計的重中之重,因為主鍵不僅關係到業務模型,更關係到對錶資料操作的的效率(因為主鍵會處於b樹的非葉子節點中,對樹的高度的影響最多)。關於主鍵的選擇,我之前已經有一篇文章關於這點:從效能的角度談sql server聚集索引鍵的選擇,這裡就不再細說了。

總結

本篇文章對於設計表時,資料列的選擇進行了一些探尋。好的表設計不僅僅是能滿足業務需求,還能夠滿足對效能的優化。

***********************************=分割線******************************==

對於公司程式設計師的一點思考

對於公司程式設計師的一點思考 趁著中午午休的時間,自己碎碎念一下公司的程式設計師。說真的,剛出入程式設計師這個行業,其實我感覺我挺孤獨的,這種孤獨是一種說不出來的感覺,或許因為我是慢熱型的性格吧!所有可能相處關係和很慢,但我總覺得,不相處也罷!說真的,我真的看不起公司的個別程式設計師,就算是之前公司...

關於SVM類別選擇的一點思考

學習svm時,關於類別選擇問題陷入了乙個誤區,現在把這個過程記錄下來,希望有同樣疑問的童鞋也能注意一下。如圖1所示,直線方程為x y 4 0,設直線上方的 o 為正例,直線下方的 為負例。當樣本點被超平面正確分類時,滿足yi w xi b 0條件,但是這個前提是假設 直線上方的點為正例,下方的點為負...

對於學習第二語言的一點思考

在學習第二語言的過程中,相信大家都有這樣的苦惱,說出來的話都帶著濃濃的中國味。這是怎麼回事呢?一般來說,只要錯過了語言的最佳習得期即兒童時期,再學一門外語就一定會受母語的影響 排除那些天生具有語言天才的人 這是我們在說或寫外語時候的思維結構決定的。在這裡筆者簡要地把說外語的思維過程分成三層境界 境界...