Mysql基础课十:sql 优化

SQL 优化

  1. 语句 show status [session/global] 可以显示数据库的统计信息,如 select 操作执行次数,commit 次数,rollback 次数等,通过参数 --log-slow-queries[=file_name] 来指定慢查询日志存放,参数 -… 指定慢查询阈值;

  2. explain 分析 sql 语句,type 字段,有 all 表示全表扫描,index 表示索引查找,range 表示索引范围查找,ref 表示非唯一索引,eq_ref 表示唯一索引,const / system 表示常量,null 表示

  3. explain 结果的 key,表示实际使用的所有,rows 表示扫描的行数

  4. 语句 explain extended sql,显示 sql 在执行中有哪些优化;explain partitions sql,显示执行访问的分区;trace,用来跟踪 sql;

	set optimizer_trace="enabled=on",end_markers_in_json=on;
	set optimizer_trace_max_mem_size=1000000;
	sql
	select * from information_schema.optimizer_trace;
  1. explain 结果的extra,如果是 using where,表示需要回表,like 子句,如果以 % 开头,是无法使用索引,出现隐式类型转换也是不会使用到索引; where 子句中如果出现 or,且又一个条件是非索引,就会使用全表扫描;
	// last_name 为字符型,这种情况下,就不会用到该索引
	select * from actor where last_name = 1;
  1. 常用优化手段,定期分析表,检查表和优化表,业务上尽量减少 order by,使用索引有序的数据,适当加大max_length_for_sort_data的值,使排序在内存中完成,而不使用临时表; group by:默认会按其指定字段排序,可以添加order by null 禁止排序来改善性能;尽量用 join 代替 子查询;or 组成并集条件时,要求每个条件都是索引字段;
	//使sql能生成正确执行计划
	analyze table table_name; 
	//检查是否有错误 
	check table table_name;   
	//优化表,可以整理碎片
	optimize table table_name; 

Sql语句执行慢

  1. 查询语句长时间不返回,可能是表锁住了,可以通过命令 show processlist 来分析下当前语句处于什么状态,如果是 waiting for table metadata lock,就说明其他 session 占有了 MDL 写锁没有释放,通过 select blocking_pid from sys.schema_table_lock_waits 可以找到阻塞的 process_id,kill 断开即可;

  2. 如果通过 show processlist 返回的是 wait for table flush,表示 flush 操作阻塞了 select 查询语句,通常 flush 操作很快,所以要查看什么操作 阻塞了 flush 操作,然后 kill 断开相应的操作;

  3. 如果返回的是 等行锁,就需要通过 select * from t sys.innodb_lock_waits where locked_table=’test.t’\G 来获取占用锁的线程,执行 kill 操作;

数据库连接不足

  1. 如果业务中大量使用短连接,当机器负载高,出现请求时间过长,导致连接数大量增加,超过 max-connections 的限制,Mysql 因此拒绝了新的连接,就需要考虑如何恢复业务;

  2. 首先考虑处理掉,占着连接但不工作的线程,并且优先断开非事务的空闲太久的连接,如果还不够,再断开事务内空闲太久的连接,

  3. 服务端断开连接,使用命令 kill connection + id ,如果客户端处于 sleep 状态时,它的连接被服务端主动断开后,客户端并不会马上知道,直到客户端在发起下一个请求的时候,才会收到这样的报错;

  4. 命令 show processlist 查看连接状态,information_schema 库的 innodb_trx 表 查看事务具体状态;

  5. 第二种方案是,减少连接过程的消耗,一种可能的做法是,让数据库跳过权限验证阶段,不太推荐;

慢查询

  1. 慢查询通常是:索引没有设计好,SQL 语句没写好,或者 MySQL 选错了索引;

  2. 索引没有设计好,可以通过,紧急创建索引,MySQL 5.6 版本以后,创建索引已经支持 Online DDL;

  3. SQL 语句,可以通过改写处理,MySQL 5.7 提供了 query_rewrite 功能,可以把输入的一种语句改写成另外一种模式,而不必紧急修改应用代码;

	// 改写 id + 1 = ? 为 id = ? - 1
	mysql> insert into query_rewrite.rewrite_rules(pattern, replacement, pattern_database) values ("select * from t where id + 1 = ?", "select * from t where id = ? - 1", "db1");
	call query_rewrite.flush_rewrite_rules();
  1. 选错索引,同样地,使用查询重写功能,给原来的语句加上 force index,避免修改应用代码,需要紧急上线;

  2. 预先发现问题,上线前,在测试环境,把慢查询日志(slow log)打开,并且把 long_query_time 设置成 0,确保每个语句都会被记录入慢查询日志;然后在测试表里插入模拟线上的数据,做一遍回归测试;观察慢查询日志里每类语句的输出,特别留意 Rows_examined 字段是否与预期一致。

你做业务开发的话,要知道,连接异常断开是常有的事,你的代码里要有正确地重连并重试的机制。

QPS 突增问题

  1. 由于业务突然出现高峰,或者应用程序 bug,导致某个语句的 QPS 突然暴涨,最理想的情况需要做服务降级,可能要下掉该功能;

  2. 从数据库角度,下掉某个功能,可以在数据库白名单将应用部署地址去掉,如果是单独的用户,可以删除该用户,最后一种方法是将引起 QPS 暴涨的语句,在线改写为 select 1 返回;

tips

  1. myISAM对表总数有缓存,而innodb没有;

  2. sql 中字符串,使用单引号;

你可能感兴趣的:(Mysql)