在测试压测过程中发现有一个统计接口qps只有3.4/sec,但是脚本比较简单,只是进行了count和sum,也没有特别复杂的查询条件,经过本地调试,发现把脚本单独拉到控制台执行只要600毫秒,并且本地调用接口前9次都很快,第十次开始脚本就要执行2秒,重启项目之后还是一样。

脚本示例

select
        count(*) as item_no_num,
        COALESCE(sum(m.sum_insured),0) as sum_insured_sum,
        COALESCE(sum(m.sum_priceTax_total),0) as sum_priceTax_total_sum
        from policy_list m
        where m.state = '1'
        and st_contains(st_geometryfromtext(#{range},4326),m.gemo)
        <choose>
            <when test='dataDate != null and dataDate != ""'>
                AND m.start_date <![CDATA[<=]]> #{dataDate}
                AND m.end_date <![CDATA[>=]]> #{dataDate}
            </when>
            <otherwise>
                AND m.start_date <![CDATA[<=]]> NOW()
                AND m.end_date <![CDATA[>=]]> NOW()
            </otherwise>
        </choose>

处理过程

在百度查了一下,发现有挺多帖子说了这个问题,解决方案一般分为三种

1、将传参改为java.util.Date

2、将传参改为java.sql.Date

3、将#{date}改为${date}

第一个和第二个方法都试了没有作用,第三个方法可以正常执行,网上说是mybatis的预编译有问题,改为$后就不会预编译了而是直接拼接到sql中。

但是这样有一个问题,由于date是前端传过来的,所以会有SQL注入的风险,于是在执行脚本之前加了一个日期转换,如果前端传过来的日期字符串可以正常转换为Date就没问题,否则就会报错。

代码如下:

@Override
    public SearchPolicyItemCountVo searchPolicyItemByGeometry(SearchItemNoPositionListCommonDTO searchDTO, String companyCode) {
        // 对日期格式做校验
        String dataDate = searchDTO.getDataDate();
        if (StrUtil.isNotBlank(dataDate)) {
            DateUtil.parse(dataDate);
        }
        return guMainMapper.searchPolicyItemByGeometry(
                searchDTO.getRiskClassList(),
                searchDTO.getRiskCodeList(),
                searchDTO.getPolygon(),
                dataDate,
                searchDTO.getSearchCompanies(),
                companyCode);
    }

最终脚本如下:

select
        count(*) as item_no_num,
        COALESCE(sum(m.sum_insured),0) as sum_insured_sum,
        COALESCE(sum(m.sum_priceTax_total),0) as sum_priceTax_total_sum
        from policy_list m
        where m.state = '1'
        and st_contains(st_geometryfromtext(#{range},4326),m.gemo)
        <choose>
            <when test='dataDate != null and dataDate != ""'>
                AND m.start_date <![CDATA[<=]]> '${dataDate}'
                AND m.end_date <![CDATA[>=]]> '${dataDate}'
            </when>
            <otherwise>
                AND m.start_date <![CDATA[<=]]> NOW()
                AND m.end_date <![CDATA[>=]]> NOW()
            </otherwise>
        </choose>

由于没有找到其他更好的方法, 只能先保证项目先能正常运行