一、项目背景
该项目是一个对资金还、回款改造的项目。以前的做法是,在签约或者发生标转让的时候生成回款信息,直接插入回款表,下次回款时从回款表里面查找。现在这张表有2亿+条数据,100G的数据量,并且还在快速增长,随时都有可能爆发出问题。改造的逻辑是,按照投资人投资的金额占比来实时计算回款。
二、性能优化
1、缓存优化
针对我们这种应用场景,大部分情况是投资人查看自己投了某一个标的回款情况。这里,可以根据标和投资人做一个回款记录的缓存,在service层就可以把用户请求给做掉。为了保证数据一致性,在实际发生回款的时候,刷新这条缓存数据。
2、多线程优化
线上的服务器一般都多核的,完全可以开多个线程同事跑,充分利用计算资源。在这个项目中,对历史数据做订正的时候,同时开了20个线程并发修复历史数据。这里要注意一点,涉及到资金的数据一致性要求很高,一般会用到事务,这里多线程要防止发生死锁。
3、对常用的字段建索引
本次项目中涉及到几个表关联查询,几张表有1000w-2000w条数据,对关联的字段建立索引之后,单次查询时间由原来的1.5s降到了200ms左右。查询效率提高了好几倍。
4、Ibatis表达式优化
单个查询中,一个SQL上千个字符,如果直接把sql裸露在<select> </select>关键词中间,其实ibatis要做很多检查的工作,如果这些sql是纯查询语句,不涉及到ibatis关键字,可以用这个<![CDATA[ ]]> 括起来,性能可以提高很多。我的一个测试用例中,由原来的700ms压缩到200ms。
5、SQL结构优化
简单的SQL结构优化空间可能不大,复杂的SQL尤其是涉及关联查询或嵌套查询的,如果单表数据量比较大,结构优化空间就很大了。每一次关联就是笛卡尔乘积,如果两张表都有一定的数据量,则乘积的数据量就很大了。这里,我们可以遵守几条原则:
5.1 条件尽量用到尽可能多降低笛卡尔积的子查询中,使得总得笛卡尔积最小化。比如说:A表中有20条数据;B标中有10条数据。如果过滤条件放在A中查询能过滤15条数据,同样的过滤条件放在B中查询能过滤7条数据,则把过滤条件放在A中过滤,因为放在A中总体笛卡尔积只有有50,而放在B中笛卡尔积则有60条数据。
5.2 查询条件尽可能的走索引。比如同样的查询条件,可以拆分开,使得其中部分查询可以走某一张表的索引,则拆开查询。
5.3 能不要加括号的则不要加括号。增加了括号会限定执行的顺序。其实数据库自身会根据查询条件优化查询的。如果增加不必要的括号,会限定查询的顺序,使得数据库无法优化查询。
5.4 构建组合索引,索引字段顺序问题。构建组合索引,常用来查询的字段放在前面,部分查询字段顺序保持跟索引字段顺序一致。
5.5 刷选最多的条件优先执行。把刷选数据最多的条件放在最先执行的位置。
5.6 慎用merge into语句。批量执行merge into时,当符合条件就更新,不符合条件就插入。这种情况性能很差。可以把整个list放到数据库过滤一把,存在的就批量更新,不存在的,就批量插入,这种方式,性能更好。
今天想到的就这些,先写这么多。