MySQL索引优化

什么是索引

	索引(index)是帮助MySQL高效获取数据的数据结构
	索引的目的在于提高查询效率,可以类比字典
	可以理解为“排好序的快速查找数据结构”
    数据本身之外,数据库还维护着一个满足特定算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引
    一般来说索引本身也很大,不可能全部存储在内存中,因此索往往以索引文件的形式存储在磁盘上
    我们平常所说的索引,如果没有特别指明,都是指B树(多路搜索,并不一定是二叉树)结构缓和的索引。其中聚集索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引。当然,除了B+树这种类型的索引外,还有哈稀索引。
    优势:类似大学图片馆建书目索引,提高数据检索的效率,降低数据库的IO成本
    		  通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗
 	劣势:

索引分类

  1. 单值索引:即一个索引只包含一个列,一个表可以有多个单列索引
  2. 唯一索引:索引列的值必须唯一,但允许为空值
  3. 复合索引:即一个索引包含多列
    一张表索引最多不要超过5个

哪些情况需要创建索引

  1. 主键自动建立唯一索引
  2. 频繁作为查询条件的字段应该创建索引
  3. 查询中与其他表关联的字段,外键关系建立索引
  4. 频繁更新的字段不适合创建索引,因为每次更新不单单是更新了记录还会更新索引
  5. Where条件里用不到的字段不创建索引
  6. 单键/组合索引的选择问题,who?(在高并发下倾向创建组合索引)
  7. 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
  8. 查询中统计或者分组字段

哪些情况不要创建索引

  1. 表记录太少
  2. 经常增删改的表
  3. 数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据建立索引
  4. 注意,如果某个数据列包含许多重复的内容(比如性别),为它建立索引就没有太大的实际效果

MySQL常见瓶颈

  1. CPU: CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时
  2. IO:磁盘I/0瓶颈发生装入数据远大于内存容量的时候
  3. 服务器硬件的性能瓶颈:top,free,iostat和vmstat来查看系统的性能状态

性能分析(Explain(查询执行计划))

explain能干嘛

  1. 表的读取顺序
  2. 数据读取操作的操作类型
  3. 哪些索引可以使用
  4. 哪些索引被实际使用
  5. 表之间的引用
  6. 每张表有多少行被优化器查询

