vlambda博客
学习文章列表

Mysql中级(三):Schema 与数据库类型优化

本章内容是为接下来两个章节做铺垫,在这三张章中,我们讨论逻辑设计,物理设计和查询执行,以及他们的相互作用

选择优化的数据类型

Mysql中支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要,不管存储那种数据类型,以下几个原则都有助于做出更好的选择

  1. 更小的通常更好,一般情况下,应该使用正确存储数据的最小数据类型,更小的数据类型通常占用更少的磁盘和内存,并且处理时需要的CPU周期也最小
  2. 简单就好,简单的数据类型通常需要更少的CPU周期,例如整形比字符操作代价更低,举两个例子,一般用Mysql自带的date来处理日期,以及存储IP地址应该使用整形
  3. 尽量避免使用NULL,通常情况下,最好指定列为NOT NULL,除非真的需要存储NULL值

整数类型

整数类型有TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT.分别使用8,24,32,64位存储空间,他们可以存储的范围从

-2^{(n-1)} ~ 2^{(n-1)}

Mysql可以整数型指定宽度,例如INT(11),对大多数应用而言是没有意义的,他不会限制合法的范围,例如 INT(1) 和 INT(20) 是相同的

实数类型

  • Float使用四个字节存储
  • Double使用8个字节存储
  • DeCIMAL使用65个数字,但是在实际的计算过程中会转换为Double类型

在对数字要求精度比较高的时候,例如财务数据,可以考虑用BigInt代替Decimal只需要将存储的最小货币单位乘以相应的倍数即可,例如假设财务数据需要精确到万分之一分,可以把所有的金额乘以1百万,然后将结果存储在BigInt中,这样可以同时避免浮点计算不精确和Decimal计算昂贵的问题。

字符串类型

  • char :类型是定长的,适合存储很短的字符串,比如存储密码的MD5值,因为定长的char类型不容易产生碎片,对于非常短的列,存储空间上效率比varchar的要高
  • varchar:用于存储可变长字符串,他比定长类型更省空间,同时varchar对性能也有帮助

慷慨是不明智的 使用varchar(5)和varchar(200) 存储Hello的空间开销是一样的,那么使用短的列有什么优势吗?

事实证明优势还是挺大的,更长的列会消耗更多的内存,因为Mysql通常会分配固定大小的内存块来保存内部值,尤其是在使用内存临时表进行排序操作时会变得特别糟糕,利用磁盘临时表进行排序的时候也同样糟糕,最好的策略是分配真正需要的空间

日期类型

DATETIME和TIMESTAMP都可以用来存储时间类型,但是TIMESTAMP只使用DATETIME一半的存储空间,并且会根据时区变化,但是TIMESTAMP允许的时间范围要小很多。

  • DateTime 这个类型能保存大范围的值,从1001到9999,精度为秒,他把日期格式封装在YYYYMMDDHHMMSS的整数中,与时区无关
  • Timestamp 保存了从1970年1月1日午夜以来的秒数据,他和unix的时间戳是相同的,但是他的范围要比DateTime小得多,只能表示1970年到2038年,TimeStamp默认的列not null,除特殊情况外,通常也应该尽量使用TimeStamp,因为他的空间使用效率更高,

位数据类型

Bit 和 set bit 和set 这两种数据类型一般需要谨慎使用,对于大部分的应用,应当最好避免使用这种类型。如果需要在bit的存储空间中存储一个ture/false值,那么可以创建一个为空的char(0),该列可以保存为空值或者长度为0的字符串

选择标识符

为标识符选择合适的数据类型非常重要,也就是主键的选择,通常整数是标识列最好的选择,因为他们可以很快并且可以使用Auto_Increment

字符串类型,如果可能,应当避免使用字符串类型作为标识列,因为他们非常耗空间,并且通常比数字慢

Mysql中设计中的缺陷

Mysql schema设计中的缺陷:

  1. 太多的列:Mysql存储引擎API工作时需要在服务器层和存储引擎之间通过缓冲格式拷贝数据,然后再服务器层将缓存内容解码成各个列,从行缓冲中将编码过的列转化为行数据结构的代价非常高。
  2. 太多的关联:Mysql限制了每个关联操作最多只能有61张表,因为EAV数据库需要许多自关联。如果需要查询执行得非常快速且并发性非常好,单个查询关联最好在12张表以内
  3. 全能枚举:注意防止过度枚举的情况,过度枚举是一个有问题的设计方案

总结

良好的schema设计原则是普遍适用的,但是Mysql由他自己的实现细节,Mysql喜欢简单的,需要使用数据库的人应该也是喜欢简单的原则

  • 避免过度设计,例如会导致极其复杂的查询的schema设计,或者有很多列的表设计
  • 适用小而简单的合适的数据类型,除非真实数据模型确实有确切的需要,否则应当避免使用NULL
  • 尽量使用相同的数据类型存储相似的或相关的值,尤其是在关联条件下使用的列
  • 注意可变长的字符串,尤其是在临时表和排序时会导致悲观的按照最大长度分配的内存
  • 尽量使用整数定义标识列
  • 比秒使用Mysql已经遗弃的特性,例如指定浮点数精度,或者整数显示宽度
  • 小心使用枚举ENUM和SET,虽然他们使用很方便,但是不要滥用否则有时候会变成陷阱,最好避免使用BIT