那么创建订单需要生成1个主单,N个子单,这时很多这么写(代码仅表示执行流程):
insert(主单);for(子单:子单列表){ insert(子单);}复制代码所以就出现循环SQL操作,因为SQL操作比较耗时,循环的话就会大大拉大整个接口的rt时长,这种情况我们应该一次性把所有子单insert,而不是一次一次地操作,优化后代码类似为这样:
insert(主单);batchInsert(子单列表);复制代码Mybatits是支持循环标签的,所以在sqlMap文件里改造一下SQL就可以了。另外批量update也是可以的,执行批量操作需要在数据库链接加上参数allowMultiQueries=true 2.数据库索引索引当然是必须要建的,不然得查到什么时候。不过建归建,但是我们还要正确的运用它。我们可以通过explain命令检测SQL是否使用索引。EXPLAIN SELECT * FROM article WHERE id=10;
key和rows反应了使用的索引以及预计需要扫描的行数。还有一些我们需要注意的: 在我们优化Query语句中的ORDER BY的时候,尽可能利用已有的索引来避免实际的排序计算,可以很大幅度的提升 ORDER BY操作的性能。在有些 Query 的优化过程中,即使为了避免实际的排序操作而调整索引字段的顺序,甚至是增加索引字段也是值得的因为MySQL中,order by的实现有两种类型:
1).一种是通过有序索引而直接取得有序的数据,这样不用进行任何排序操作即可得到满足客户端要求的有序数据返回给客户端;
2).一种则需要通过 MySQL 的排序算法将存储引擎中返回的数据进行排序然后再将排序后的数据返回给客户端
我们建的索引为user_id,define_id,seq联合索引,可以看出第一张图排序define_id直接走索引,第二张图走不了索引需要额外的排序操作Using filesort.group by 其实也是进行了order by操作 然后进行分组,所以group by也是类似的优化方式。 DISTINCT尽量少用,DISTINCT其实也是进行了一次group by操作,然后每一组取的第一条记录。 java应用的类型一定和数据库索引列的类型匹配,例如java类型为long,数据库类型为varchar,这样去查询是用不了索引的,但是不会报错。下图是两种方式的对比:
3.count计数千万不能用计数也是我们经常用到的,比如优惠券领取数量,统计活动参加人数。这些有时是和业务强耦合的。比如秒杀只能卖出多少件等等。这类场景我们千万不能使用count来计数。我们来分析一下为什么不使用count:
1).count会查询所有满足条件的记录,如果表非常大,这将可能导致全表扫描,这后果大家都知道的吧。2).如果使用count来控制,那么在业务逻辑执行期间,肯定要加锁,否则刚才count的结果就白操作了,这将也会阻止所有对该活动的请求。
这种场景我们一般都是在需要控制的记录上加个计数字段,比如控制最大领取值num=10个。那在业务逻辑里面可将对总数控制转为通过SQL的方式,update xxx set num=num-1 where id=xx and num>0;这是原子操作,可保证一定不会超领。根据返回结果判断是否执行成功(返回结果为影响的行数)。 4.锁单机锁和分布式锁,锁其实我们能够避免就不要使用它,因为加锁就代表只能串行执行,并发数降为1,这肯定影响性能。 如果是类似库存扣减的场景,可参考第3条。通过数据库的原子操作来避免。如果是更新等操作,可通过乐观锁来避免长时间的阻塞。如果非要使用锁,不管是单机锁还是分布式锁,我们一定要评估该锁的影响范围,是针对单个用户userId还是所有的用户userId,单个用户是可以采用的,因为单个用户并发度极低,但是如果是所有用户的操作加锁,那一定要好好评估,这个操作会导致所有用户的类似操作阻塞。5.适当冗余在分布式系统中,冗余应该是非常常见的情况。我们这个时候就不要追求数据库范式的标准了,因为按照数据库第几范式来设计,所有字段都不冗余,但是这给我们查询带来很大麻烦。可能我们查一个订单,需要关联查询,查子单信息,查商品信息,查支付信息等等,查询这么多,想想我们接口的rt能快吗,qps能高吗。将商品名称等基本信息冗余可减少对其实模块的查询,未尝不是一种好的方式。 6.Redis缓存其实缓存在我们系统普遍都用到了,所以对这部分优化不多。还是总结一些经验。缓存的刷新策略选择:失效刷新还是定时刷新。因为监控到很多接口RT总是有规律的变慢,这是因为都是在缓存失效的时候,需要从db及其他模块组装数据,然后推到缓存,这时所有请求都走不了缓存,在流量大的时候也有可能成为致命的因素。如果是这种情况,例如首页推荐商品、推荐帖子等等访问量大且相同的场景可以通过定时刷新的方式。Keys*命令线上严禁使用:Redis是单线程,该命令的执行将会导致所有后续请求阻塞,影响整个系统性能。 7.搜索引擎可能看到这个比较疑惑,搜索引擎怎么还能优化RT,他比DB当然慢,但是在某些场景他可以比DB更快。例如一个社区论坛,需要对文章进行筛选排序,总共十来个字段,而且自由组合,这时DB就无能为力,因为条件太多,各种排序操作,关联操作,数据库没办法建索引。我们可以通过将A、B表中的字段构建成完整的信息,推送到搜索引擎,查询的时候直接根据条件搜索。这样既能保证rt,又能避免DB被复杂查询拖垮。