文章目录
Schema与数据类型优化
schema元数据 不管是表还是字段、字段类型、表结构都和优化有很大关系。
一、选择优化的数据类型
选择正确的数据类型对于获得高性能至关重要,几个简单的选择原则
更小的通常更好
更小的类型通常更快,因为占用更少的盘、内存和CPU缓存,处理时需要的CPU周期也更少。
应该尽量使用可以正确存储数据的最小类型,但是要确保没有低估需要存储的值的范围,增加范围是一个非常耗时和痛苦的操作
简单就好
简单类型的操作通常需要更少的CPU周期,如整型比字符串操作代价更低,因为字符集和校队规则(排序规则)使字符串比较比整型比较更复杂
尽量避免NULL
通常情况最好指定列为 NOT NULL,除非真的需要存储NULL值。
如果查询中包含可为NULL的列,对 MysqL来说更难优化,因为可为NULL的列使得索引、索引统计和值比较都更复杂。
可为NULL的列会使用更多的存储空间,在 My sql里也需要特殊处理,当可为NULL的列被索引时,每个索引记录需要一个额外的字节。
通常把可为NULL的列改成 NOT NULL带来的性能提升比较小,所以后期调优时没必要首先处理这种情况,但如果计划在列上建立索引,就应该避免设计成可为NULL。
二、数值类型
应该尽量只在对小数进行精确计算时才使用 DECIMAL,使用int类型通过程序控制单位效果更好
字符串
使用 VARCHAR合适的情况:字符串列的最大长度比平均长度大很多;列的更新少,所以碎片不是问题:使用了像UTF8这样复杂的字符集,每个字符都使用不同的字节数进行存储
CHAR适合存储很短的字符串,或所有值都接近同一个长度:不容易产生碎片,在存储空间上更有效率
VARCHAR(5)和 VARCHAR(200)存储“hello”,空间开销一致,内存开销不一致
枚举
用字符串而不是数字作为枚举常量,因为枚举后台存储的是数字,数字+数字很容易混乱
注意:枚举是按内部存储的数字而不是字符串进行排序的
相对固定的预定义集合适用枚举,修改枚举及表重建,代价大(不要经常改)
日期和时间类型
DATETIME:8个字节,1001-9999年,精度秒,把日期和时间封装到格式YYYYMMDDHHMMSS的整数中,与时区无关。
TIMESTAMP(时间戳):1970-1-1午夜(UTC)以来的秒数,4个字节,1970-2038,通过函数 FROM_UNIXTIME转为日期,相反的函数UNIX_TIMESTAMP把日期转为时间戳。
显示值依赖时区,比如值0在美国东部时间显示为1069-12-31 19:00:00
通常应该尽量使用TIMESTAMP,它比DATETIME空间效率更高(空间更少)。
TIMESTAMP在跨时区时更方便。
三、 MySQL schema设计中的陷阱
一些普遍的好坏设计原则,但也有一些问题是 MYSQL的实现机制导致的:
- 太多的列
MySQL存储引擎工作时需要在服务层和存储引擎层之间通过行缓存格式拷贝数据(存储引擎查到数据给服务层,然后在服务层将缓冲内容解码成各个列),然后在服务层将缓冲内容解码成各个列,从缓冲中将编码过的列转换成行数据结构的操作代价非常高,代价依赖于列的数量。 - 太多的关联
解析和优化查询代价,单个查询最好在12个表以内做关联。 - 全能的牧举
数字枚举,集合不稳定的枚举(比如过一段时间加一个类型,过一段时间加一个类型) - 变相的枚举
区分枚举ENUM和集合SET的使用场景 - 非此发明( Not Invent Here)的NULL
衡量使用程序去掉NULL的代价
四、范式和反范式
1.范式的优点:
- 范式化的更新操作通常比反范式化要快
- 当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据
- 范式化的表通常更小,可以更好地放在内存里,所以执行操作会要快
- 很少有多余的数据意味着检索列表数据时更少需要DISTINCT成者 GROUP BY语句
2范式化设计的缺点是通常需要关联
3.反范式的优点:避免关联,能使用更有效的索引策略(组合索引)
五、缓存表和汇总表
1.有时提升性能最好的方法是同一张表中保存衍生的冗余数据,有时也需要创建一张完全独立的总表或者缓存表。
(需要避免复杂、昂贵的实时更新操作)
2.物化视图, MySQL并不原生支持, Flexviews
3.如果应用表中保存计数器,则在更新计数器时可能碰到并发问题,创建一张独立的表存储计数器,可以帮助避免缓存失效
- 解决独立表并发问题可以建多行,根据id随机更新,然后计时sum()
- 按天或小时可以单独建行,旧时间可定时任务合并到统一的一行
UPDATE hit_counter SET cnt = cnt +1 WHERE slot = RAND()*100
六、加快 ALTER TABLE操作的速度
MySQL的 ALTER TABLE对大表来说是个大问题,执行大部分修改表结构操作的方法是创建新表结构,旧表数据导入新表,删除旧表,可能花费数小时甚至数天
1.两种方式
- 一是在一台不提供服务的机器上执行 ALTER TABLE操作,然后和提供服务的主库进行切换
- 二是通过“影子拷贝”,创建一张新表,然后通过重命名和删表操作交换两张表及里面的数据