执行计划包含的信息

  1. id
    • id 相同,执行顺序由上至下
    • id 不同,如果是子查询,数字大者先查询
    • id相同不同 在这里插入图片描述
  2. select_type:
    • SIMPLE:简单的select查询,查询中不包含子查询或union
    • PRIMARY:查询中若包含任何复杂的子部分,最外层则被标记为PRIMARY
    • SUBQUERY:在select 或where列表中包含了子查询
    • DERIVED: 在from列表中包含的子查询被标记为DERIVED(衍生)MySQL会递归执行这些子查询,把结果放在临时表里
    • UNION 若第二个SELECT出现在UNION之后,则被标记为UNION,若UNION包含在from子句的子查询中,外层select 将被标记为DERIVED
    • UNION RESULT 从union表获取结果的select
  3. table
  4. partitions
  5. type: 访问类型
    • 从最好到最差依次是system>const>eq_ref>ref>range>index>ALL
    • 一般来说,得保证查询至少达到range组别,最好达到ref
    • system 表只有一行记录(等于系统表),这是const类型特例,平时不会出现,这个可以忽略不计
    • const 表示通过索引一次就找到了,const用于比较primary key 或unique索引,因为只匹配一行数据,所以很快。如将主键置于where列表中,Mysql就能将该查询转换为一个常量。
    • eq_ref 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。
    • ref 非唯一性扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
    • range 只检索给定范围的行,使用一个索引来选择行。key列显示来使用哪个索引,一般就是在你的where语句中出现了between、<、>、in等的查询,这种范围扫描索引比全表扫描要好,因为他只开始于索引的某一点,而结束于另一点,不用扫描全部索引。
    • index: Full Index Scan, index与all区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小(也就是说,虽然all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
  6. possible_keys:显示可能应用在这张表中的索引,可能是1个或多个;查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。
  7. key:实际使用的索引。如果为NULL,则没有使用索引,查询中若使用了覆盖索引,则该索引仅出现在key列表中。
  8. key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精度的情况下,长度越短越好。key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
  9. ref:显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或常量被用于查找索引列上的值。
  10. rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。
  11. filtered
  12. Extra:包含不适合在其他列中显示但十分重要的额外信息
- Using filesort:说明mysql会对数据使用的一个外部的索引排序,而不是按照表内的索引顺序进行读取。Mysql中无法利用索引完成的排序操作称为"文件排序"。
- Using temporary: 使用了临时表保存了中间结果,Mysql在对查询结果排序时使用临时表。常见于排序order by 和分组group by。例EXPLAIN SELECT * from user GROUP BY name (此时的索引建为 index_age_name)
- Using index: 表示相应的selectr操作中使用了覆盖索引(Covering index),避免了广访问了表的数据行,效率不错。如果同时出现using where,表示索引被用来执行索引键值的查找。如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。(覆盖索引:select 的数据列只用从索引中就能够取得,不必读数据行,Mysql可以利用索引返回select列表中的字段,而不必根据索引两再次读取数据文件,换句话说查询列要被所建的索引覆盖。)
- using where :表明使用了where过滤
- using join buffer: 表明使用了连接缓存
- impossible where:where 子句的值总是false,不能用来获取任何元素(EXPLAIN SELECT * from user where age = 7 and age = 8)
- Select tables optimized away :在没有group by 子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化count(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。(EXPLAIN SELECT min(age) from user)
- distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作。

索引优化

  1. 两张表左连接,应在右表的连接字段上建立索引
  2. 三张表左连接,应在两张右表的连接字段上建立索引
  3. 右连接则相反

索引失效

  1. 全值匹配我最爱
  2. 最佳左前缀法则(带头大哥不能死,中间兄弟不能断)
  3. 不在索引列上做任何操作(计算,函数,自动或手动类型转换),会导致索引失效而转向全表扫描
  4. 存储引擎不能使用索引中范围条件右边的列
  5. 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select *
  6. mysql 在使用不等于(!= 或<>)的时候无法使用索引会导致全表扫描
  7. is null 和 is not null 也无法使用索引
  8. like 以通配符开头(’%abc’)mysql索引失效会变成全表扫描的操作(覆盖索引(见5)可以解决like两端百分号的问题)
  9. 字符串不加单引号索引失效
  10. 少用or,用它来连接时会索引失效
  11. 小总结:全值匹配我最爱,最左前缀要遵守;带头大哥不能死,中间兄弟不能断;索引列上少计算,范围之后全失效;LIKE百分写最右,覆盖索引不写星;不等空值还有OR,索引失效要少用;VAR引号不可丢,SQL高级也不难。

查询截取分析

分析

  1. 观察,至少跑一天,看看生产的慢SQL情况。
  2. 开启慢查询日志,设置阈值,比如超过5秒钟的就是慢SQL,并将它抓取出来。
  3. explain+慢SQL分析
  4. show profile
  5. 运维经理 or DBA ,进行SQL数据库服务器的参数调优。

in 和exist(小表驱动大表)

在这里插入图片描述

排序

在这里插入图片描述

group by 关键字优化

  1. group by 实质是先排序后分组,遵照索引建的最佳左前缀
  2. 当无法使用索引列,增大max_length_for_sort_data参数的设置和增大sort_buffer_size参数的设置。
  3. where 高于 having,能写在where限定的条件就不要去having限定了。

慢查询日志

  1. 查看是否开启:SHOW VARIABLES LIKE ‘%slow_query_log%’
  2. 开启:set global slow_query_log=1(只对当前数据库生效,如果MySQL重启后则会失效)
  3. 那么开启了慢查询日志后,什么样的SQL才会记录到慢查询日志里面呢?
  4. 假如运行时间 正好等于long_query_time的情况,并不会被记录下来。也就是说,在MySQL源码里是判断大于long_query_time,而非大于等于。
  5. 休眠4秒,select sleep(4)
  6. 查询慢查询语句的数量: show global status like ‘%slow_queries%’

mysql 慢查询日志分析工具:mysqldumpslow

在这里插入图片描述
在这里插入图片描述

  1. lock table 表名字 read(write), 表名字2 read(write),其他;
  2. session1 中对表加了读锁,对该表可以有读操作,不能有写操作,也不能对其他表有读和写操作,session2中可以对该表有读操作,若对他有写操作,会被阻塞,直到session1中对该表释放锁,session2中的被阻塞的写操作才会被执行。

在这里插入图片描述
4. 简而言之,就是读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。
5. 查看哪些表被加了锁:show OPEN TABLES
6. 可以通过检查Table_locks_immediate 和Table_locks_waited状态变量来分析系统上的表锁定;SQL: show STATUS like ‘table%’
7. Table_locks_immediate: 产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1;
8. Table_locks_waited:出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1),此值高则说明存在着较严重的表级锁争用情况。
9. 此外,Myisam的读写锁调度是写优先,这也是Myisam不适合做写为主表的引擎。因为写锁后,其他 线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。

事务

在这里插入图片描述

行锁变表锁

  1. (导致原因,update table set a = 4000 where id = 1), 因为a是varchar,没有加单引号,导致索引失效。

间隙锁危害

select * from a where a= 8 for update 锁定某一行,其他操作会阻塞,直到commit后,其他操作才会执行。

show status like ‘%innodb_row_lock%’

Innodb_row_lock_current_waits:当前正在等待锁定的数量
Innodb_row_lock_waits 系统启动后到现在总共等待的次数
在这里插入图片描述

优化建议

  1. 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。
  2. 合理设计索引,尽量缩小锁的范围。
  3. 尽可能较少检索条件,避免间隙锁。
  4. 尽量控制事务大小,减少锁定资源量和时间长度。
  5. 尽可能低级别事务隔离。

主从复制

在这里插入图片描述

  1. mysql 版本一致且后台以服务运行。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值