本章的关注点在于数据库设计,良好的数据库设计是高性能的基石,应该根据系统即将执行的查询语句来设计数据库。
1.1 数据库设计的一些参考点
- 字段设计时,应该尽量选择正确数据类型的最小数据类型,使用时占用更少的磁盘、内存、cpu。
- 使用更简单的数据类型,例如整数比字符串的操作代价更低。如使用MYSQL的内建的类型,不要用字符串存储时间和日期
- 尽量避免NULL。
1.1.1 整数类型
有两种类型的数字:整数和实数。如果存储整数,可以使用这几种类型:TINYINT(8字节),SMALLINT(16字节),MEDIUMINT(24字节),INT(32字节),BIGINT(64字节)。可以存储的范围是-2的N-1次方 - 2的N-1次方减一。N是存储空间的位数。
1.1.2 实数类型
实数是带有小数部分的数字MYSQL及支持存储精确类型,也支持不精确类型。浮点类型会需要额外的空间和计算消耗,所以应该尽量只在对小数进行准确计算时才使用DECIMAL。
1.1.3 字符串类型
MYSQL支持多种字符串类型,每种还有很多变种。
- VARCHAR:需要一个或者两个额外字节记录字符串长度,如果列的最大长度小于或者等于255字节,则只使用一个字节展示,否则两个字节。varchar存储是变长的,会节省空间,但是在update时,空间更新后字节长度增加时,并且磁盘页没有多余空间时,MyISAM会将行拆成不同的片段存储,而InnoDB则需要分裂页来使行能放进业内。
- 以下情况适合使用varchar:1.字符串列的最大长度比平均长度大很多,列的更新很少。
- CHAR:CHAR类型是定长的。char适合存储很短的字符串,或者所有值都接近同一长度,对于经常变更的字段,char比varchar更好,因为不会产生碎片。对于非常短的列,char比varchar在存储空间上也更有效率
- BLOB和TEXT:为存储很大的数据而设计的字段,分别采用二进制和字符串的方式存储。
1.1.4 日期和时间类型
MYSQL提供两种相似的日期类型:DATETIME(8字节,与时区无关)和TIMESTAMP(4字节,只能表示1970年 - 2038年。展示的值也依赖于时区,MYSQL的服务器、操作系统、客户端连接都有时区设置,默认非空)。
1.1.5 位数据类型
所有位类型,不管存储底层存储格式和处理方式如何,从技术上来说都是字符串类型。
1.1.6 选择标识符
进行查询时,一般更有可能用标识列与其他值进行比较,所以为标识列选数据类型时,应该与关联表的类型都保持一致。
1.1.7 特殊类型数据
IPv4地址,可以用INET_ATON(无符号整数)类型存储,和INET_NTOA()方法进行转换
1.2 数据库设计的一些参考点
- 不要疯狂在一个表中增加列
- 表关联不宜太多,单个查询最好在12个表以内做关联
- 注意过度使用枚举
1.3 范式和反范式
完全的范式化与反范式化是很难存在的,在实际应用中经常会混用。
范式化的优点:
- 范式化的更新操作通常比反范式快
- 当数据遵守范式化规则时,就只有很少或者没有重复的数据,所以修改点少
- 范式化的表会更小,设计更合理
范式化的缺点:
- 通常需要较多的表关联
反范式化的优点:
- 反范式化可以很好的避免关联。
- 单独的表也能使用更有效的索引策略。
1.4 缓存表和汇总表
有时提升性能的最好办法是在同一张表中保存衍生的冗余数据,然而有时也需要创建一张完全独立的汇总表或缓存表。如需要计算一个网站的24小时内发送的消息数,可以考虑每小时生成一张汇总表。
1.4.1 物化视图
物化视图实际上是预先计算并且存储在磁盘上的表,可以通过各种各样的策略刷新和更新。即可以通过工具来实现一些汇总信息的自动更新,无需每小时认为执行查询统计更新。
1.4.2 计数器表
如果应用在表中保存计数器,则在更新计数器时可能碰到并发问题。计数器在web应用中很常见,可以用这个表缓存一个朋友的朋友数
1.4.5 加快ALTER TABLE的操作速度
mysql的Alter 操作对于大表来说是一个大问题,mysql进行大部分修改表的操作是用新的结构新建一张表,从旧表中查出所有数据,插入新表,然后删除旧表。
- 一种是在一台不提供服务的机器上执行alter,然后和提供服务的机器主库进行对换
- 另一种是“影子拷贝”。他的技巧是要求表的结构创建一张与源表无关的新表,然后通过重命名和删表操作交换两张表
- 为了高效的载入数据到MyISAM表中,有一个常见的技巧是先禁用索引,载入数据,然后重新启用索引,这个技巧能发挥作用,是因为构建索引的工作被延迟到数据完全载入之后,这个时候已经可以通过排序来构建索引。但对唯一索引无效。