Schema数据类型优化
良好的数据路逻辑设计和物理设计是高性能的基石,所以要打造一个高性能的数据库服务,在Schema设计之初就应该需要权衡各种因素。
选择最优化的数据类型
数据库支持的数据类型非常多,选择一个正确的数据类型对于获得高性能至关重要。
选择合适数据类型的几个原则:
更小的通常更好
一般情况下,应该尽量使用可以正确数据类型的最小数据类型。但也要确保没有低估需要存储的范围。简单就好
简单的数据类型的操作通常需要更少的CPU周期。例如,
- 整型比字符串操作代价更低
- 使用MySQL内建的数据类型(比如,date、time、datetime),比用字符串更快
- 使用整型存储一个IP地址,比用一个字符串更好
- 尽量避免使用NULL
因为如果在查询中包含有NULL的列,对MySQL来说更难优化。所以通常情况下,最好指定列为 NOT NULL。
TIPS:
datetime和timstamp列都可以存储相同类型的数据(时间和日期,都可以精确到秒),然而timestamp实际只使用datetime一般的存储空间。但另一方面,timestamp允许的时间范围要小的多。
基本的数据类型
- 数字
- 整数 - TINYINT (8) - SMALLINT (16) - MEDIUMINT (24) - INT (32) - BIGINT (64)
> **TIPS1:** 整数类型有可选的 unsigned 属性,表示不允许有负值,如果将要使用的列不会出现负值的话,加上这个属性,将会可以使正数的上限增加一倍。
> **TIPS2:** int(1)与int(11),对于存储和计算来说,这两者本质是没有区别的;两者只是在MySQL的一些交互工具中略有差别(比如,MySQL命令行客户端,用来控制显示字符的个数)。
- 实数 - 作用
存储小数
存储比BIGINT更大的数
- float
- double
> float 和 double支持使用标准的浮点运算进行近似的计算。
- decimal
> decimal 类型用于存储精确的小数,支持精确的计算。
>
> 由于CPU不支持对decimal的直接计算,所以对decimal的精确计算是由MySQL服务器自己来实现。
>
> **Tips:** 因为在进行精确计算时需要额外的空间和计算开销,所以尽量只对小数才使用decimal。比如,财务数据。另外如果数据量大的话,可以考虑使用bigint代替decimal,只需将存储的货币单位根据小数的位数乘以相应的倍数即可。
字符串
CHAR
char 类型是定长的:MySQL是根据定义的字符串长度分配足够的空间。
char,适合存储很短的字符串,或者所有值的长度都差不多的的字符串。例如,密码的md5值。
另外,char还适合存储经常进行变更的值,相比于vachar,char类型很少会产生碎片。所以这一类的列,会比varchar更好。VARCHAR
varchar 类型用于存储可变长的字符串。它只使用必要的空间,所以比定长类型更节省空间。
varchar,需要使用一个或者两个额外的字节来存储当前字符串的长度信息;如果列的长度小于或等于255个字节,则只需要一个字节表示,否则就需要两个字节来表示。
下面的这些情况适合使用varchar
- 字符串列的长度比平均长度大很多
- 列的更新很少,所以碎片不是问题
- 使用了像UTF-8这样复杂的字符集,因为该字符集中每个字符可能使用不同的字节来进行存储
**Tips:**
用varchar(5)和varchar(200)来存储 「hello」有什么区别?
首先两者在存储空间的开销是一样的。
但是,一般的列在查询时会消耗更多的内存,因为在读到这些列时MySQL通常会分配固定大小的内存块来保存内部值。
尤其在使用内存临时表进行排序或者其他操作时,会特别的糟糕。
所以最好的策略就是,**分配真正需要的空间**。
**Tips:**
字符串长度定义不是字节数,而是字符数。两者概念是不同的,多字节字符集会需要更多的空间存储单个字符。
BLOB和TEXT
两者都是为存储很大的数据而设计的字符串数据类型,不同的是两者分别采用二进制和字符方式存储。
MySQL在处理两个类型的值时,处理基本相同,仅有的不同是BLOB类型是以二进制格式来存储的,所以没有排序规则和字符集,而text类型有排序规则和字符集。
枚举(ENUM)
枚举可以把一些不重复的字符串存储成一个预定义的集合。
MySQL会在存储枚举类型时粉肠紧凑,会根据列的值的数量压缩到一个或者两个字节中。
MySQL会在内部将每个值在列表中的位置保存成整数,而这些『数字–字符串』的对应关系,会保存在 .frm 文件中。
所以当该列需要新添加一个新的枚举值时,必须添加在之前枚举列表的最后面,否则就会出现数据错乱的问题。切记。日期和时间类型
DATETIME
该类型能保存大范围的值,从1001年到9999年,精度为秒。他会把时间封装到YYYYMMDDHHIISS的整数中,没有时区概念。使用8个字节的存储空间。
TIMESTAMP
该类型保存了从1970-01-01 00:00:00(格林威治时间)以来的秒数。该类型使用4个字节的存储空间,所以只能表示1970到2023年,其值还具有时区的概念。
- 位数据类型
存储更紧凑。但所有这些位类型,不管底层存储格式和存储方式,从技术上来说都是字符串类型。虽然用它存储数据更紧凑,但是对于大部分应用来说,最好避免使用该类型。
BIT
SET
- 特殊类型的数据
某些数据的类型并不直接和内置的类型一致。所以需要一定的转换进行存储。
低于秒级的时间戳
低于秒级的时间需要在引用层做处理,一般可以通过存储两个或者多个列来存储(一个存储秒级的时间戳,另外的存储秒级以下的)
ipv4地址
我们常见到有人会用 varchar(15)来存错一个IP地址,IP地址实际是一个32位的无符号整数,所以应该用无符号整数来存储IP地址。MySQL提供了 INET_ATON()和 INET_NTOA() 函数在这两表示方法之间转换。
love over~
2016-09-19