付款查询、导出接口优化

问题接口

具体问题

HFINS 服务

  • /v2/0/csh/transaction-header/info
  • /v2/0/csh/transaction-header/info/export

主要问题在于查询慢和超过一定数据后导出报错

  1. 查询慢

查询接口在总 400 条数据,分页查询 size=10 的条件下,时间通常在 5 ~ 10 秒

  1. 导出报错

导出接口在生成环境中,数据量超过 500 必定报错。

两接口共用同一套查询方法,区别只在数据量。

问题原因

上述两接口所用查询方法主要分两部分,一是 SQL 查询,二是 SQL 查询结束后对部分字段属性的补充。

  1. SQL 问题

表的关联非常多,一共有 14 张表联查和一个子查询,其中只有两个类型表数据量小,其他均是数据量大的表,虽然大部分连接是通过索引,但是性能问题依旧很大。

  1. 补充属性过程的问题

在测试环境中,employeeCode 比较单一,所以在导出时并没有发现报错,但是生产环境的数据,employeeCode 和数据量基本上 1: 1,在通过 employeeCode 查询 employeeName 的 Feign 请求中,请求方法是 GET,所以 URL 携带的 employeeCodes 超出了长度限制,于是出行了异常。

解决方案

Feign 异常处理

上述的两个问题中,Feign 请求的问题比较好处理,主要有两个方案。

  1. 将通过 employeeCodes 获取 employeeName 的请求设计为 POST,此方案应是标准方案。

  2. 对查询进行切片分批查询,比较好的切片大小应该让 URL 长度接近 4096 个字符,这样既不会超出 URL 长度限制,也不会切分太多,导致处理时间过长。

观察已有代码,发现之前已经有人处理过该问题,使用的是切片方案,这里直接使用已有代码节省时间。

SQL 优化

SQL 的优化基本是围绕着索引、反范式(添加冗余字段)等做文章,但一些复杂业务不得不编写这类复杂、低性能的 SQL,除了设计和一些细节上的优化,其余的优化空间只能具体情况具体分析了。

这个付款查询的 SQL 主要的问题在于(最初的开发节省心智,直接把所有逻辑写在一条 SQL 里面):

  1. 通过关联多张表来给一些字段赋值,即使这个字段不在给定的查询条件中

  2. 使用了 LEFT JOIN 针对互斥的字段关联两张大表,多做了没有意义的表连接。

优化方案

针对上述问题,就可以做一些大的改动了。

  1. 拆开不含查询字段的表,对于一些只是需要关联而不需要进行查询的字段,可以通过另外的查询再来补齐这些字段。减去这些相关的表之后,还有 8 张表关联。

  2. 针对这个互斥的字段或类型,使用 JOIN 内连接加上 UNION,再次减少了 3 张关联的表。

经过前面两步,最多关联的表已经减少到了 5 张,在不修改表的情况下,已经达到了最简洁的状态。

最后,缺少的字段则需要在业务代码中进行补齐,只需要权衡好代码的简洁和性能即可。

测试

在测试环境下,400 条数据,响应从 7S 降低到了 1S 左右,在生产环境中,性能有更明显的提升。