h0945634 发表于 2015-6-28 15:36:05

《Microsoft Sql server 2008 Internals》读书笔记--第五章Table(6)

  
  《Microsoft Sql server 2008 Internals》读书笔记订阅地址:
  http://www.iyunv.com/downmoon/category/230397.html/rss
  《Microsoft Sql server 2008 Internals》索引目录:
  《Microsoft Sql server 2008 Internal》读书笔记--目录索引
  
  上篇文章中提到五种典型的存储结构:一、固定长度的行;二、可变长度的行;三、Null和可变长度列;四、时间和日期数据;五、SQL_variant 数据。今天我们继续来看可变长度的行的存储:可变长度的列要比固定长度的列的存储复杂一些。
  我们先来测试一个表Variable,有三个variable 列和两个固定长度列:


CREATETABLE variable
(
Col1 char(3)       NOTNULL,
Col2 varchar(250)NOTNULL,
Col3 varchar(5)    NULL,
Col4 varchar(20)   NOTNULL,
Col5 smallintNULL
);
SELECTobject_id,type_desc,
    indexproperty(object_id, name, 'minlen') as minlen
    FROM sys.indexes whereobject_id=object_id('variable');

SELECTname, column_id, max_inrow_length, pc.system_type_id, leaf_offset
FROM sys.system_internals_partition_columns pc
    JOIN sys.partitions p
          ON p.partition_id = pc.partition_id
    JOIN sys.columns c
         ON column_id = partition_column_id AND c.object_id= p.object_id
WHERE p.object_id=object_id('variable');   可以看到:
http://public.blu.livefilestore.com/y1pt4_rjTM6abNjKWO9Ee1JrZOmIXoZULe7COVRIydxMY6cD2mLt0QgOpyBoQOLGkAvDTMuM-QpdbD7a_j7b20ovA/2010-02-01%2013-29-54.png
  现在,插入一行数据:


INSERT variable VALUES('AAA', REPLICATE('X', 250), NULL, 'ABC', 123);  说明:REPLICATE函数仅仅填充了250个X到col2,很有用的一个函数哟,特别在填充测试数据的时候。
  我们可以按照前一篇所述的方法来查看data pages的存储状况:
http://public.blu.livefilestore.com/y1p_u4FCZhS1EYDDN0-HLxGLmrQIFn32TPHTvWDzuz9fbgbEyGGuNdZ_xuqIwGgfHQ00EFjOow6tJ4kC5NiYH5Baw/2010-02-01%2013-41-02.png
  简要说明:
  1、还记得前面学过的存放顺序吗?先固定列,再可变列。所以Col1和Col5要先存储,并且偏移量为正值,而col2\Col3\col4偏移量分别是-1,-2,-3。正好表示它们分别是可变列的第一、第二、第三个序号。
  2、0500表示该行有5列。
  3、04代表null Bitmap没有使用。
  4、0300代表共有三个可变长度的列。
  5、0e01代表第一个可变列的结束位置,与第二个可变列的位置相同。这是为什么呢?可能有人猜出来了,因为插入的是Null,所以实际上并没有数据存储到行中。这与固定长度的行不同。固定长度的行,Null值也占用存储空间。
  6、该行数据的总长度为273字节,计算方法是0X1101,经过字节换算,应该是0X0111=273
  那么,存储这行数据到底用去多少空间呢?可变长度列意味着更大的开销(overhead),它们的实际长度是无法预测的。即便对于固定长度的列,开销的数量也会取决于表中列的数量。记住:Null bitmap必须有足够的空间来存放每列的bit值。此外,每行还必须包含2个字节overhead和行底部的行偏移量数组
  再来看第三种存储:Null和可变长度列
  可能,有人看了上面的图会说,可变长度的列既然并不存放实际数据,那么应该不会占用空间。可为什么每个可变列还是有2个字节的偏移呢?这个-2是从哪儿来的呢?
  因此,我们不能说SQL Server一点空间也不用。实际上,它仍然用了两个字节来存放了偏移数组。我们看一个例子:


CREATETABLE dbo.null_varchar
    (
      id INTPRIMARYKEYIDENTITY(1,1),
      col1 VARCHAR(10) NULL,
      col2 VARCHAR(10) NULL,
      col3 VARCHAR(10) NULL,
      col4 VARCHAR(10) NULL,
      col5 VARCHAR(10) NULL,
      col6 VARCHAR(10) NULL,
      col7 VARCHAR(10) NULL,
      col8 VARCHAR(10) NULL,
      col9 VARCHAR(10) NULL,
      col10 VARCHAR(10) NULL
    );
GO
SET NOCOUNT ON
INSERTINTO null_varchar(col10)
   SELECT'a';
INSERTINTO null_varchar(col1)
   SELECT'b';
INSERTINTO null_varchar
   SELECT'','','','','','','','','','c';
INSERTINTO null_varchar
   SELECT'd','','','','','','','','','';
GOhttp://public.blu.livefilestore.com/y1pxEpdEAY1QPxwgRsouUD6UibDXQLTLuwJURvnBfGlYLt12PQkO9gdmgyy7OkpxosGT3n220Ws1weFT0hHWmH_gQ/2010-02-01%2014-45-20.png
  从红色部分显示,0x03fe意味着0000001111111110,从右往左看,第一列是not Null,第10列是not Null,其余列是Null。共11列,后5列被忽略了。
  同理:0x07fc意味着0000011111111100,从右往左看,第一列和第二列是not Null,其余列是Null。
  第四种存储方式:日期和时间格式


CREATETABLE times (
    a char(1),
    dt1 datetime,
    b char(1),
    sd smalldatetime,
    c char(1),
    dt2 datetime2,
    d char(1),
    dt date,
    e char(1),
    dto datetimeoffset,
    f char(1),
    t time,
    g char(1),
    t0 time(0),
    h char(1),
    t1 time(1),
    i char(1),
    t2 time(2),
    j char(1),
    t3 time(3),
    k char(1),
    t4 time(4),
    l char(1),
    t5 time(5),
    m char(1),
    t6 time(6),
    n char(1),
    t7 time(7));
GO

INSERTINTO times
SELECT
    'a', '01:02:03.123',
    'b', '01:02:03.123',
    'c', '01:02:03.123',
    'd', '01:02:03.123',
    'e', '01:02:03.123',
    'f', '01:02:03.123',
    'g', '01:02:03.123',
    'h', '01:02:03.123',
    'i', '01:02:03.123',
    'j', '01:02:03.123',
    'k', '01:02:03.123',
    'l', '01:02:03.123',
    'm', '01:02:03.123',
    'n', '01:02:03.123';http://public.blu.livefilestore.com/y1pn451SrcSRtkBO5iPtcntYjKqnaSv_sG-8Npt4Iqv45v1LVN-LsHv1VcgS87HO4tMyF46cCDtPxp86mlzAdORMQ/2010-02-01%2015-14-17.png
需要说明的是:
  对于datatime和smalldatetime,存储值为0意味着日期是'1900-01-01",对于其他类型的日期值为693595意味着日期是"0001-01-01"
  你可以通过这个语句查看对应的日期:


SELECTDATEADD(dd, 693595, CAST('0001/1/1'AS datetime2));  结果为默认值:1900-01-01 00:00:00.0000000
  第五种:SQL_variant 数据
  在此略去。
  关于存储行更多的信息,在后面的第七章学习中将继续展开。
  下一节将继续学习列和行的存储相关操作。
页: [1]
查看完整版本: 《Microsoft Sql server 2008 Internals》读书笔记--第五章Table(6)