关于数据存储类型的一点分析

关于数据存储类型的一点分析

简介

    SQL Server每个表中各列的数据类型的有各种形式,产生的效果也各有不同,我们主要根据效率兼顾性能的情况下讨论下如何规定类型。

    在SQL Server中,数据的存储以页为单位。八个页为一个区。一页为8K,一个区为64K,这个意味着1M的空间可以容纳16个区。       SQL Server中的分配单元分为三种,分别为存储行内数据的In_Row_Data,存储Lob对象的LOB_Data,存储溢出数据的Row_Overflow_data。下面我们通过一个更具体的例子来理解这三种分配单元。

    我建立如图2所示的表。

image

    图2.测试表

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

image

    图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所示。

 image
    图4.使用char(5)类型,每行所占的空间为16字节

    下面我们再来看改为Varchar(5),此时的页信息,如图5所示。

image

    图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所示。

image

    图6.稀疏列

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

对于主键的选择

     对于主键的选择是表设计的重中之重,因为主键不仅关系到业务模型,更关系到对表数据操作的的效率(因为主键会处于B树的非叶子节点中,对树的高度的影响最多)。这个我们得结合主键索引的选择来具体分析,之前写过一篇关于索引的,以后有需要再进一步延伸来讲

总结

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119627.html原文链接:https://javaforall.net

(0)
上一篇 2021年11月27日 下午9:00
下一篇 2021年11月27日 下午10:00


相关推荐

  • 系统架构师(1)计算机组成与结构[通俗易懂]

    系统架构师(1)计算机组成与结构[通俗易懂]1.计算机硬件组成计算机得硬件基本系统由五大部分组成运算器、控制器、存储器、输入设备、输出设备存储器分为内部存储器:内存,容量小。特点是速度快,临时存放数据。外部存储器:硬盘,光盘。特点是容量大,速度慢,能长期存储数据。输入设备:键盘、鼠标。输出设备:音响、显示器。主机:CPU+主存储器…

    2022年5月30日
    84
  • 聊聊Dotnetty

    聊聊Dotnetty以前 我曾经写过一个 C S 的期货交易系统 C S 就绕不开通信 我大概的了解了 net 的通信机制后 选择用 TCP 长连接实现了通信 客户端可以调用服务器端 服务器端可以主动推送消息到客户端 实现是实现了 但是代码笨重而且低效 近来又要解决一个 C S 的通信问题 感觉到自己以前写的通信继续复用会触犯自己的洁癖 同时深感自己的精力大不如以前 重新写一个优雅而且高效的通信的中间件没有任何信心 于是就在网络上

    2026年3月19日
    3
  • CNCF开源项目概述

    CNCF开源项目概述目录 CNCF 简介 KubernetesEn 需求背景 EnvoyProxy 简介 CoreDNS 简介架构原理 TUF 简介 Jaeger 简介架构 Vitess 简介 etcd 简介应用场景 NATS 简介使用场景 CloudEventsP 简介监控的目标与常见监控系统比较常用的监控系统的不足 Prometheus 的优势 gRPCgRPC 简介什么是 RPC 特性基于 HTTP 2IDL 使用 ProtoBuf 多语言支持 C C Pytho

    2026年3月17日
    2
  • jQuery数据类型总结建议收藏

    jQuery除了包含原生JS中的内置数据类型(built-indatatype),还包括一些扩展的数据类型(virtualtypes),如Selectors、Events等。1.StringS

    2021年12月21日
    38
  • 如何求最长回文子串

    如何求最长回文子串回文字符串,就是像“12321”这种轴对称形式的字符串,系不系很简单呀(狗头)。但并不是所有的字符串都是这种整个串都是回文串的。有些计算机问题就是在一个字符串中找出一段最长的回文字符子串,这个时候时候,我们会很自然的想到一种暴力的方法来解决。1975年,一位叫Manacher的人发明了一个算法,这个算法是用来查找一个字符串的最长回文子串的方法。…

    2022年5月8日
    55
  • Java中高级工程师面试题及答案,Java面试题及答案汇总(二

    Java中高级工程师面试题及答案,Java面试题及答案汇总(二需要注意Jdk1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)24.说一下HashSet的实现原理?HashSet底层由HashMap实现HashSet的值存放于HashMap的key上HashMap的value统一为PRESENT25.ArrayList和LinkedList的区别是什么?最明显的区别是ArrrayList底层的数据结构是数组,支持随机访问,而Linke

    2022年5月11日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号