总结了巨多关于项目中慢查询的处理方式, 后续也将持续进行更新
概述
为什么需要优化
- 从用户角度:慢查询 会对用户体验产生负面影响,往往会造成c端用户失去耐心,b端用户怨声载道,大量用户流失。想象一下,一次简单查询都需要耗时数秒甚至数分钟时,这是任何产品都无法接受的
- 从项目角度:慢查询往往是由于工具使用的不合理 or 系统设计的不合理导致,可以映射出系统的不健康、设计的不合理。同时慢查询会导致一次查询的内存使用时间or内存使用量增加,容易引发gc、oom等问题,对其它模块资源进行挤占,严重时甚至会导致系统崩溃
优化思路
工作中接过众多校招生的代码,虽然他们也不断在对性能进行优化,但是最终慢查询还是走到了不可遏制的状态。
大量的事实证明,不停的加缓存、优化机器性能都不能保证从根本上消除慢查询
究竟是什么引发了慢查询?确定这点非常重要
阑尾炎只吃止痛药,解决不了问题,想要根上解决就必须开刀
常见的问题大概可以分为五个类别:
- 开发存在不规范的情况
- 没有合理的使用索引,慢sql优化
- 数据量过大
- 缺少合理的技术选型
- 系统设计混乱
优化方式
开发存在不规范的情况&索引使用
- 在循环中select查询(尤其是在java8stream流比较成熟的情况下一定不要偷懒,要在避免代码里如此进行查询),可以考虑在循环外进行批量查询内存中进行拼接,减少网络时间消耗
for{
//sql select查询
}
- 如果是超多分页的场景, 可以通过子查询的方式进行优化比如limit,offset, 从mysql中取出n+offset条数据,再在其中返回n条. 而利用自查子查询直接查出n条,通过id索引对应的记录出来,提高查询效率
select * from table_name where ...... limit 10000,10
-- 这样的查询会导致前面查询的10000条数据没有意义却占用了大部分的查询时间
select * from table_name where id in (select id from table_name where ...... limit 10000,10)
-- 改进后就可以大量缩小需要回表的数据量,从而加快查询
- 创建数据表的时候需要创建索引
- 查询数据的时候使用覆盖索引而不是
select *可以减少回表消耗的时间 - 考虑是否需要创建联合索引,如果需要联合索引的话, 使用请遵守最左匹配原则
- 对索引进行函数操作或者表达式计算会导致索引失效
- 通过explain命令来查看SQL的执行计划, 看SQL是否走来索引,走了什么索引, 通过show profile来查询sql对系统资源的损耗情况
- 在开启事务的时候也要尽可能减少锁的持有时间,如果进行修改更新操作, 会加行锁, 并发下可能会导致多个事务的请求等待行锁释放, 减少行锁的持有时间,就可以提高并发度
还有很多索引使用的问题这里就不一一列举,网络上的文章一抓一大把
数据量过大
还存在即使走的索引依旧非常慢的情况, 这种情况一般是由于过大的数据量导致的
- 可以先查看历史数据是否有保存的必要, 能把大量的旧数据删掉是最直接的方法, 历史数据可以同步到hive中方便日后做数据分析
- 如果不可以删除, 但是不会对历史进行查询修改, 如果对历史进行查询也只是根据指定的时间范围查询, 那可以考虑按照时间段进行分表操作. 在聊天分析系统中, 经过一层聚合后的数据是 老师+学生+日期的这样一个数据. 为了方便进行聚合采用了每天主动创建一张mysql表的这样的方式减少sql查询的响应时间(当时是百万级别, 其实性能上问题比较小) 但是这样也可以按照业务逻辑的时间进行区分, 也不失是一种解决方式
- 主从读写修改已经达到了瓶颈, 那么就可以考虑分库分表, 根据不同的业务将数据分在不同的表中, 可能根据用userd进行分表(因为业务中都是这种查询方式), 这样就设计到分库分表后的id如何生成(一般使用雪花算法比较多
- 采用中间添加缓存的方式减少业务的响应时间(一般业务场景为, 对同一记录会存在多次重复查询的操作, 并且最好是update动作比较少的场景), 业务数据会存在读取非真正实时的数据的情况, 因为redis要和mysql保证数据一致性, 而且涉及多变的查询条件时groupby sum,走缓存也不是一种很好的办法, 不好维护( 转介绍项目中就有需要保证这种groupby的缓存一致性的操作, 延时双删已经不适用了)
还有需要查询大量聚合数据的场景
- 和很多流计算的思想类似, 如果需要聚合,但是还要减少聚合的数据量, 那读取的就要是中间的聚合后结果(数据量要远小于原始表数据量), 比如我想查询7点到10点的总计数据, 那么我就可以每小时对上一小时的数据进行聚合, 这样查询7-10点的总计数据只需要查询聚合表的三行内容进行聚合计算即可
系统设计问题 未完待续