SQL Server誤區(qū)30日談 第6天 有關(guān)NULL位圖的三個(gè)誤區(qū)
更新時(shí)間:2013年01月09日 19:18:29 作者:
NULL位圖是為了確定行中的哪一列是NULL值,哪一列不是。這樣做的目的是當(dāng)Select語(yǔ)句后包含存在NULL值的列時(shí),避免了存儲(chǔ)引擎去讀所有的行來(lái)查看是否是NULL,從而提升了性能
這樣還能減少CPU緩存命中失效的問(wèn)題(點(diǎn)擊這個(gè)鏈接來(lái)查看CPU的緩存是如何工作的以及MESI協(xié)議)。下面讓我們來(lái)揭穿三個(gè)有關(guān)NULL位圖的普遍誤區(qū)。
誤區(qū) #6a:NULL位圖并不是任何時(shí)候都會(huì)用到
正確
就算表中不存在允許NULL的列,NULL位圖對(duì)于數(shù)據(jù)行來(lái)說(shuō)會(huì)一直存在(數(shù)據(jù)行指的是堆或是聚集索引的葉子節(jié)點(diǎn))。但對(duì)于索引行來(lái)說(shuō)(所謂的索引行也就是聚集索引和非聚集索引的非葉子節(jié)點(diǎn)以及非聚集索引的葉子節(jié)點(diǎn))NULL位圖就不是一直有效了。
下面這條語(yǔ)句可以有效的證明這一點(diǎn):
CREATE TABLE NullTest (c1 INT NOT NULL);
CREATE NONCLUSTERED INDEX
NullTest_NC ON NullTest (c1);
GO
INSERT INTO NullTest VALUES (1);
GO
EXEC sp_allocationMetadata 'NullTest';
GO
你可以通過(guò)我的博文:Inside The Storage Engine: sp_AllocationMetadata - putting undocumented system catalog views to work.來(lái)獲得sp_allocationMetadata 的實(shí)現(xiàn)腳本。
DBCC TRACEON (3604);
DBCC PAGE (foo, 1, 152, 3); -- page ID from SP output
where Index ID = 0
DBCC PAGE (foo, 1, 154, 1); -- page ID from SP output
where Index ID = 2
GO
首先讓我們來(lái)看堆上這頁(yè)Dump出來(lái)的結(jié)果
Slot 0 Offset 0x60 Length 11
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Memory Dump
@0x685DC060
再來(lái)看非聚集索引上的一頁(yè)Dump出來(lái)的結(jié)果:
Slot 0, Offset 0x60, Length 13, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = <<<<<<<
No null bitmap Memory Dump @0x685DC060
誤區(qū) #6b: NULL位圖僅僅被用于可空列
錯(cuò)誤
當(dāng)NULL位圖存在時(shí),NULL位圖會(huì)給記錄中的每一列對(duì)應(yīng)一位,但是數(shù)據(jù)庫(kù)中最小的單位是字節(jié),所以為了向上取整到字節(jié),NULL位圖的位數(shù)可能會(huì)比列數(shù)要多。對(duì)于這個(gè)問(wèn)題.我已經(jīng)有一篇博文對(duì)此進(jìn)行概述,請(qǐng)看:Misconceptions around null bitmap size.
誤區(qū) #6c:給表中添加額外一列時(shí)會(huì)立即導(dǎo)致SQL Server對(duì)表中數(shù)據(jù)的修改
錯(cuò)誤
只有向表中新添加的列是帶默認(rèn)值,且默認(rèn)值不是NULL時(shí),才會(huì)立即導(dǎo)致SQL Server對(duì)數(shù)據(jù)條目進(jìn)行修改??傊?,SQL Server存儲(chǔ)引擎會(huì)記錄一個(gè)或多個(gè)新添加的列并沒(méi)有反映在數(shù)據(jù)記錄中。關(guān)于這點(diǎn),我有一篇博文更加深入的對(duì)此進(jìn)行了闡述:Misconceptions around adding columns to a table.
誤區(qū) #6a:NULL位圖并不是任何時(shí)候都會(huì)用到
正確
就算表中不存在允許NULL的列,NULL位圖對(duì)于數(shù)據(jù)行來(lái)說(shuō)會(huì)一直存在(數(shù)據(jù)行指的是堆或是聚集索引的葉子節(jié)點(diǎn))。但對(duì)于索引行來(lái)說(shuō)(所謂的索引行也就是聚集索引和非聚集索引的非葉子節(jié)點(diǎn)以及非聚集索引的葉子節(jié)點(diǎn))NULL位圖就不是一直有效了。
下面這條語(yǔ)句可以有效的證明這一點(diǎn):
復(fù)制代碼 代碼如下:
CREATE TABLE NullTest (c1 INT NOT NULL);
CREATE NONCLUSTERED INDEX
NullTest_NC ON NullTest (c1);
GO
INSERT INTO NullTest VALUES (1);
GO
EXEC sp_allocationMetadata 'NullTest';
GO
你可以通過(guò)我的博文:Inside The Storage Engine: sp_AllocationMetadata - putting undocumented system catalog views to work.來(lái)獲得sp_allocationMetadata 的實(shí)現(xiàn)腳本。
讓我們通過(guò)下面的script來(lái)分別查看在堆上的頁(yè)和非聚集索引上的頁(yè):
復(fù)制代碼 代碼如下:
DBCC TRACEON (3604);
DBCC PAGE (foo, 1, 152, 3); -- page ID from SP output
where Index ID = 0
DBCC PAGE (foo, 1, 154, 1); -- page ID from SP output
where Index ID = 2
GO
首先讓我們來(lái)看堆上這頁(yè)Dump出來(lái)的結(jié)果
復(fù)制代碼 代碼如下:
Slot 0 Offset 0x60 Length 11
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Memory Dump
@0x685DC060
再來(lái)看非聚集索引上的一頁(yè)Dump出來(lái)的結(jié)果:
復(fù)制代碼 代碼如下:
Slot 0, Offset 0x60, Length 13, DumpStyle BYTE
Record Type = INDEX_RECORD Record Attributes = <<<<<<<
No null bitmap Memory Dump @0x685DC060
誤區(qū) #6b: NULL位圖僅僅被用于可空列
錯(cuò)誤
當(dāng)NULL位圖存在時(shí),NULL位圖會(huì)給記錄中的每一列對(duì)應(yīng)一位,但是數(shù)據(jù)庫(kù)中最小的單位是字節(jié),所以為了向上取整到字節(jié),NULL位圖的位數(shù)可能會(huì)比列數(shù)要多。對(duì)于這個(gè)問(wèn)題.我已經(jīng)有一篇博文對(duì)此進(jìn)行概述,請(qǐng)看:Misconceptions around null bitmap size.
誤區(qū) #6c:給表中添加額外一列時(shí)會(huì)立即導(dǎo)致SQL Server對(duì)表中數(shù)據(jù)的修改
錯(cuò)誤
只有向表中新添加的列是帶默認(rèn)值,且默認(rèn)值不是NULL時(shí),才會(huì)立即導(dǎo)致SQL Server對(duì)數(shù)據(jù)條目進(jìn)行修改??傊?,SQL Server存儲(chǔ)引擎會(huì)記錄一個(gè)或多個(gè)新添加的列并沒(méi)有反映在數(shù)據(jù)記錄中。關(guān)于這點(diǎn),我有一篇博文更加深入的對(duì)此進(jìn)行了闡述:Misconceptions around adding columns to a table.
相關(guān)文章
sql語(yǔ)句中單引號(hào)嵌套問(wèn)題(一定要避免直接嵌套)
直接嵌套肯定是不行的,java中用反斜杠做轉(zhuǎn)義符也是不行的,在sql中是用單引號(hào)來(lái)做轉(zhuǎn)義符的2014-09-09
實(shí)例理解SQL中truncate和delete的區(qū)別
這篇文章主要介紹了實(shí)例理解SQL中truncate和delete的區(qū)別,truncate和delete兩者易混,本文就為大家進(jìn)行區(qū)分兩者的異同,感興趣的小伙伴們可以參考一下2016-02-02
SQL2005、SQL2008允許遠(yuǎn)程連接的配置說(shuō)明(附配置圖)
這篇文章主要介紹了SQL2005、SQL2008允許遠(yuǎn)程連接的配置過(guò)程,需要的朋友可以參考下2015-08-08
SQL Server 游標(biāo)語(yǔ)句 聲明/打開(kāi)/循環(huán)實(shí)例
游標(biāo)屬于行級(jí)操作 消耗很大 SQL查詢(xún)是基于數(shù)據(jù)集的所以一般查詢(xún)能有 能用數(shù)據(jù)集 就用數(shù)據(jù)集 別用游標(biāo) 數(shù)據(jù)量大 是性能殺手2013-04-04
數(shù)據(jù)庫(kù)設(shè)計(jì)三大范式簡(jiǎn)析
這篇文章主要介紹了數(shù)據(jù)庫(kù)設(shè)計(jì)三大范式簡(jiǎn)析,遵循范式是為了建立冗余較小、結(jié)構(gòu)合理的數(shù)據(jù)庫(kù),需要學(xué)習(xí)數(shù)據(jù)庫(kù)設(shè)計(jì)三大范式的朋友可以參考下2015-08-08
SQL Server Management Studio(SSMS)復(fù)制數(shù)據(jù)庫(kù)的方法
這篇文章主要為大家詳細(xì)介紹了如何利用SQL Server Management Studio復(fù)制數(shù)據(jù)庫(kù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03

