重庆市建设信息网站,网络科技有限公司起名大全,自己的网站怎么建立,微信scrm系统本文是向大家介绍在sql调优的几个操作步骤#xff0c;它能够在日常遇到慢sql时有分析优化思路#xff0c;能够让开发者更好的了解sql执行的顺序和原理。一、前言在日常开发中#xff0c;我们经常遇到一些数据库相关的问题#xff0c;比方说#xff1a;SQL已经走了索引了它能够在日常遇到慢sql时有分析优化思路能够让开发者更好的了解sql执行的顺序和原理。一、前言在日常开发中我们经常遇到一些数据库相关的问题比方说SQL已经走了索引了为什么还是会耗时很长索引越建越多了但是好像都是合理的因为需求就是需要各种查询但是索引过多又会降低写入的效率怎么更加合理的建立索引为某个业务场景建立了某个索引想当然的会生效搞不清楚为啥没有完全覆盖索引包含了排序字段为什么还是fileSort?批量处理大量数据如何优化二、SQL优化步骤1、通过查SQL日志等定位那些执行效率较低的SQL语句。2、explain 分析SQL的执行计划。常见字段type执行链接类型常见的比如ALL表示全表扫描const表示常量匹配通过索引可以确认一条数据rang范围查询、ref使用非唯一索引匹配数据ref_or_null表示使用唯一索引匹配index_merge表示使用了索引合并 possible_keys可能用到的索引key用到的索引key_len使用到的索引长度按照字段的类型字节数计算。比方说一个BIGINT类型则为8. Varchar比较特殊。比方说可以为空的utf8mb4编码的Varchar(32)占用key_len 32 * 4 2 1。 2字节用于标示长度1字节用于标示是否为空。rows扫描行数引擎层通过索引过滤后剩余的数据行数(剩余的数据需要在server层进行非索引过滤)。Extra额外信息通常用于判断Mysql怎么使用该索引filtered符合所有查询条件的返回的结果占rows列的百分比只是一个抽样统计的结果并不一定准确。100%则表示完全走索引过滤通过索引过滤后的数据完全符合查询结果。查询语句常出现的Extra类型 空什么都没显示说明完全使用了索引但是需要回表using index覆盖索引说明完全使用了索引并且不需要回表using where部分用到索引using index condition使用到了ICP利用到索引现有的数据在引擎层过滤数据using filesort排序没有通过索引排序出现filesort且rows比较大的情况则需要优化using temporary使用到了临时表如果执行过程需要根据查询到的数据做一些聚合分组而数据量较大时会使用临时表。比如group by、distinct没走索引时using unionUsing intersectUsing sort_union索引合并: 指字段分别有索引采用索引查询合并数据的方式优化使用到了索引合并联合访问算法 select * from table where filed11 or filed22使用到了索引合并交叉访问算法 select * from table where filed11 and filed22使用到了索引合并排序访问算法select * from table where filed11 or filed22需要重点关注 type、rows、filtered、extra。type 由上至下效率越来越高ALL 全表扫描。index 索引全扫描。range 索引范围扫描常用语,,,between,in等操作。ref 使用非唯一索引扫描或唯一索引前缀扫描返回单条记录常出现在关联查询中。eq_ref 类似ref区别在于使用的是唯一索引使用主键的关联查询。const/system 单条记录系统会把匹配行中的其他列作为常数处理如主键或唯一索引查询。null MySQL不访问任何表或索引直接返回结果。虽然上至下效率越来越高但是根据cost模型假设有两个索引idx1(a, b, c), idx2(a, c)SQL为select * from t where a 1 and b in (1, 2) order by c;如果走idx1那么是type为range如果走idx2那么type是ref当需要扫描的行数使用idx2大约是idx1的5倍以上时会用idx1否则会用idx2。extraUsing filesortMySQL需要额外的一次传递以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序并按排序顺序检索行。Using temporary使用了临时表保存中间结果性能特别差需要重点优化。Using index表示相应的 select 操作中使用了覆盖索引Coveing Index,避免访问了表的数据行效率不错如果同时出现 using where意味着无法直接通过索引查找来查询到符合条件的数据。Using index conditionMySQL5.6之后新增的ICPusing index condtion就是使用了ICP索引下推在存储引擎层进行数据过滤而不是在服务层过滤利用索引现有的数据减少回表的数据。3、show profile 分析了解SQL执行的线程的状态及消耗的时间。默认是关闭的开启语句“set profiling 1;”SHOW PROFILES;SHOW PROFILE FOR QUERY #{id};4、trace 工具trace分析优化器如何选择执行计划通过trace文件能够进一步了解为什么optimizer选择A执行计划而不选择B执行计划。set optimizer_traceenabledon;set optimizer_trace_max_mem_size1000000;select * from information_schema.optimizer_trace;5、确定问题并采用相应的措施优化索引优化SQL语句修改SQL、IN 查询分段、时间查询分段、基于上一次数据过滤改用其他实现方式ES、数仓等数据碎片处理三、 案例分析案例1、最左匹配索引KEY idx_shopid_orderno (shop_id,order_no) SQL语句select * from t where order_no 查询匹配从左往右匹配要使用order_no索引必须查询条件携带shop_id或索引(shop_id, order_no)调换前后顺序。案例2、隐式转换索引KEY idx_mobile (mobile) SQL语句select * from user where mobile 12345678901 隐式转换相当于在索引上做运算会让索引失效。mobile是字符类型使用了数字应该使用字符串匹配否则MySQL会用到隐式替换导致索引失效。案例3、大分页索引KEY idx_a_b_c (a, b, c) SQL语句select * from t where a 1 and b 2 order by c desc limit 10000, 10; 对于大分页的场景可以优先让产品优化需求如果没有优化的有如下两种优化方式一种是把上一次的最后一条数据也即上面的c传过来然后做“c xxx”处理但是这种一般需要改接口协议并不一定可行。另一种是采用延迟关联的方式进行处理减少SQL回表但是要记得索引需要完全覆盖才有效果SQL改动如下select t1.* from t t1, (select id from t where a 1 and b 2 order by c desc limit 10000, 10) t2 where t1.id t2.id;案例4、in order by索引KEY idx_shopid_status_created (shop_id, order_status, created_at) SQL语句select * from order where shop_id 1 and order_status in (1, 2, 3) order by created_at desc limit 10 in查询在MySQL底层是通过 n*m 的方式去搜索类似union但是效率比union高。in查询在进行cost代价计算时代价 元组数 * IO平均值是通过将in包含的数值一条条去查询获取元组数的因此这个计算过程会比较的慢所以MySQL设置了个临界值(eq_range_index_dive_limit)5.6之后超过这个临界值后该列的cost就不参与计算了。因此会导致执行计划选择不准确。默认是200即in条件超过了200个数据会导致in的代价计算存在问题可能会导致Mysql选择的索引不准确。处理方式可以(order_status, created_at)互换前后顺序并且调整SQL为延迟关联。案例5、范围查询阻断后续字段不能走索引索引KEY idx_shopid_created_status (shop_id, created_at, order_status) SQL语句select * from order where shop_id 1 and created_at 2021-01-01 00:00:00 and order_status 10 范围查询还有“IN、between”案例6、不等于、不包含不能用到索引的快速搜索。可以用到ICPselect * from order where shop_id 1 and order_status not in (1, 2);select * from order where shop_id 1 and order_status ! 1;在索引上避免使用NOT、!、、!、!、NOT EXISTS、NOT IN、NOT LIKE等案例7、优化器选择不使用索引的情况如果要求访问的数据量很小则优化器还是会选择辅助索引但是当访问的数据占整个表中数据的蛮大一部分时一般是20%左右优化器会选择通过聚集索引来查找数据。select * from order where order_status 1 查询出所有未支付的订单一般这种订单是很少的即使建了索引也没法使用索引。案例8、复杂查询select sum(amt) from t where a 1 and b in (1, 2, 3) and c 2020-01-01; select * from t where a 1 and b in (1, 2, 3) and c 2020-01-01 limit 10; 如果是统计某些数据可能改用数仓进行解决如果是业务上就有那么复杂的查询可能就不建议继续走SQL了而是采用其他的方式进行解决比如使用ES等进行解决。案例9、asc和desc混用select * from t where a 1 order by b desc, c asc;desc 和 asc 混用时会导致索引失效案例10、大数据对于推送业务的数据存储可能数据量会很大如果在方案的选择上最终选择存储在MySQL上并且做7天等有效期的保存。那么需要注意频繁的清理数据会照成数据碎片需要联系DBA进行数据碎片处理。