mysql优化切入点:
- 事前:
设计数据库时:数据库表、字段的设计(垂直分表),存储引擎 。
横向扩展:MySQL集群、负载均衡、读写分离,分库分表 。
- 事中:
SQL语句的优化,利用好MySQL自身提供的功能,如索引等 。
- 事后:
mysql 中的慢查询Explian查看执行计划,做分析,做优化。
数据库设计:
字段类型的选择,设计规范,范式,常见设计案例
一.表级设计规范:
1.数据库和表的字符集统一使用UTF8
2.字段命名要见名知一,所有表和字段都需要添加注释
3.单表字段不宜过多,冷热数据分离
Mysql限制每个表最多存储4096列,并且每一行数据的大小不能超过65535字节 减少磁盘IO,保证热数据的内存缓存命中率(表越宽,把表装载进内存缓冲池时所占用的内存也就越大,也会消耗更多的IO) 更有效的利用缓存,避免读入无用的冷数据 经常一起使用的列放到一个表中(避免更多的关联操作)
4.单表数据过多要考虑分表或者历史数据归档
单表数据量建议控制在500万以内,过大会造成修改表结构,备份,恢复都会有很大的问题
可以用历史数据归档(应用于日志数据),分库分表(应用于业务数据)等手段来控制数据量大小
二.字段级设计规范:
1.优先选择符合存储需要的最小的数据类型
-
将字符串转换成数字类型存储,如: 将IP地址转换成整形数据
-
对于非负型的数据(如自增ID、整型IP)来说,要优先使用无符号整型来存储
-
无符号相对于有符号可以多出一倍的存储空间
SIGNED INT -2147483648~2147483647
UNSIGNED INT 0~4294967295 -
VARCHAR(N)中的N代表的是字符数,而不是字节数使用UTF8存储255个汉字 Varchar(255)=765个字节过大的长度会消耗更多的内存
-
2.尽可能使用 not null
非null字段的处理要比null字段的处理高效些!且不需要判断是否为null。
null在MySQL中,不好处理,存储需要额外空间,运算也需要特殊的运算符。如select null = null和select null <> null(<>为不等号)有着同样的结果,只能通过is null和is not null来判断字段是否为null。
如何存储?MySQL中每条记录都需要额外的存储空间,表示每个字段是否为null。因此通常使用特殊的数据进行占位,比如int not null default 0、string not null default ‘ ’。
3.避免使用ENUM类型
修改ENUM值需要使用ALTER语句
ENUM类型的ORDER BY操作效率低,需要额外操作
禁止使用数值作为ENUM的枚举值
4.使用TIMESTAMP(4个字节)或DATETIME类型(8个字节)存储时间
TIMESTAMP 存储的时间范围 : 1970-01-01 00:00:01 ~ 2038-01-19-03:14:07
TIMESTAMP 占用4字节和INT相同,但比INT可读性高
超出TIMESTAMP取值范围的使用DATETIME类型存储
经常会有人用字符串存储日期型的数据(不正确的做法)
缺点1:无法用日期函数进行计算和比较
缺点2:用字符串存储日期要占用更多的空间
5.同财务相关的金额类数据必须使用decimal类型
- 非精准浮点:float,double
- 精准浮点:decimal
Decimal类型为精准浮点数,在计算时不会丢失精度
占用空间由定义的宽度决定,每4个字节可以存储9位数字,并且小数点要占用一个字节
可用于存储比bigint更大的整型数据
三.索引的设计规范
1.限制每张表上的索引数量,建议单张表索引不超过5个
2.禁止给表中的每一列都建立单独的索引
3.每个Innodb表必须有个主键
4.常见索引列建议
-
出现在SELECT、UPDATE、DELETE语句的WHERE从句中的列
-
包含在ORDER BY、GROUP BY、DISTINCT中的字段,并不要将符合1和2中的字段的列都建立一个索引, 通常将1、2中的字段建立联合索引效果更好
-
多表join…on…的关联列
5.如何选择索引列的顺序
建立索引的目的是:希望通过索引进行数据查找,减少随机IO,增加查询性能 ,索引能过滤出越少的数据,则从磁盘中读入的数据也就越少
- 区分度最高的放在联合索引的最左侧(区分度=列中不同值的数量/列的总行数)
- 尽量把字段长度小的列放在联合索引的最左侧(因为字段长度越小,一页能存储的数据量越大,IO性能也就越好)
- 使用最频繁的列放到联合索引的左侧(这样可以比较少的建立一些索引)
6.避免建立冗余索引和重复索引
建立冗余索引和重复索引会增加了查询优化器生成执行计划的时间。
重复索引示例:primary key(id)、index(id)、unique index(id) 冗 余索引示例:index(a,b,c)、index(a,b)、index(a)
7.对于频繁的查询优先考虑使用覆盖索引
覆盖索引:就是包含了所有查询字段(where,select,ordery by,group by包含的字段)的索引
覆盖索引的好处:
- 避免Innodb表进行索引的二次查询
Innodb是以聚集索引的顺序来存储的,对于Innodb来说,二级索引在叶子节点中所保存的是行的主键信息,
如果是用二级索引查询数据的话,在查找到相应的键值后,还要通过主键进行二次查询才能获取我们真实所需要的数据
而在覆盖索引中,二级索引的键值中可以获取所有的数据,避免了对主键的二次查询 ,减少了IO操作,提升了查询效率
- 可以把随机IO变成顺序IO加快查询效率
由于覆盖索引是按键值的顺序存储的,对于IO密集型的范围查找来说,对比随机从磁盘读取每一行的数据IO要少的多,
因此利用覆盖索引在访问时也可以把磁盘的随机读取的IO转变成索引查找的顺序IO
SQL语句的优化:
1.避免数据类型隐式转换
所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低)
//todo 待续