Schema数据类型优化

良好的数据路逻辑设计和物理设计是高性能的基石,所以要打造一个高性能的数据库服务,在Schema设计之初就应该需要权衡各种因素。

选择最优化的数据类型

数据库支持的数据类型非常多,选择一个正确的数据类型对于获得高性能至关重要。

选择合适数据类型的几个原则:

  1. 更小的通常更好
    一般情况下,应该尽量使用可以正确数据类型的最小数据类型。但也要确保没有低估需要存储的范围。

  2. 简单就好
    简单的数据类型的操作通常需要更少的CPU周期。例如,

  • 整型比字符串操作代价更低
  • 使用MySQL内建的数据类型(比如,date、time、datetime),比用字符串更快
  • 使用整型存储一个IP地址,比用一个字符串更好
  1. 尽量避免使用NULL
    因为如果在查询中包含有NULL的列,对MySQL来说更难优化。所以通常情况下,最好指定列为 NOT NULL。

TIPS:
datetime和timstamp列都可以存储相同类型的数据(时间和日期,都可以精确到秒),然而timestamp实际只使用datetime一般的存储空间。但另一方面,timestamp允许的时间范围要小的多。

基本的数据类型

  1. 数字
  2. 整数 - TINYINT (8) - SMALLINT (16) - MEDIUMINT (24) - INT (32) - BIGINT (64)
> **TIPS1:** 整数类型有可选的 unsigned 属性,表示不允许有负值,如果将要使用的列不会出现负值的话,加上这个属性,将会可以使正数的上限增加一倍。

> **TIPS2:** int(1)与int(11),对于存储和计算来说,这两者本质是没有区别的;两者只是在MySQL的一些交互工具中略有差别(比如,MySQL命令行客户端,用来控制显示字符的个数)。
  1. 实数 - 作用

    存储小数

    存储比BIGINT更大的数

- float
- double
> float 和 double支持使用标准的浮点运算进行近似的计算。

- decimal
> decimal 类型用于存储精确的小数,支持精确的计算。
>
> 由于CPU不支持对decimal的直接计算,所以对decimal的精确计算是由MySQL服务器自己来实现。
>
> **Tips:** 因为在进行精确计算时需要额外的空间和计算开销,所以尽量只对小数才使用decimal。比如,财务数据。另外如果数据量大的话,可以考虑使用bigint代替decimal,只需将存储的货币单位根据小数的位数乘以相应的倍数即可。
  1. 字符串

  2. CHAR

    char 类型是定长的:MySQL是根据定义的字符串长度分配足够的空间。
    char,适合存储很短的字符串,或者所有值的长度都差不多的的字符串。例如,密码的md5值。
    另外,char还适合存储经常进行变更的值,相比于vachar,char类型很少会产生碎片。所以这一类的列,会比varchar更好。

  3. VARCHAR

    varchar 类型用于存储可变长的字符串。它只使用必要的空间,所以比定长类型更节省空间。

    varchar,需要使用一个或者两个额外的字节来存储当前字符串的长度信息;如果列的长度小于或等于255个字节,则只需要一个字节表示,否则就需要两个字节来表示。

    下面的这些情况适合使用varchar

    1. 字符串列的长度比平均长度大很多
    2. 列的更新很少,所以碎片不是问题
    3. 使用了像UTF-8这样复杂的字符集,因为该字符集中每个字符可能使用不同的字节来进行存储
**Tips:**
用varchar(5)和varchar(200)来存储 「hello」有什么区别?

首先两者在存储空间的开销是一样的。
但是,一般的列在查询时会消耗更多的内存,因为在读到这些列时MySQL通常会分配固定大小的内存块来保存内部值。
尤其在使用内存临时表进行排序或者其他操作时,会特别的糟糕。
所以最好的策略就是,**分配真正需要的空间**。

**Tips:**
字符串长度定义不是字节数,而是字符数。两者概念是不同的,多字节字符集会需要更多的空间存储单个字符。
  1. BLOB和TEXT

    两者都是为存储很大的数据而设计的字符串数据类型,不同的是两者分别采用二进制和字符方式存储。

    MySQL在处理两个类型的值时,处理基本相同,仅有的不同是BLOB类型是以二进制格式来存储的,所以没有排序规则和字符集,而text类型有排序规则和字符集。

  2. 枚举(ENUM)

    枚举可以把一些不重复的字符串存储成一个预定义的集合。
    MySQL会在存储枚举类型时粉肠紧凑,会根据列的值的数量压缩到一个或者两个字节中。
    MySQL会在内部将每个值在列表中的位置保存成整数,而这些『数字–字符串』的对应关系,会保存在 .frm 文件中。
    所以当该列需要新添加一个新的枚举值时,必须添加在之前枚举列表的最后面,否则就会出现数据错乱的问题。切记。

  3. 日期和时间类型

  • DATETIME

    该类型能保存大范围的值,从1001年到9999年,精度为秒。他会把时间封装到YYYYMMDDHHIISS的整数中,没有时区概念。使用8个字节的存储空间。

  • TIMESTAMP

    该类型保存了从1970-01-01 00:00:00(格林威治时间)以来的秒数。该类型使用4个字节的存储空间,所以只能表示1970到2023年,其值还具有时区的概念。

  1. 位数据类型

    存储更紧凑。但所有这些位类型,不管底层存储格式和存储方式,从技术上来说都是字符串类型。虽然用它存储数据更紧凑,但是对于大部分应用来说,最好避免使用该类型。

  • BIT

  • SET

  1. 特殊类型的数据

    某些数据的类型并不直接和内置的类型一致。所以需要一定的转换进行存储。

  • 低于秒级的时间戳

    低于秒级的时间需要在引用层做处理,一般可以通过存储两个或者多个列来存储(一个存储秒级的时间戳,另外的存储秒级以下的)

  • ipv4地址

    我们常见到有人会用 varchar(15)来存错一个IP地址,IP地址实际是一个32位的无符号整数,所以应该用无符号整数来存储IP地址。MySQL提供了 INET_ATON()和 INET_NTOA() 函数在这两表示方法之间转换。

love over~
2016-09-19