目录
为什么要优化
- 数据库出现瓶颈,系统的吞吐量出现访问速度慢
- 随着应用程序的运行,数据库的中的数据会越来越多,处理时间变长
- 数据读写速度缓慢
存储引擎的选择
存储引擎
使用的存储引擎 myisam / innodb
myisam 存储: 如果表对事务要求不高,同时是以查询和添加为主的,我们考虑使用myisam存储引擎. ,比如 bbs 中的 发帖表,新闻网,回复表,读多写少用 MyISAM。
INNODB 存储: 对事务要求高,保存的数据都是重要数据,我们建议使用INNODB,比如订单表,账号表,写多读少用 InnoDB,InnoDB 支持事务,保证数据安全性、完整性。
MyISAM 和 INNODB的区别
事务安全(MyISAM不支持事务,INNODB支持事务)
查询和添加速度(MyISAM批量插入速度快)
支持全文索引(MyISAM支持全文索引,INNODB不支持全文索引)
锁机制(MyISAM时表锁,innodb是行锁)
外键 MyISAM 不支持外键, INNODB支持外键
如何通俗地理解三个范式?
第一范式1NF:字段原子性
- 字段原子性,字段不可再分割。
注意比较容易出错的一点,在一对多的设计中使用逗号分隔多个外键,这种方法虽然存储方便,但不利于维护和索引(比如查找带标签java的文章)
第二范式:消除对主键的部分依赖
- 即在表中加上一个与业务逻辑无关的字段作为主键
第三范式:消除对主键的传递依赖
传递依赖:B字段依赖于A,C字段又依赖于B。比如上例中,任课老师是谁取决于是什么课,是什么课又取决于主键id。因此需要将此表拆分为两张表日程表和课程表(独立数据独立建表):
这样就减少了数据的冗余(即使周一至周日每天都有Java课,也只是course_id:3546出现了7次)
建立适当的索引
1、索引为什会使查找变快
- btree类型的索引,就是使用的二分查找法,肯定快啊,算法复杂度是log2N,也就是说16条数据查4次,32条数据查5次,64条数据查6次…依次类推。
- 使用索引跟没使用索引的区别,就跟我们使用新华字典查字,一个是根据拼音或者笔画查找,一个是从头到尾一页一页翻。
所以说使用索引访问数据是非常快的
2、索引的代价
- 磁盘占用
- 对dml(update delete insert)语句的效率影响
3、索引使用原则
1、较频繁的作为查询条件字段应该创建索引
select * from emp where empno = 1;
2、唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
select * from emp where sex = ‘男’
3、更新非常频繁的字段不适合创建索引
select * from emp where logincount = 1
4、不会出现在WHERE子句中的字段不该创建索引
4、mysql四种索引的区别
- 主键索引,主键自动的为主索引 (类型Primary),要求关键字唯一且不为 bull
- 唯一索引 (UNIQUE):关键字的唯一
- 普通索引 (INDEX):按照第一字段有序
- 全文索引 (FULLTEXT) :所有数据都要有索引
即使建立了索引,有些场景也不一定使用:
假如说 性别 这样的字段,一个关键字对应着很多条数据,使用索引会比全表扫描的效率还低。
所以 索引有种类,选择需谨慎
SQL语句的优化
1、 尽量稍作计算
Mysql的作用是用来存取数据的,不是做计算的,做计算的话可以用其他方法去实现,mysql做计算是很耗资源的。
2.尽量少 join
MySQL 的优势在于简单,但这在某些方面其实也是其劣势。MySQL 优化器效率高,但是由于其统计信息的量有限,优化器工作过程出现偏差的可能性也就更多。对于复杂的多表 Join,一方面由于其优化器受限,再者在 Join 这方面所下的功夫还不够,所以性能表现离 Oracle 等关系型数据库前辈还是有一定距离。但如果是简单的单表查询,这一差距就会极小甚至在有些场景下要优于这些数据库前辈。
3.尽量少排序
排序操作会消耗较多的 CPU 资源,所以减少排序可以在缓存命中率高等 IO 能力足够的场景下会较大影响 SQL的响应时间。
对于MySQL来说,减少排序有多种办法,比如:
通过利用索引来排序的方式进行优化
减少参与排序的记录条数
非必要不对数据进行排序
4.尽量避免 select * .
在数据量少并且访问量不大的情况下,select * 没有什么影响,但是量级达到一定级别的时候,在执行效率和IO资源的使用上,还是有很大关系的,用什么字段取什么字段,减少不必要的资源浪费。
之前遇到过因为一个字段存储的数据比较大,并发高的情况下把网络带宽跑满的情况,造成网站打不开或是打开速度极慢的情况。
5.尽量用 join 代替子查询
虽然 Join 性能并不佳,但是和 MySQL 的子查询比起来还是有非常大的性能优势。MySQL 的子查询执行计划一直存在较大的问题,虽然这个问题已经存在多年,但是到目前已经发布的所有稳定版本中都普遍存在,一直没有太大改善。虽然官方也在很早就承认这一问题,并且承诺尽快解决,但是至少到目前为止我们还没有看到哪一个版本较好的解决了这一问题。
6.尽量少 or
当 where 子句中存在多个条件以“或”并存的时候,MySQL 的优化器并没有很好的解决其执行计划优化问题,再加上 MySQL 特有的 SQL 与 Storage 分层架构方式,造成了其性能比较低下,很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果。
7.尽量用 union all 代替 union
union 和 union all 的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用 union all 而不是 union。
8.尽量早过滤
这一优化策略其实最常见于索引的优化设计中(将过滤性更好的字段放得更靠前)。
在 SQL 编写中同样可以使用这一原则来优化一些 Join 的 SQL。比如我们在多个表进行分页数据查询的时候,我们最好是能够在一个表上先过滤好数据分好页,然后再用分好页的结果集与另外的表 Join,这样可以尽可能多的减少不必要的 IO 操作,大大节省 IO 操作所消耗的时间。
9.优先优化高并发的 SQL,而不是执行频率低某些“大”SQL
对于破坏性来说,高并发的 SQL 总是会比低频率的来得大,因为高并发的 SQL 一旦出现问题,甚至不会给我们任何喘息的机会就会将系统压跨。而对于一些虽然需要消耗大量 IO 而且响应很慢的 SQL,由于频率低,即使遇到,最多就是让整个系统响应慢一点,但至少可能撑一会儿,让我们有缓冲的机会。
10.从全局出发优化,而不是片面调整
SQL 优化不能是单独针对某一个进行,而应充分考虑系统中所有的 SQL,尤其是在通过调整索引优化 SQL 的执行计划的时候,千万不能顾此失彼,因小失大。
11.尽可能对每一条运行在数据库中的SQL进行 explain
优化 SQL,需要做到心中有数,知道SQL 的执行计划才能判断是否有优化余地,才能判断是否存在执行计划问题。在对数据库中运行的 SQL 进行了一段时间的优化之后,很明显的问题 SQL 可能已经很少了,大多都需要去发掘,这时候就需要进行大量的 explain 操作收集执行计划,并判断是否需要进行优化。
数据量大的时候,主从分离、分库分表、垂直/水平分割
读写分离
读写分离是依赖于主从复制,而主从复制又是为读写分离服务的。因为主从复制要求slave不能写只能读
垂直拆分
垂直拆分就是要把表按模块划分到不同数据库表中(当然原则还是不破坏第三范式)
水平拆分
垂直切分只是把表按模块划分到不同数据库,但没有解决单表大数据量的问题,而水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。
分表原因
- 为数据库减压
- 分区算法局限
- 数据库支持不完善(5.1之后mysql才支持分区操作)
配置优化
配置的优化其实包含两个方面的:操作系统内核的优化和mysql配置文件的优化
1)系统内核的优化对专用的mysql服务器来说,无非是内存实用、连接数、超时处理、TCP处理等方面的优化,根据自己的硬件配置来进行优化,这里不多讲;
2)mysql配置的优化,一般来说包含:IO处理的常用参数、最大连接数设置、缓存使用参数的设置、慢日志的参数的设置、innodb相关参数的设置等,如果有主从关系在设置主从同步的相关参数即可,网上的相关配置文件很多,大同小异,常用的设置大多修改这些差不多就够用了。