良好的逻辑设计和物理设计是高性能的基石,应该根据系统要执行的查询语句来设计 schema。这往往需要权衡各种因素。
例如:反范式的设计可以加快某些类型的查询,但同时可能使另一些类型的查询变慢。比如添加计数表和汇总表是一种很好的优化查询的方式,
但是这些表的维护成本会很高。MySQL独有的特性和实现细节对性能影响也很大。
选择优化的数据类型的简单原则:
1.更小的通常更好
一般情况下,应该尽量使用可以正确存储数据的最小数据类型。
2.简单就好
简单数据类型的操作通常需要更少的cpu周期。
3.尽量避免NULL
如果查询包含可为NULL的列,对mysql来说更难优化,因为可为NULL的列使得索引,索引统计,值比较都更复杂。
可为NULL的列会使用更多的存储空间,在MySQL里也需要特殊处理。
schema设计的第一步,那就是建表,建表的第一步呢就是设计字段,然而了解mysql的数据类型又对设计字段有莫大的帮助。
那我们先来了解mysql的基本数据类型吧。
1.整数类型
TINYINT, SMALLINT,MEDIUMINT,INT,BIGINT
8,16,24,32,64,位存储空间。
MySQL可为证书类型制定宽度,例如INT(11),但对大多数应用这是没意义的;它不会限制值合法范围。对于存储和计算来说
INT(1) 和 INT(20)是相同的
2.实数类型
FLOAT,DOUBLE,DECIMAL(精确计算用的)
3.字符串类型
VARCHARE
最常见的字符串类型。它比定长类型更节省空间,因为它仅适用必要的空间。有一种情况例外,如果MySQL表使用ROW_FORMAT=FIXED创建的话。
VARCHAR需要适用1或2个额外字节记录字符串的长度。如果列的最大长度小于等于255,则使用一个字节记录长度。
CHAR
是定长的。MySQL总是根据定义的字符串分配足够的空间。当存储CHAR值时,MySQL会删除所有的末尾空格。
CHAR值会根据需要采用空格填充以方便比较。
CHAR适合存储很短的字符串。对于经常变更的数据,CHAR也比VARCHAR更好,因为定长CHAR类型不容易产生碎片。
BLOB和TEXT
BLOB和TEXT都是为存储很大数据而设计的字符串数据类型,分别采用二进制和字符方式存储。
使用枚举(ENUM)代替字符串类型
4.日期和时间类型
DATETIME
这个类型能保存大范围的值。从1001年到9999年,精度为妙。
TIMESTAMP
存储空间小,并且会根据时区变化,有特殊的自动更新能力。精度为妙。
如果要存储比秒更小粒度的时间时,可以用bigint类型存储微秒级别的时间戳。
5.位数据类型
BIT
标识符的选择:
整数类型
整数通常是标识列的最好选择。因为他们很快,并且可以使用auto_increment
enum 和 set 类型
字符串类型
如果可能,尽量避免使用字符串类型作为标识符,因为它们很消耗空间,并且通常比数字类型慢。
尤其在MyISAM表里使用字符串作为标识列时要特别小心。MyISAM默认对字符串使用压缩索引,这会使查询很慢。
对于完全‘随机‘的字符串也需要多加注意,例如md5(),sha1(),uuid()产生的字符串。
这些函数生成的新值会任意分布在很大的空间内,这会导致insert以及一些select语句变得很慢:
1.因为插入值会随机写到索引的不同位置,所以使得insert语句更慢。这会导致页分裂,磁盘随机访问,以及对于聚簇存储引擎产生聚簇索引碎片。
2.select语句会变得更慢,因为逻辑上相邻的行为分布在磁盘和内存的不同地方。
3.随机值会导致缓存对所有类型的查询语句效果都很差。
schema设计中的陷阱
1.太多的列
2.太多的关联
3.全能的枚举
范式和反范式
三大范式:
1.必须有主键,列不可分
2.当一个表是复合主键时,非主键的字段不依赖于部分主键(即必须依赖于全部的主键字段)
3.关系模式R(U,F)中的所有非主属性对任何候选关键字都不存在传递依赖
反范式,顾名思义,不遵守三大范式。
首先我们来看看范式的优缺点:
优点:
范式化的更新操作通常比反范式快。
当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据
范式化的表通常很小,可以更好的放在内存里,所以执行操作会更快。
很少有多余的数据意味着检索列表数据更少需要DISTINCT或者GROUP BY语句。
缺点:
过度依赖关联。这不但代价昂贵,也可能使一些索引策略无效。
反范式优缺点:
因为所有的数据在一张表中,可以很好的避免关联。
如果不需要关联,则对大部分查询最差的情况,即使没有使用索引,是全表扫描,当数据比内存大时这可能比关联要快得多,
因为这样避免了随机I/O。
单独的表能更好的使用索引策略。
混用范式和反范式才是schema的主流。
缓存表和汇总表
方便查询,不易维护。
物化视图
计数器表