原SQL语句(所有相关敏感信息已做脱敏处理)

 

image-20210106140645055

sql解析顺序分析

1.from条件后的 table_xxx_activity表(只有5万条数据)字段查询条件过滤,根据目前的生产业务情况,最多不超过(小)几百条数据,每个项目下最多只建了几百个活动

没有覆盖索引,走辅助索引后,回表用Using where过滤

2.遍历1中的结果分别执行exist语句的子查询判断当条记录是否保留

exist语句1可以走索引PK_tablexxxregistry_37、38

exist语句2可以走索引table_xxx_registry_store_idx1、table_xxx_activity_areastore,但是没有覆盖索引需要走Using where

已知table_xxx_registry表数据60万,table_xxx_activity_areastore表数据400万

3.执行select部分,选择查询的字段和signUpCount字段的子查询

signUpCount字段的子查询可以走辅助索引PK_tablexxxregistry_38

4.排序用到PUBLISH_TIME字段,重新走Using filesort排序

5.limit截断

【时间估算大致情况】

查询1的时间 + 查询1的结果条数 * (exist语句1的时间 + exist语句2的时间) + exist判断后结果2的条数 *( select字段获取的时间 + signUpCount字段的子查询的时间)+ PUBLISH_TIME字段排序的时间

 

explain解析

 

初步分析

该语句为一个分页查询语句,慢查中报出的count语句为.queryForListPage(方法自动封装的语句

语句中嵌套了3个子查询

1.signUpCount字段

2.exist语句1

3.exist语句2

explain结果中出现了Using filesort排序,因为最终的order by t.PUBLISH_TIME DESC不在索引中出现

 

解决方案

1.原java代码中

在现有sql语句结果集上,添加count(1)自动封装了获取总条数的sql语句,而根据分析,count计算不需要通过order by,且原来的查询字段中所有字段均不参与最终条数计算,包括signUpCount子查询,可以使用新的

代替原来的方法,并去除掉对应的字段signUpCount子查询(对应key_len为390,id为2的那一步查询),排序(对应id为1中的Using filesort排序)等语句作为新的countSqlId进行总数量查询

2.signUpCount字段可以另外写逻辑单独查询,而具体展示数据查询的时候,因为有limit条件的存在,所以相对关联到的子查询数量会比较少

3.exist语句1、2 作为前置查询条件,先查询出结果集,再代入到本sql中作为新的in查询条件,或者做一个join查询,需要预先判断这个结果集的数量多少

方案2 子查询2表table_xxx_activity_areastore构建联合索引。ACTIVITY_CODE & AREA_CODE

5.排序字段order by t.PUBLISH_TIME DESC,可以看业务情况考虑是否使用id倒序排列,减少排序资源消耗

6.目前本表table_xxx_activity建立的索引已经非常多了,不便于重新新增新的联合索引

优化发布后验证结果,查询时间降低到700毫秒以下