本文其实是结合业务做了一些很简单又非常有效的优化,并没有涉及什么高大上 MySQL 底层原理。
搜索优化
在应用中,往往会有很多需要搜索的时候,比如订单里面根据订单号搜索,客户管理里面根据客户的编号搜索等。
场景:根据订单号搜索
背景:搜索的字段只有 “关键字” 一个字段,会使用这个字段去模糊匹配很多不同表的字段。
在订单搜索里面,在查看慢查询的时候,发现大多数的慢查询来自于对订单号的查询。因此可以猜测:用户搜索订单的时候很多情况下是通过订单号来搜索的,而订单号本来有索引,如果通过订单号精确匹配的话,可以将搜索时长缩短到 10ms 级,而原来起码需要 5s 以上,甚至 10s 20s。
优化方法:
订单搜索的时候,由于订单号的格式比较固定,可以通过简易的判断就可以几乎 100% 确定是一个订单号,因此在搜索其他字段之前。
先单独通过订单号查找是否有关键字对应的订单,有的话,直接返回相应订单即可,不再需要搜索其他字段了。
效果:原来几秒几十秒的搜索 => 100ms 左右完成。
类似场景,客户搜索里面:管理员搜索的时候,因为绝大多数情况下是通过客户编号或者手机号或客户企业名称来搜索的,因此优化为:先通过客户编号、手机号、客户企业名称精确匹配,匹配到了,直接返回对应数据,不再搜索其他字段。效果:几秒十几二十秒 => 100ms。
场景:搜索中文不匹配纯英文字母的字段
在客户列表里面,有很多慢查询,但是查看慢查询语句发现,明明是中文的字段,却在查找过程中匹配了一些没有必要匹配的字段,比如:用中文去匹配只保存拼音的字段,或者用中文去匹配手机号。
优化方法:客户搜索的时候,如果检查到客户搜索的关键字为中文,则不再 like 匹配拼音字段、手机号字段。
效果:原来几秒甚至十几二十秒的请求 => 2s 内可以完成。
场景:不必要的 order by
还是搜索,在列表搜索的时候,有些地方的搜索很多时候搜索结果只有 1
条,又或者几条,反正几乎 100% 的情况不会超过 50 条。但是尽管如此,MySQL
语句里面还是有 order by
子句。而这个 order by
是有点多余的,甚至会对性能造成很严重的影响。比如,只有一条搜索结果数据的情况下,order by
的开销完全是多余的。
优化方法:如果判断关键字长度达到一定长度,基本上能搜索出来的结果只有那么一两条了,这个时候直接去除
order by
,然后获取到查询结果后再在代码里面做排序(就是对搜索的结果做排序,但实际上很多情况下都是没有必要的,因为只有一条数据)。
效果:原来十几二十秒的请求 => 1s 内可以完成。
场景:order by id
在有些 sql 中,往往会需要根据 id
做逆序查询,但是如果我们的语句中有几个条件的话,只
order by id
会很慢,但是如果我们有另外的 where
字段,可以考虑将 id 和 where 的字段做一个联合索引,然后
order by
这个索引中的字段,这样一来 MySQL
排序就可以直接用索引的排序的。
效果:几秒的查询 => 几百毫秒
其他:查询尽量覆盖索引
我们在做过滤的时候,如果 where 条件的时候有某些字段不存在索引里面的话,会需要进行回表,数据量大的时候效率很低。
后记
从上周某一天开始到今天,持续做了一些优化性的工作。其中有一些自己以前未曾尝试过的做法,但是效果奇好。也有一些值得记下来,对自己以后做优化有参考价值的。还有一些跟优化关系不大的,比如应用的可观测性,说到底关系还是有,只有先发现了性能问题才能进一步去优化。
所以,也就有了本文。