首先感謝宋沄劍提供的文章和sqlskill網站:www.sqlskills.com,看下面文章之前請先看一下下面兩篇文章
SQL Server誤區30日談-Day6-有關NULL位圖的三個誤區
char nchar varchar nvarchar的差別
在SQLSERVER内部有很多地方都使用到了位圖技術,包括執行計劃,資料庫系統頁面,複制,還有這篇文章說到的資料行中的NULL位圖
執行計劃中有位圖運算符
資料庫系統頁面有:DCM頁面、BCM頁面,詳細請看:SQL Server 2008 存儲結構之DCM、BCM
複制:Replication的犄角旮旯(三)--聊聊@bitmap(@bitmap 是binary類型,即二進制串;簡單來說,它是用來表示所操作的字段位置的參數,通過@bitmap,分發代理從distribution.dbo.msrepl_commands中讀取指令時(update操作),才會知道哪些列進行了更新;)
而這些位圖技術的作用無疑都是為了 标志位
标志哪些地方發生了變化,發生了變化的就标記為1,沒有發生變化的就标記為0
建立環境
建表
插入資料
檢視
建立DBCCResult表
View Code
檢視資料頁
資料頁内容
我們看到第一行的長度是11,第二行的長度是17
我們看第一行記錄長度11怎麽得出來的
在SQL Server頁中行實體存儲裡對資料行的各段進行了解釋
2個位元組行标頭存儲了狀态A和狀态B的資訊(2 bytes row header)
2個位元組存儲固定長度大小,因為一行記錄了有varchar這些不固定長度的資料類型(2 bytes for length of fixed length columns)
SQLSERVER需要知道int、datetime、decimal這些固定長度資料類型的大小
2個位元組的列數,用來存儲這個表一共有多少列(2 bytes for number of columns in the table)
1個位元組的null bitmap,(1 byte for null bitmap)
4個位元組存儲int型資料(4 bytes for int (1st column))
2+2+2+1+4=11
我們看第二行記錄長度17怎麽得出來的
2個位元組存儲資料行中的可變長度列數量,統計資料行中一共有多少列是nvarchar ,varchar類型的列( 2 bytes for number of variable length columns in the table)
2個位元組存儲可變長度偏移陣列,可變長度偏移陣列的公式
2*表格中可變長度資料類型的列數量,這個表隻有一列varchar,是以2*1=2,為什麽要有可變長度偏移陣列?我估計是因為可變長度的資料類型
存儲的資料是不固定的,是以要預留一些位置,當update varchar值的時候有足夠的位置(2 bytes for name column offset)
2個位元組存儲name列的值,為什麽用兩個位元組大家可以看一下char nchar varchar nvarchar的差別 2 bytes for name (你)
2+2+2+1+4+2+2+2=17
我們這裡不讨論資料占用空間的問題,這裡要說的是null bitmap
無論資料行中是否有null值,都會有一個位元組用來存儲null bitmap
而這個null bitmap是不是總是隻有一個位元組的長度,他的原理是什麼??
我畫了一下草圖
他在每一行記錄裡都存在,并且标記了哪一列是NULL,哪一列不是NULL
這樣在使用 len函數或者select 出表中的資料時候,先掃描NULL 位圖,遇到某一位為1就跳過不select出來,進而大大加快select的速度
len函數也是一樣,遇到某一位為1就傳回null
但是一個位元組隻有8位,也就是隻能标記表中8個列,如果一張表有10個列呢??
我們建立另外一張表
看一下他的資料頁
2個位元組行标頭存儲了狀态A和狀态B的資訊
2個位元組存儲固定長度大小,因為一行記錄了有varchar這些不固定長度的資料類型
2個位元組的列數,用來存儲這個表一共有多少列
4個位元組存儲int型資料
2個位元組存儲資料行中的可變長度列數量,統計資料行中一共有多少列是nvarchar ,varchar類型的列
20個位元組存儲可變長度偏移陣列,可變長度偏移陣列的公式2*10=20,因為有10個varchar類型列
9個位元組存儲name1~name10列的值,因為name1值為null,是以實際位元組長度為9個位元組即統計name2~name10的值,詳細可以再看一下
2個位元組的null bitmap
2+2+2+4+2+20+9+2=43
下面用草圖示範
是以這裡NULL位圖的長度是根據你目前表中有多少列來決定的
testnull10varchar表有11個列相當于需要2個位元組的NULL 位圖了
關于行記錄屬性
在上面的實驗中testnullvarchar表第一行記錄和第二行記錄的行記錄屬性都不一樣,實際上這個行記錄屬性隻是指明
testnullvarchar表第二行記錄有可變長度類型資料,并且不為NULL,這并不意味着SQLSERVER掃描到第一行記錄的時候,
當發現record attributes(行記錄屬性)=NULL_BITMAP 就跳過第一行,不去讀取第一行記錄裡的資料
掃描到第二行記錄的時候,當發現record attributes(行記錄屬性)=NULL_BITMAP VARIABLE_COLUMNS知道第二行記錄有
可變長度資料并且不為NULL就去讀取第二行記錄裡的資料
論壇裡的rmiao大俠給出了下面解釋:
Null_bitmap in record attributes means this record contains null_bitmap field. Likewise,'null_bitmap variable_columns' means this record contains null_bitmap field with variable length columns.
不管資料行中是否有NULL值,建表的時候是否允許NULL,資料頁中的行都會有record attributes = NULL_BITMAP
而record attributes =NULL_BITMAP VARIABLE_COLUMNS 隻是說明了資料行有可變長度資料類型并且不為NULL
是以SQLSERVER在任何情況下都會去掃描這個NULL 位圖的,除了Record Attributes = No null bitmap
詳細可以看一下SQL Server誤區30日談-Day6-有關NULL位圖的三個誤區
證明
建立測試環境
testnullchar表,因為testnullchar表沒有可變長度資料類型,是以兩行資料都是NULL_BITMAP
testnotnullvarchar表,因為testnotnullvarchar表有可變長度資料類型,是以第二行為NULL_BITMAP VARIABLE_COLUMNS
testnotnullchar表,跟testnullchar表一樣
而NULL_BITMAP VARIABLE_COLUMNS隻是說明了資料行中有可變長度類型的資料,不是說某個字段就是可變長度資料類型
題外話
其實這篇文章是我前天看到某篇文章特别而寫的,覺得這個null bitmap要好好研究一下,以免被人誤導
本人不喜歡某些人以泰山壓頂之勢去評論别人,你知道的某些東西可能不一定正确的,而别人不知道的東西,日後一定會知道的,隻是時間問題
知道某樣東西的時間問題,遲早問題,或者這就是技術人的通病,自己技術厲害了,就XXXXXX!!!
如有不對的地方,歡迎大家拍磚o(∩_∩)o 哈哈