尊嘟假嘟?三行代码提升接口性能600倍

2024-01-12 01:36

本文主要是介绍尊嘟假嘟?三行代码提升接口性能600倍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、背景

  业务在群里反馈编辑结算单时有些账单明细查不出来,但是新建结算单可以,我第一反应是去测试环境试试有没有该问题,结果发现没任何问题!!!  然后我登录生产环境编辑业务反馈有问题的结算单,发现查询接口直接504网关超时了,此时心里已经猜到是代码性能问题导致的,接来下就把重点放到排查接口超时的问题上了。

二、问题排查

遇到生产问题先查日志是基本操作,登录阿里云的日志平台,可以查到接口耗时竟然高达469245毫秒

这个结算单关联的账单数量也就800多条,所以可以肯定这个接口存在性能问题。

image

但是日志除了接口耗时,并没有其他报错信息或异常信息,看不出哪里导致了接口慢。

接口慢一般是由如下几个原因导致:

1. 依赖的外部系统慢,比如同步调用外部系统的接口耗时比较久

2. 处理的数据过多导致

3. sql性能有问题,存在慢sql

4. 有大循环存在循环处理的逻辑,如循环读取exel并处理

5. 网络问题或者依赖的中间件比较慢

6. 如果使用了锁,也可能由于长时间获取不到锁导致接口超时

当然也可以使用arthas的trace命令分析哪一块比较耗时。

由于安装arthas有点麻烦,就先猜测可能慢sql导致的,然后就登录阿里云RDS查看了慢sql监控日志。

image

好家伙一看吓一跳,sql耗时竟然高达66秒,而且执行次数还挺多!

我赶紧把sql语句放到数据库用explain命令看下执行计划,分析这条sql为啥这么慢。

EXPLAIN SELECT DISTINCT(bill_code) FROM `t_bill_detail_2023_4` WHERE  
(settlement_order_code IS NULL OR settlement_order_code = 'JS23122600000001');

分析结果如下:

image

如果不知道explain结果每个字段的含义,可以看看这篇文章《长达1.7万字的explain关键字指南!》。

可以看到扫描行数达到了250多万行,ref已经是最高效的const,但是看最后的Extra列Using temporary 表明这个sql用到了临时表,顿时心里清楚什么原因了。

因为sql有个去重关键字DISTINCT,所以mysql在需要建临时表来完成查询结果集的去重操作,如果结果集数据量比较小没有超过buffer,就可以直接在内存中去重,这种效率也是比较高的。

但是如果结果集数据量很大,buffer存不下,那就需要借助磁盘完成去重了,我们都知道操作磁盘相比内存是非常慢的,时间差几个数量级。

虽然这个表里的settlement_order_code字段是有索引的,但是线上也有很多settlement_order_code为null的数据,这就导致查出来的结果集非常大,然后又用到临时表,所以sql耗时才这么久!

同时,这里也解释了为什么测试环境没有发现这个问题,因为测试环境的数据不多,直接在内存就完成去重了。

三、问题解决

知道了问题原因就很好解决了,首先根据SQL和接口地址很快就找到出现问题的代码是下图红框圈出来的地方

image

可以看到代码前面有个判断,只有当isThreeOrderQuery=true时才会执行这个查询,判断方法代码如下

image

然后因为这是个编辑场景,前端会把当前结算单号(usedSettlementOrderCode字段)传给后端,所以这个方法就返回了true。

同理,拼接出来的sql就带了条件(settlement_order_code IS NULL OR settlement_order_code = 'JS23122600000001')。

image

解决起来也很简单,把isThreeOrderQuery()方法圈出来的代码去掉就行了,这样就不会执行那个查询,同时也不会影响原有的代码逻辑,因为后面会根据筛选条件再查一次t_bill_detail表。

改代码发布后,再编辑结算单,优化后的效果如下图:

image

只改了三行代码,接口耗时就立马从469245ms缩短到700ms,性能提升了600多倍

四、总结

感觉压测环境还是有必要的,有些问题数据量小了或者请求并发不够都没法暴露出来,同时以后写代码可以提前把sql在数据库explain下看看性能如何,毕竟能跑就行不是我们的追求😏。

文章转载自:烟味i

原文链接:https://www.cnblogs.com/2YSP/p/17955463

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

这篇关于尊嘟假嘟?三行代码提升接口性能600倍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/596375

相关文章

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

usb接口驱动异常问题常用解决方案

《usb接口驱动异常问题常用解决方案》当遇到USB接口驱动异常时,可以通过多种方法来解决,其中主要就包括重装USB控制器、禁用USB选择性暂停设置、更新或安装新的主板驱动等... usb接口驱动异常怎么办,USB接口驱动异常是常见问题,通常由驱动损坏、系统更新冲突、硬件故障或电源管理设置导致。以下是常用解决

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim