写在前面
这篇文章是《高性能 MySQL》第五章的读书笔记以及总结~旨在帮助我本身梳理并总结书中的知识点和内容~同时也为一些懒得看书的小伙伴提供一个提取好的知识点~以为水的朋友烦请关闭哟数据库
巧妙的使用 Explain
看一条 SQL 语句的性能,可使用 explain
关键字查看语句性能,这里说一下其中的 type
字段的部分含义,服务器
- all,即全表扫描,说明这个 SQL 语句没有使用到索引,有多是表自己没有建立索引,也多是由于 SQL 语句致使没有使用索引
- range,说明使用的是有范围的索引扫描,性能优于 index
- index,这里说明使用了索引,这种状况下,若是 extra 列中的值为 Using index,这种状况是索引覆盖,索引覆盖的意思是,咱们想要查询的数据,索引中已经都存在啦,这种状况下就不须要再回表取数据了
- ref,说明条件列使用了索引,可是不是主键和 unique,因此这里即便使用了索引,索引值不惟一,有重复的状况
- eq_ref,相对于 ref 来讲就是使用的是惟一索引,对于每一个索引键值,只有惟一的一条匹配记录
- const/system,单表中最多只有一条匹配行,查询起来很是迅速,因此这个匹配行中的其余列中的值能够被优化器在当前查询中当作常量来处理。例如根据主键或者惟一索引进行的查询
- index_merge,说明使用了 MySQL 的索引合并的优化方法,当使用合并索引的时候,就须要检查一下咱们所建立的索引是否为多个单列索引
如何有效的优化索引
使用索引的时候,索引必须做为独立的列出现
做为独立的列的意思是,索引不能做为表达式的一部分,也不能做为函数的参数出现,不然索引会失效,缘由是 MySQL 没法自动解析表达式以及参数,因此也就没法使用索引了,索引失效还有如下几种状况:markdown
- 条件中使用
is null
或者 is not null
会致使索引失效,缘由是索引中不会存储 null
- 使用
%like
,由于 MySQL 是左匹配,使用模糊查询时若是以%
开头会致使全表查询
- 使用多列索引的时候,若是索引顺序不是创建索引的顺序,或者跳过第一个索引直接使用后面的索引,也会致使索引失败,缘由依然是 MySQL 是左匹配~
- 条件中包含
or
时,只有全部列都是单独索引时才会使用索引
如何建立有效的索引
- 若是须要索引很长的字符串,此时须要考虑前缀索引
- 前缀索引即选择所需字符串的一部分前缀做为索引,这时候,须要引入一个概念叫作索引选择性,索引选择性是指不重复的索引值与数据表的记录总数的比值,能够看出索引选择性越高则查询效率越高,当索引选择性为1时,效率是最高的,可是在这种场景下,很明显索引选择性为1的话咱们会付出比较高的代价,索引会很大,这时候咱们就须要选择字符串的一部分前缀做为索引,一般状况下一列的前缀做为索引选择性也是很高的
- 如何选择前缀
- 计算该列完整列的选择性,使得前缀选择性接近于完整列的选择性
- 使用多列索引
- 尽可能不要为多列上建立单列索引,由于这样的状况下最多只能使用一星索引,这样的话,不如去建立一个全覆盖索引,在多列上建立单列索引大部分状况下并不能提升 MySQL 的查询性能,MySQL 5.0 中引入了合并索引,在必定程度上能够表内多个单列索引来定位指定的结果,可是 5.0 之前的版本,若是 where 中的多个条件是基于多个单列索引,那么 MySQL 是没法使用这些索引的,这种状况下,还不如使用 union
- 选择合适的索引列顺序
- 经验是将选择性最高的列放到索引最前列,能够在查询的时候过滤出更少的结果集
- 但这样并不老是最好的,若是考虑到 group by 或者 order by 等状况,再好比考虑到一些特别场景下的 guest 帐号等数据状况,上面的经验法则可能就不是最适用的
- 覆盖索引
- 所谓覆盖索引就是指索引中包含了查询中的全部字段,这种状况下就不须要再进行回表查询了
- MySQL 中只能使用 B-Tree 索引作覆盖索引,由于哈希索引等都不存储索引的列的值,覆盖索引对于 MyISAM 和 InnoDB 都很是有效,能够减小系统调用和数据拷贝等时间
- Tips:减小
select *
操做
- 使用索引扫描来作排序
- MySQL 生成有序的结果有两种方法:经过排序操做,或者按照索引顺序扫描;使用排序操做须要占用大量的 CPU 和内存资源,而使用
index
性能是很好的,因此,当咱们查询有序结果时,尽可能使用索引顺序扫描来生成有序结果集
- 怎样保证使用索引顺序扫描:
- 索引列顺序和 ORDER BY 顺序一致
- 全部列的排序方向一致
- 若是关联多表,那么只有当 ORDER BY 子句引用的字段所有为第一张表时,才能使用索引作排序,限制依然是须要知足索引的最左前缀要求
- 压缩索引
- 上一篇将索引结构的文章提到了,MyISAM 中使用了前缀压缩技术,会减小索引的大小,能够在内存中存储更多的索引,这部分优化默认也是只针对字符串的,可是能够自定义对整数作压缩
- 这个优化在必定状况下性能比较好,可是对于某些状况可能会致使更慢,由于前缀压缩决定了每一个关键字都必须依赖于前面的值,因此没法使用二分查找等,只能顺序扫描,因此若是查找的是逆序那么性能可能不佳
- 减小重复、冗余以及未使用的索引
- MySQL 的惟一限制和主键限制都是经过索引实现的,因此不须要在同一列上增长主键、惟一限制再建立索引,这样是重复索引
- 再举个例子,若是已经建立了索引(A,B),那么再建立索引(A)的话,就属于重复索引,由于 MySQL 索引是最左前缀,因此索引(A,B)自己就可使用索引(A),可是建立索引(B)的话不属于重复索引
- 尽可能减小新增索引,而应该扩展已有的索引,由于新增索引可能会致使 INSERT、UPDATE、DELETE 等操做更慢
- 能够考虑删除没有使用到的索引,定位未使用的索引,有两个办法,在 Percona Server 或者 MariaDB 中打开 userstates 服务器变量,而后等服务器运行一段时间后,经过查询 INFORMATION_SCHEMA.INDEX_STATISTICS 就能够查询到每一个索引的使用频率
- 索引和锁
- 以前讲索引结构的时候说过,InnoDB 支持行锁和表锁,默认使用行锁,而 MyISAM 使用的是表锁,因此使用索引可让查询锁定更少的行,这样也会提高查询的性能,若是查询中锁定了1000行,但实际只是用了100行,那么在 5.1 以前都须要提交事务以后才能释放这些锁,5.1 以后能够在服务器端过滤掉行以后就释放锁,不过依然会致使一些锁冲突
- 减小索引和数据碎片
- 首先咱们须要了解一下为何会产生碎片,好比 InnoDB 删除数据时,这一段空间就会被留空,若是一段时间内大量删除数据,就会致使留空的空间比实际的存储空间还要大,这时候若是进行新的插入操做时,MySQL 会尝试从新使用这部分空间,可是依然没法完全占用,这样就会产生碎片
- 产生碎片带来的后果固然是,下降查询性能,由于这种状况会致使随机磁盘访问
- 能够经过 OPTIMIZE TABLE 或者从新导入数据表来整理数据
总结
数据库的索引这部分要讲的话实在是太多了~绝大部分状况都须要结合实际状况,若是咱们能够更多的了解数据库索引自己的一些原理,那么对于优化会有一些帮助~巧妙地使用 explain 分析本身所写的 SQL 语句,能够更好的进行优化。函数