对于一般的INT、CHAR、tinyint等数据 类型 ,他们占用的 存储 空间都是以Byte字节为单位的,但是BIT 类型 由于只有0和1或者说false和true,这种情况只需要一个Bit位就可以表示了,那么在SQL Server中BIT 类型 到底占用了多少空间?是不是由一个Bit位来 存储
对于一般的INT、CHAR、tinyint等数据 类型 ,他们占用的 存储 空间都是以Byte字节为单位的,但是BIT 类型 由于只有0和1或者说false和true,这种情况只需要一个Bit位就可以表示了,那么在SQL Server中BIT 类型 到底占用了多少空间?是不是由一个Bit位来 存储 的?或者可能是使用一个字节来 存储 的?
这两个答案都不正确!实际上 BIT 类型 占用的空间与BIT 类型 的列所在表的位置有关,有些情况下BIT占用了一个字节,有些情况下BIT实际占用了几个位(几个BIT 类型 的列共用一个字节)。下面就来具体分析一下:
1. 单独的BIT 类型 的列将占用一个字节。
所谓单独就是指一个BIT 类型 的列的左边定长列和右边定长列都不是BIT 类型 的列。例如这样一个表:
CREATE TABLE tt
(
c1 INT PRIMARY KEY,
c2 BIT NOT NULL,
c3 CHAR(2) NOT NULL
)
SQL Server 在 存储 表 中的数据时先是将表中的列按照原有顺序分为定长和变长(变长就是长度不固定的数据 类型 ,如varchar,nvarchar,varbinary等)两组。在数据页中 存储 数据时先 存储 所有定长的数据,然后再 存储 变长的数据。这里由于c2列的左边是int 类型 ,右边是char 类型 ,都是定长的,而且不是BIT 类型 ,所以c1和c3之间必须留出一个字节来 存储 c2,虽然c2只用到了其中的一个位。
下面我们来验证一下是否真是如我所说:
(1)插入一行数据 :
INSERT INTO tt VALUES(1,1,'aa')
(2)找到tt表数据的第一页 (也就是刚才插入的这行数据所在页)的文件号和页面号:
SELECT first_page
FROM sys.partitions p
INNER JOIN sys.system_internals_allocation_units a
ON p.partition_id=a.container_id
WHERE OBJECT_ID= OBJECT_ID('dbo.tt')
我这里返回的是0x76 00 00 00 01 00,这里需要反转过来看0x00 01 00 00 00 76。其中前两个字节是文件号,后面的是页面号,所以文件号是1,页面号是118(0x76转换成十进制就是118)
(3)使用DBCC page命令查看该页的内部结构:
DBCC traceon(3604)
DBCC page(TestDB,1,118,3)
这儿DBCC traceon(3604)表示将页面内容直接 输出,TestDB是我创建的tt表所在的数据库,1和118前面已经说了。最后一个是打印选项。0表示只 输出页头;1则不会 输出所有内容,只是 输出有数据的内容;2表示完整的 输出这个页的内容,3则和1差不多,但是要每条记录分别列出列的值。以下是 输出的需要关注的内容:
00000000: 10000b00 01000000 01616103 0000††††††.........aa...
关于数据行的具体格式我就不在这里多说了,在《SQL Server 2005技术内幕 存储 引擎》中有详细介绍。我们插入的数据从第5个字节开始,是01000000 016161。这儿01000000就是c1,由于是int 类型 ,所以占用4个字节。接下来01就是c2,在这里占用了1字节。再接下来6161就是c3了。
2.多个BIT 类型 的列之间使用变长数据 类型 列分开,则去掉变长列,然后看连续的BIT 类型 列的个数,每列占用一个位,如果多余了8列那就再占用更多的字节。 例如创建这样的表:
CREATE TABLE vtt
(
c1 BIT NOT NULL,
c2 VARCHAR(5) NOT NULL,
c3 BIT NOT NULL,
c4 NVARCHAR(5) NULL,
c5 BIT NULL,
c6 INT NOT NULL
)
这里将变长列筛选出来后就变成了c1、c3、c5、c6,有3个BIT 类型 列是连续的,所以c1、c3、c5将公用一个字节。接下来就来验证一下:
(1)插入一条示例数据:
INSERT INTO vtt VALUES(1,'abc',1,N'xyz',0,1023)
(2)用前面用的SQL语句,同样的方法,找出vtt表的第一页为:0xC00000000100,对应的就是文件号1,页号192
(3)查看该页的内部数据:
00000000: 30000900 03ff0300 00060000 02001500 †0. .............
00000010: 1b006162 63780079 007a00†††††††††††††..abcx.y.z.
插入的数据从第5个字节开始03ff…… 这儿03就是c1、c3、c5的数据,03转换成二进制就是00000011。c1列对应最低位1,c3对应倒数第二位1,c5对应倒数第三位0。接下来的ff就是c6的值1023。后面的就是列数、NULL位图、变长列等,这里是讨论BIT位占用空间的,所以就不讲解后面这些了。
3.一个表中有多个BIT 类型 的列,其顺序是否连续决定了BIT位是否可以共享一个字节。SQL Server中按照列顺序 存储 ,第一列和最后一列都是BIT数据 类型 列,不可以共用一个字节。
也就是说下面的表t1和表t2占用的空间是不同的,t1数据占用了7字节,t2数据占用了8字节。
CREATE TABLE t1
(
c1 INT PRIMARY KEY,
c2 BIT NOT NULL,
c3 BIT NOT NULL,
c4 CHAR(2) NOT NULL
)
CREATE TABLE t2
(
c1 INT PRIMARY KEY,
c2 BIT NOT NULL,
c4 CHAR(2) NOT NULL,
c3 BIT NOT NULL
)
但是在下面的t3和t4表中,由于中间是变长数据 类型 ,所以他们的BIT列占用的数据空间是相同的。
CREATE TABLE t3
(
c1 INT NOT NULL,
c2 BIT NOT NULL,
c3 VARCHAR(2) NOT NULL,
c4 BIT NOT NULL
)
CREATE TABLE t4
(
c1 INT NOT NULL,
c2 BIT NOT NULL,
c4 BIT NOT NULL,
c3 VARCHAR(2) NOT NULL
)
查看更多关于BIT类型在SQLServer中的存储大小的详细内容...