`
yiheng
  • 浏览: 156770 次
社区版块
存档分类

对于表列数据类型选择的一点思考

 
阅读更多

简介

SQL Server每个表中各列的数据类型的选择通常显得很简单,但是对于具体数据类型的选择的不同对性能的影响还是略有差别。本篇文章对SQL Server表列数据类型的选择进行一些探索。

一些数据存储的基础知识

在SQL Server中,数据的存储以页为单位。八个页为一个区。一页为8K,一个区为64K,这个意味着1M的空间可以容纳16个区。如图1所示:

1

图1.SQL Server中的页和区

如图1(PS:发现用windows自带的画图程序画博客中的图片也不错微笑)可以看出,SQL Server中的分配单元分为三种,分别为存储行内数据的In_Row_Data,存储Lob对象的LOB_Data,存储溢出数据的Row_Overflow_data。下面我们通过一个更具体的例子来理解这三种分配单元。

我建立如图2所示的表。

2

图2.测试表

图2的测试表不难看出,通过插入数据使得每一行的长度会超过每页所能容纳的最大长度8060字节。使得不仅产生了行溢出(Row_Overflow_Data),还需要存储LOB的页.测试的插入语句和通过DBCC IND看到的分配情况如图3所示。

3

图3.超过8060字节的行所分配的页

除去IAM页,这1行数据所需要三个页来存储。首先是LOB页,这类是用于存储存在数据库的二进制文件所设计,当这个类型的列出现时,在原有的列会存储一个24字节的指针,而将具体的二进制数据存在LOB页中,除去Text之外,VarBinary(max)也是存在LOB页中的。然后是溢出行,在SQL Server 2000中,一行超过8060字节是不被允许的,在SQL Server 2005之后的版本对这个特性进行了改进,使用Varchar,nvarchar等数据类型时,当行的大小不超过8060字节时,全部存在行内In-row data,当varchar中存储的数据过多使得整行超过8060字节时,会将额外的部分存于Row-overflow data页中,如果update这列使得行大小减少到小于8060字节,则这行又会全部回到in-row data页。

数据类型的选择

在了解了一些基础知识之后。我们知道SQL Server读取数据是以页为单位,更少的页不仅仅意味着更少的IO,还有更少的内存和CPU资源消耗。所以对于数据选择的主旨是:

尽量使得每行的大小更小

这个听起来非常简单,但实际上还需要对SQL Server的数据类型有更多的了解。

比如存储INT类型的数据,按照业务规则,能用INT就不用BIGINT,能用SMALLINT就不用INT,能用TINYINT就不用SMALLINT。

所以为了使每行的数据更小,则使用占字节最小的数据类型。

1.比如不要使用DateTime类型,而根据业务使用更精确的类型,如下表:

类型 所占字节
Date(仅日期) 3
Time(仅时间) 5
DateTime2(时间和日期) 8
DateTimeOffSet(外加时区) 10

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
图4.使用char(5)类型,每行所占的空间为16字节

下面我们再来看改为Varchar(5),此时的页信息,如图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

图6.稀疏列

更具体的稀疏列如何能节省空间,请参看MSDN

对于主键的选择

对于主键的选择是表设计的重中之重,因为主键不仅关系到业务模型,更关系到对表数据操作的的效率(因为主键会处于B树的非叶子节点中,对树的高度的影响最多)。关于主键的选择,我之前已经有一篇文章关于这点:从性能的角度谈SQL Server聚集索引键的选择,这里就不再细说了。

总结

本篇文章对于设计表时,数据列的选择进行了一些探寻。好的表设计不仅仅是能满足业务需求,还能够满足对性能的优化。


分享到:
评论

相关推荐

    2021-2022计算机二级等级考试试题及答案No.1905.docx

    - **知识点解析**:在数据库设计中,使用表设计器定义表时,通常需要指定几个关键属性:字段名称、数据类型、字段属性等。其中,“说明”或“备注”字段虽然有助于提高数据的可读性和维护性,但它并不是创建表时的...

    校园导航系统数据结构课程设计报告书.doc

    - 抽象数据类型:定义了表示建筑节点的结构体`Vertex`,包含建筑名、编号和简介等信息。 - 主程序流程:初始化系统,调用初始化函数和地图展示函数,根据用户输入调用相应功能,如最短路径计算或信息查询,最后...

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    12.1.2 列的选择 337 12.1.3 空值问题 338 12.2 索引结构类型 339 12.2.1 B-树索引 339 12.2.2 位图索引 340 12.2.3 索引组织表 341 12.3 分区索引 343 12.3.1 局部索引 343 12.3.2 全局索引 345 12.3.3 ...

    ggplot2:数据分析与图形艺术

    , 从始至终,数据分析者都在数据层面上思考问题,而不是拿着水彩笔和调色板在那里一笔一划作图,而计算机程序员则倾向于画点画线。Leland Wilkinson的著作在理论上改善了这种状况,他提出了一套图形语法,让我们在...

    MISRA-C-2004_工业标准的C编程规范_中文版

    MISRA-C针对C语言的基本特性进行了详细说明,包括但不限于数据类型、变量声明、表达式处理等。 **3.2 未指出的问题** MISRA-C还关注了一些通常被忽略的问题,如不常用的数据类型、边缘情况处理等。 **3.3 可应用...

    ds4ds_2015:数据科学2015的数据结构幻灯片

    这些幻灯片Swift地放在一起以强调一个观点:对于类似数据框的事物,我们应该从元组或向量的操作中抽象出存储模型的角度来考虑开发人员API。 我希望能够插入新的数组/列压缩类型并使这些列上的操作“有效”。 大约十...

    2021年薪酬报告系列之珠三角地区生产管理部门岗位薪酬水平报告.pdf .pdf

    从提供的文件内容中,我们可以提取以下有关珠三角地区生产...以上知识点不仅涵盖了珠三角地区生产管理部门岗位薪酬水平的细节,还包括了对行业报告的深入解读、数据分析方法以及如何将这些数据应用到实际场景中的思考。

    MongoDB的ruby 教程,太搞了

    此外,内容中还隐含了作者对于“为什么构建MongoDB”这一问题的思考,尽管没有直接给出答案,但我们可以推测MongoDB被构建出来是为了填补当时数据库领域中某些需求的空缺,可能是为了提供一种新的存储解决方案,或者...

    非常实用的毕业答辩模板PPT答辩 (164).pptx

    毕业论文答辩是学术生涯中的一个重要环节,它不仅是对学术成果的展示,也是对学生独立思考和表达能力的检验。一份精心制作的答辩PPT可以帮助毕业生更有效地传达研究成果,增强评委和听众的理解,从而提高答辩的成功...

    北师大版小学一年级数学(下册)第五单元测试卷与答案.docx

    7. **数据收集与整理**:基础的数据统计,比如通过画图或者列图表的方式来收集和整理数据,理解数据的初步概念,如最多、最少、一样多等。 测试卷通常会设计各种类型的题目来检验这些知识点的掌握程度,包括选择题...

    2022届高考数学统考一轮复习第10章计数原理概率随机变量及其分布第5节离散型随机变量及其分布列教师用书教案理新人教版202103081183

    理解并掌握这一点对于正确构建和理解分布列至关重要。 在实际应用中,随机变量的分布列能够反映随机事件发生的可能性,因此在分析和预测中扮演着重要角色。两点分布是离散型随机变量分布中的一种特殊情况,它描述的...

    华为编程开发规范与案例

    6、注意数据类型的匹配 第18页 【案例1.6.1】 第18页 【案例1.6.2】 第18页 7、用于控制条件转移的表达式及取值范围是否书写正确 第20页 【案例1.7.1】 第20页 【案例1.7.2】 第21页 【案例1.7.3】 第22页 8、条件...

    算法技术手册(Algorithms in Nutshell)英文版

    - **最后一点**(Section 2.7 One Final Point):总结本章的关键概念,并提出一些额外思考的问题。 - **参考文献**(Section 2.8 References):列出本章中引用的研究论文、书籍和其他资源。 #### 三、模式与...

    C++中级,讲述了一些很有用的东西

    比如`int`表示整型数据类型。通过对`int`、`float`、`char`等关键字的共性进行抽象,我们可以得到一个更为通用的概念。 **2. 抽象的步骤** - **归纳**:确定被分析的目标有哪些。 - **罗列**:列出每个目标的性质...

    操作系统的实现

    **3.2.5 关于“保护”二字的一点思考** 这部分内容反思了保护模式的设计理念,探讨了它对现代操作系统发展的重要意义。 **3.3 页式存储** 页式存储是保护模式下另一种重要的内存管理方式,它可以提高内存使用的...

    算法艺术与信息学竞赛 部分习题提示

    理解这一点对于优化算法性能至关重要。 #### 1.2 节习题 **1.2.1** 此题讨论了枚举法的应用及其效率问题。题目指出,在某些情况下,枚举法可能不是最佳选择,其效率取决于枚举的数量和所需的时间。这提醒我们在...

    NEC部分笔试题(软件工程师应聘)

    ### NEC部分笔试题解析(软件工程师应聘) ...综上所述,这些题目旨在考察应聘者在面对不同类型的逻辑题时的思考方式和解决问题的能力。通过这些练习,可以帮助应聘者更好地准备面试,并提高解决问题的技巧。

    制作Powerpoint的学习资料,对初学者及提升者很有帮助

    在开始设计演示文稿之前,至关重要的一点是理解你的听众。听众的特性和偏好直接影响到他们接收信息的方式以及对你演讲内容的关注度。根据不同的性格类型,可以将听众大致分为以下几类: 1. **性格类型**:外向型与...

    四年级下册数学期末测试卷(全国通用)word版.docx

    ### 一、选择题知识点 #### 1. 图形路径比较 - **知识点**: 两点间直线段最短。 - **解析**: 题目通过小狗吃骨头的情境引出了路径长短的比较问题,旨在考察学生对于“两点之间线段最短”这一几何学基本原则的理解。...

Global site tag (gtag.js) - Google Analytics