今天在偶然看到了一篇文章,忽然想起疯子的一个帖子中,一直没有想明白的问题,可能和这个有关系,验证了一下,果然如此。
一、起因:
-- 创建2个测试表
CREATE TABLE [dbo].[Table_2019]([Data] [nchar](2019) NOT NULL) 
CREATE TABLE [dbo].[Table_2020]([Data] [nchar](2020) NOT NULL) 
go
-- 填充数据
declare @i int
set @i = 0
while(@i < 20)
begin
    insert Table_2019(Data) values('')
    insert Table_2020(Data) values('')
    select @i = @i + 1
end
go 
查看每个表所占用的空间,结果:
Table_2020 表数据占了 160kb ,Table_2019 表数据占了 80 kb
二、问题
两张表中的字符长度相差为1,(因为数据类型为nchar,所以数据所占用的空间实际相差为2),但是两张表所占用的空间确相差一倍,原因何在?有图片,csdn上传图片真麻烦,详情参见http://blog.csdn.net/HEROWANG/archive/2009/11/04/4769430.aspx
对于数据行的存储结构,也可以参见JJ的blog:
http://blog.csdn.net/jinjazz/archive/2008/08/07/2783872.aspx

解决方案 »

  1.   

    所占空间最小单位为8K
    所以表中空间并不是全部占用了。
    2020*20*2=80800 也就是80K多一些吧
    这个应该类似是数据存储的最小单位吧。以80为单位.和MSSQL内部具体的数据组织有关了。
      

  2.   

    我感觉这和操作系统文件存储很相似.文件存储的最小单位是一个4KB大小的扇区,如果一个文件就有一个字符,他也是4KB,随着字符的增多,文件并没有即时的增大,当文件增大到4KB装不下的时候,会再申请一个4KB的扇区.数据库文件也是,当数据量增加到一个临界值时,数据库文件的大小会有一个变化过程,但是并不表示数据量就是原先的两倍,只是占用了两倍的空间.
      

  3.   

    经测试:
    2019和2018每添加两条记录表空间加8K
    2020和2021每添加一条记录表空间加8K如21L大大所说确实是分水岭
      

  4.   

    是不是 Table_2020 的字符长度为 1,而 Table_2019的字符长度为 2. 如果是这样,那 Table_2019 不正好是 Table_2020 的2陪..
      

  5.   

    應該是nchar(2020)的 每一行數據 +頁頭信息超過4KB,所以一行占了一頁,而nchar(2019)的 每一行數據 +頁頭信息總大小小于4KB,所以一頁可以容納兩行。可以認為2019和2020是unicode字符類型數據的單頁能否存儲的臨界值。
      

  6.   

    貌似一行數據實際大小+頁組織信息總大小小于8KB而兩行數據實際大小+頁組織信息總大小超過8KB時候,單行占據一頁,所以會浪費存儲空間。
      

  7.   

    SQL Server页定义:
    在 SQL Server 中,页的大小为 8 KB。这意味着 SQL Server 数据库中每 MB 有 128 页。每页的开头是 96 字节的标头,用于存储有关页的系统信息在 SQL Server 2005 中,行不能跨页,但是行的部分可以移出行所在的页,因此行实际可能非常大。页的单个行中的最大数据量和开销是 8,060 字节 (8 KB)。在数据页上,数据行紧接着标头按顺序放置。页的末尾是行偏移表,对于页中的每一行,每个行偏移表都包含一个条目。每个条目记录对应行的第一个字节与页首的距离。行偏移表中的条目的顺序与页中行的顺序相反。
    计算:计算总的行大小:
    Row_Size = Fixed_Data_Size + Variable_Data_Size + Null_Bitmap + 4
    公式中的值 4 是数据行的行标题开销。由于nchar是固定长度,所以Variable_Data_Size=0保留行中称为 Null 位图的部分以管理列的为空性。计算其大小:
    Null_Bitmap = 2 + ((Num_Cols + 7) / 8)
    由于你只有一列,所以Null_Bitmap = 3 由以上原则可以计算:
    nchar(2019): 2019×2+0+3+4=4045
    nchar(2020): 2020×2+0+3+4=4047微软给出的每页容纳行数计算公式:
    计算每页的行数(每页有 8096 个可用字节):
    Rows_Per_Page = 8096 / (Row_Size + 2)
    因为行不跨页,所以每页的行数应向下舍入到最接近的整数。公式中的数值 2 是计算行数时引入的行大小余量。
     
    nchar(2019): 8096/(4045+2)=2.000494193229
    nchar(2020): 8096/(4047+2)=1.999506050876据以上计算,可以得出,一页可以存储只有一列nchar(2019)数据的行数为2行,而存储只有一列nchar(2020)数据的行数为1行。
    所以就出现了你所举例子的情况。
      

  8.   

    SQL 每页(8K)能放2条NCHAR(2019)的记录,只能放一条NCHAR(2020)的记录
    导致NCHAR(2020)的表做成严重浪费。