如何调优?

SQL调优是一个很大的概念,但是大致就是从索引优化、代码/业务优化、架构优化几个方向上来做:

  • 比如最常说的索引优化:
    1. 我们可以使用覆盖索引避免回表;
    2. 然后就是尽量满足最左匹配原则,避免索引失效;
    3. 还有就是索引也不宜过多,这样写入的时候维护索引的成本就高了,也占磁盘空间,mysql选择索引的时候也会选择困难
  • 再从从代码/业务层面的话:
    1. 减少sql次数,不在循环发sql,避免频繁数据库IO
    2. 可以尽量控制事务范围,用小事务避免使用大事务,不在事务中做文件/网络IO操作
    3. 在业务允许的情况下,使用合适的隔离级别,如RR->RC,避免锁等待
    4. 在业务上做优化,比如如果需要查询未加索引的情况时,要求用户必填一个加了索引的字段,先筛选掉一部分数据在逐行查询
  • 最后就是架构上来说:
    1. 最容易想到的就是加缓存中间层分担数据库压力,如redis、caffiein、guava
    2. 可以使用读写分离、分库分表(注意数据库主键与业务主键分离)+使用OLAP数据库定时归档减少OLTP数据库的数据量来分担数据库压力
    3. 还可以通过升级数据库版本、采用性能更好的连接池来优化

调优大方向

  1. 索引优化:联合索引、覆盖索引、隐式类型转换、控制索引数量
  2. 架构优化:读写分离、分库分表、缓存中间层
  3. 数据库升级/版本升级:5.7->8.0优化器改进、更好的执行计划
  4. 更好的查询引擎/混合架构:使用OLAP分析性数据库,如ClickHouse、Doris、TiDB
  5. 并发/锁优化:避免大事务、合理使用隔离级别(RR->RC),避免锁等待
  6. 代码优化:不在事务中进行网络IO/文件IO操作、使用短事务、减少SQL次数,避免频繁数据库IO
  7. 业务优化:在查询未用索引字段强制必填索引字段先筛选一部分

索引优化技巧

  1. 最左前缀原则:联合索引必须从最左边的字段开始使用。
  2. 索引覆盖:查询的字段都包含在索引里,避免回表,提高性能。
  3. 索引下推:MySQL 5.6+ 提供优化,先在存储引擎层用索引过滤条件,减少回表次数。
  4. 控制索引数量:降低写入维护索引成本,避免查询优化器难以选择
  5. 索引选择性:读多写少,越散列的字段越适合加索引

你做过哪些具体的优化呢?

像架构的优化太大了,我们最常做的就是对索引和业务的优化

  1. 没使用联合索引导致回表的查询慢
    • 比如我记得之前因为刚开始真正的就是到企业工作,之前更多是做的一些比赛和练手的项目,所以对于企业这种模式还是没经验,当时我记得是有一个新的查询功能嘛,然后我当时就是按平时我做练习的一些习惯,在mysql里把数据库语句写好了查出来数据,然后改成xml放到mybatis里,但是其实这种存在的问题就是可能我需要的这些字段没有建立联合索引,所以会导致这个查询效率不高,当时这个接口也确实查询比较慢,就定位到这里,其实当时xml文件上面有之前同时写好的建立了联合索引的<sql>标签,只是当时我没有使用这个标签去查,然后后面我就改成了这个联合索引嘛,然后通过在这个业务层把需要的字段组装成vo再返回给前端嘛,提高了这个查询到效率。
  2. 用户查询无索引字段的业务优化
    • 还有就是用户反馈某个查询特别慢,反馈到我们这里,然后要求我们改,当时我们去看了,那个需求就是要查询一个无索引的字段,这个没有索引慢是正常的,当时我们评审了这个是一个就是修改较为频繁的字段,建立索引不合适,会导致写入很慢,但是这个字段又有查询的需求,还要快,当时我们跟产品扯了好久,最后我们就是采取折中的方案,就是你要查询这个没有索引的字段,那你必须填一个建立了索引的字段,这样我们通过有索引的字段先筛掉一部分数据,再对剩下的数据全表扫,可以提升一部分的查询效率