简介
一些数据存储的基础知识
在sql server中,数据的存储以页为单位。八个页为一个区。一页为8k,一个区为64k,这个意味着1m的空间可以容纳16个区。如图1所示:
图1.sql server中的页和区
如图1(ps:发现用windows自带的画图程序画博客中的图片也不错)可以看出,sql server中的分配单元分为三种,分别为存储行内数据的in_row_data,存储lob对象的lob_data,存储溢出数据的row_overflow_data。下面我们通过一个更具体的例子来理解这三种分配单元。
我建立如图2所示的表。
图2.测试表
图3.超过8060字节的行所分配的页
数据类型的选择
在了解了一些基础知识之后。我们知道sql server读取数据是以页为单位,更少的页不仅仅意味着更少的io,还有更少的内存和cpu资源消耗。所以对于数据选择的主旨是:
尽量使得每行的大小更小
这个听起来非常简单,但实际上还需要对sql server的数据类型有更多的了解。
比如存储int类型的数据,按照业务规则,能用int就不用bigint,能用smallint就不用int,能用tinyint就不用smallint。
所以为了使每行的数据更小,则使用占字节最小的数据类型。
1、比如不要使用datetime类型,而根据业务使用更精确的类型,如下表:
2、使用varchar(max),nvarchar(max),varbinary(max)来代替text,ntext和image类型
根据前面的基础知识可以知道,对于text,ntext和image类型来说,每一列只要不为null,即使占用很小的数据,也需要额外分配一个lob页,这无疑占用了更多的页。而对于varchar(max)等数据类型来说,当数据量很小的时候,存在in-row-data中就能满足要求,而不用额外的lob页,只有当数据溢出时,才会额外分配lob页,除此之外,varchar(max)等类型支持字符串操作函数比如:
● col_length
● charindex
● patindex
● len
● datalength
● substring
3、对于仅仅存储数字的列,使用数字类型而不是varchar等。
因为数字类型占用更小的存储空间。比如存储123456789使用int类型只需要4个字节,而使用varchar就需要9个字节(这还不包括varchar还需要占用4个字节记录长度)。
4、如果没有必要,不要使用nvarchar,nchar等以“字”为单位存储的数据类型。这类数据类型相比varchar或是char需要更多的存储空间。
5、关于char和varchar的选择
这类比较其实有一些了。如果懒得记忆,大多数情况下使用varchar都是正确的选择。我们知道varchar所占用的存储空间由其存储的内容决定,而char所占用的存储空间由定义其的长度决定。因此char的长度无论存储多少数据,都会占用其定义的空间。所以如果列存储着像邮政编码这样的固定长度的数据,选择char吧,否则选择varchar会比较好。除此之外,varchar相比char要多占用几个字节存储其长度,下面我们来做个简单的实验。
首先我们建立表,这个表中只有两个列,一个int类型的列,另一个类型定义为char(5),向其中插入两条测试数据,然后通过dbcc page来查看其页内结构,如图4所示。
图4.使用char(5)类型,每行所占的空间为16字节
下面我们再来看改为varchar(5),此时的页信息,如图5所示。
图5.varchar(5),每行所占用的空间为20字节
因此可以看出,varchar需要额外4个字节来记录其内容长度。因此,当实际列存储的内容长度小于5字节时,使用char而不是varchar会更节省空间。
关于null的使用
关于null的使用也是略有争议。有些人建议不要允许null,全部设置成not null+default。这样做是由于sql server比较时就不会使用三值逻辑(true,false,unknown),而使用二值逻辑(true,false),并且查询的时候也不再需要isnull函数来替换null值。
但这也引出了一些问题,比如聚合函数的时候,null值是不参与运算的,而使用not null+default这个值就需要做排除处理。
因此null的使用还需要按照具体的业务来看。
考虑使用稀疏列(sparse)
稀疏列是对 null 值采用优化的存储方式的普通列。 稀疏列减少了 null 值的空间需求,但代价是检索非 null 值的开销增加。 当至少能够节省 20% 到 40% 的空间时,才应考虑使用稀疏列。
稀疏列在ssms中的设置如图6所示。
图6.稀疏列
对于主键的选择
总结
本篇文章对于设计表时,数据列的选择进行了一些探寻。好的表设计不仅仅是能满足业务需求,还能够满足对性能的优化。
====================================分割线================================
最新内容请见作者的github页:http://qaseven.github.io/