15天的性能优化工作,5方面的调优经验(转发)

简介: 总思维导图 1、代码层面  (1)for循环中不要利用 + 号去拼接字符串        在循环次数比较多的for循环中,我们也不要利用 + 号去拼接字符串。

总思维导图

img_d17937cdbb79e81e88d87643ae3d9bd8.png


 1、代码层面

  (1)for循环中不要利用 + 号去拼接字符串

        在循环次数比较多的for循环中,我们也不要利用 + 号去拼接字符串。具体例子如下:

img_393079b900166fb375fc5c67f0530fef.jpe

        具体解决方法: 根据具体的业务场景,

                1>、使用 StringBuffer(线程安全)或者 StringBuilder(非线程安全)

                2>、使用数组

img_ec3d6d689a8270dfe7b43218181acdf2.jpe

              设置容量参数提高系统性能

                    对于 StringBuffer(线程安全)或者 StringBuilder(非线程安全),都有相应的构造方法:

img_7c0b7809acd4a524918450313111461e.jpe

如果我们可以事先知道需要拼接的字符串长度,设置容量参数,防止 StringBuffer 在源码内部进行一系列复杂的内存复制操作,影响性能。

如上面的  StringBuilder stringBuilder = new StringBuilder(Integer.MAX_VALUE);

  for循环建议写法

for (int i = 0, int length = list.size(); i < length; i++)

    (2)方法的返回值

返回List:

img_312f5d4510668fdd85ada24addfaa9d6.jpe

解决方法:

img_63dc48dba1980299ad23f51301eee985.jpe

返回Set:Collections.EMPTY_SET

返回Map:Collections.EMPTY_MAP

返回Boolean:Boolean.TRUE


 (3)不要再for循环中查询数据库

    解决:

        根据业务场景,把for循环中的多次连接数据库查询,写到sql中去查询,既一次性查询出来

        根据业务场景,看是否可以利用缓存,提高查询效率

 (4)去掉System.out.println

            代码部署到生产环境前,去掉全部System.out.println

 (5)四种数组复制方式的性能比较和抉择

数组copy有很多种方法,效率不一。我们先看下面具体实例:

img_bb743b6b9c2e4735147dbd1bd14c26c1.jpe

运行结果:

img_3920e166fbdbaecd13b061b1e5a746c6.jpe

    多运行几次,我们得出数组复制效率:

    System.arraycopy > clone > Arrays.copyOf > for

    综上所述,当复制大量数据时,使用System.arraycopy()命令。

  (6)实现高性能的字符串分割

        实现字符串的分割的方法有很多种,常用的是 split ,StringTokenizer ,indexOf 和 substring 的配合,以及一些开源工具类,如:StringUtils。它们各有优缺。

img_0aac74e68e8d29619f4f2f8c1ec9e158.jpe

运行结果:

img_85a061b291a2b8c65a048871878f8077.jpe

从上面例子可以看出,字符分割的性能,由高到低的排序为:StringTokenizer > split ,StringUtils.split > indexOf 。有些书籍写着 indexOf 的性能是最高的,但是按照我的测试,index的性能是最差的。但是事物都有两面性,从上面的例子也可以看出,虽然 StringTokenizer 的性能高,但是代码量多,可读性差,而 split 代码相对就整洁多了。

  (7)切勿把异常放置在循环体内

try-catch语句本身性能不高,如果再放到循环体中,无非是雪上加霜。因此在开发中,我们要极力避免。

例:

img_90a65b884859509d4b7f95ba4957867a.jpe

正确做法:

img_982dde849d98e7dffa696a5a4678b50c.jpe

综上所述:不要再循环体内执行复制,耗时的操作。

  (8)尽量缩小锁的范围

            锁优化的思路和方法总结一下,有以下几种。

                减少锁持有时间(尽量缩小锁的范围)

                减小锁粒度

                锁分离

                锁粗化

                锁消除

我们应该确保我们只在必要的地方加锁,将锁从方法声明移到方法体中会延迟锁的加载,进而降低了锁竞争的可能性。先看下面的实例:

img_dc604de9a6310d7742f06d2524f43819.jpe

打印结果:

img_661a55fc5f901ad6b0f261d2da2817ff.jpe

总结:因为,一个线程访问了 synchronized 同步代码块中的代码,另一个线程不可以访问该对象的任何同步代码块,但可以访问非同步代码块。所有缩小锁的范围可以在一定程度上提高代码性能。

  锁分离

最常见的锁分离就是读写锁ReadWriteLock,根据功能进行分离成读锁和写锁,这样读读不互斥,读写互斥,写写互斥,即保证了线程安全,又提高了性能。

还有就是网上一个高手写的一个例子:

img_2d6b885d474a87728c5f4f87d7c3e2b2.jpe

优化后:

img_98633302ffbbc82cad7aa89a984bc34c.jpe

 文件导入导出注意使用缓存流

        (9)批量插入数据性能优化

       1.1 问题一

直接批量保存3万多条数据。

img_bda17a3e55b6a322669e5e50686e97dc.jpe

1.2 问题二

批量保存时,利用UUID生成工具,给主键设置Id。找出Hibernate的先查询后更新的机制触发,造成不必要的查询损耗。

img_ec0ff97b938d92bb9b4a97fcecc0b2a5.jpe

1.1 问题一解决方法

对于问题二,我们可以把所有数据,每500条进行一次批量保存操作,速度会比一次性批量保存好。具体如下:

img_552af356dcb3c797e4b416d6a7ff8120.jpe

1.2 问题二解决方法

对于问题三,由于Hibernate在进行插入时,会判断数据是进行插入还是进行更新。如果模型的主键不为空,查询数据后,再进行更新数据,否则,进行插入数据操作。因此,我们在进行插入操作时候,不要设置模型的主键,可以避免不必要查询消耗。

pcsTestcase.setId(UUIDUtils.generate());

2、业务层面

    减少前端请求数

    过度复用方法带来的性能问题

    后端如果需要一次性加载数据,防止多次请求数据库

3、数据库层面

    (1)SQL语句大小写规范

我们在写SQL的时候,通常会出现大小写混用的情况。如下:

select * FROM pm_testcase pt where pt.Name = ‘ay’

正确的做法是SQL语句全部大写或者全部小写。如下:

–全部小写

select * from pm_testcase pt where pt.name = ‘ay’

–全部大写

SELECT * FROM PM_TESTCASE PT WHERE PT.NAME = ‘ay’

    (2)PostgreSQL执行计划

PostgreSQL的执行计划,做为数据库性能调优的利器,有必要在开头简单的介绍下。

img_740de949d60cfb79b17977788bec680a.jpe

cost说明:

第一个数字0.00表示启动cost,这是执行到返回第一行时需要的cost值。

第二个数字4621.00表示执行整个SQL的cost

通过查看执行计划,我们就能够找到SQL中的哪部分比较慢,或者说花费时间多。然后重点分析哪部分的逻辑,比如减少循环查询,或者强制改变执行计划。

更多执行计划 Explain,可网上搜索。

建立索引避免全表扫描

首先,在数据库里有一张表 pm_testcase,里面有150万条数据。

如下SQL,我们利用执行计划,对创建时间(created_time)进行排序,输出执行计划结果。

img_0451f2ee8c77cecfd2e0b019b5d5e596.jpe

cost=说明:

第一个数字4103259.72表示启动cost,这是执行到返回第一行时需要的cost值。

第二个数字4107084.44表示执行整个SQL的cost。

该语句总共耗时 4107084.44

这里我们创建 created_time 索引,对相同语句执行 程序清单 2-1 的SQL,得到的执行计划结果为:

img_e797ca06a38ae0752df44dc37dc83180.jpe

很明显,执行整个SQL的 cost 由 4107084.44 减少到 384739.28

因此,为了避免全表扫描,建议在考虑在 where 及 order by 涉及的列上建立索引。

防止索引失效

我们应尽量避免在 where 子句中使用 != 或 <> 操作符,否则引擎将放弃使用索引而进行全表扫描。

如下例子,我们在 pm_testcase 的 code 上添加了索引:

img_1d8eac1ec849bad9f2b6866ce4659339.jpe

通过上面的例子可以看出,!= 操作符使得索引失效。

    (4)避免建立太多的索引

索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 和 update 的效率,因为 insert 或 update 时有可能会重建索引,所以视具体情况而定。一个表的索引数最好不要超过7个,若太多则应考虑一些不常使用到的列上建的索引是否有必要.

    (5)关于查询效率的几点建议

尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。

尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为变长字段存储空间小,对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库。备注、描述、评论之类的可以设置为 NULL。其他的,最好不要使用NULL。

任何地方都不要使用 select from t ,用具体的字段列表代替 ,不要返回用不到的任何字段。

应尽量避免在 where 子句中使用 or 来连接条件,可以考虑使用 union 代替

in 和 not in 也要慎用。对于连续的数值,能用 between 就不要用 in,exists 代替 in

尽量避免在 where 子句中对字段进行表达式操作和函数操作

在Join表的时候字段使用相同类型,并将其索引

如果你的应用程序有很多JOIN查询,你应该确认两个表中Join的字段是被建过索引的。这样,SQL内部会启动为你优化Join的SQL语句的机制。而且,这些被用来Join的字段,应该是相同的类型的。例如:如果你要把 DECIMAL 字段和一个 INT 字段 Join 在一起,SQL 就无法使用它们的索引。对于那些STRING 类型,还需要有相同的字符集才行。(两个表的字符集有可能不一样)程序员站

    (6)优化子查询

子查询很灵活可以极大的节省查询的步骤,但是子查询的执行效率不高。执行子查询时数据库需要为内部嵌套的语句查询的结果建立一个临时表,然后再使用临时表中的数据进行查询。查询完成后再删除这个临时表,所以子查询的速度会慢一点。

我们可以使用join语句来替换掉子查询,来提高效率。join语句不需要建立临时表,所以其查询速度会优于子查询。大部分的不是很复杂的子查询都可以替换成join语句。

4、服务器层面

服务器的调优,就得根据客户提供的真实环境的配置。如服务器是几核几个CPU等等。服务器的硬件指标确定下来后,根据指标调整Tomcat,JDK,数据库,Apatch等配置参数。让整个环境达到最优的效果。这块工作一般不是开发人员进行的。但是我们要了解清楚一些配置参数

Tomcat && JDK

tomcat 配置

JDK垃圾回收机制

垃圾回收机制算法选择

JVM内存模型

Postgresql数据库配置

Linux服务器

输出系统日志最后10行 dmesg | tail

img_b0f096291cef9b971fcb0c52dda25e9f.jpe

该命令会输出系统日志的最后10行。这些日志可以帮助排查性能问题。

top命令

top命令是进行性能分析最常使用的命令,也是最重要的命令。每个参数代表什么意思,都必须非常清楚。

img_f92b9362b08fc3085b9d32a50e5d081b.jpe

top命令包含了前面好几个命令的检查的内容。比如系统负载情况(uptime)、系统内存使用情况(free)、系统CPU使用情况(vmstat)等。因此通过这个命令,可以相对全面的查看系统负载的来源。同时,top命令支持排序,可以按照不同的列排序,方便查找出诸如内存占用最多的进程、CPU占用率最高的进程等。

但是,top命令相对于前面一些命令,输出是一个瞬间值,如果不持续盯着,可能会错过一些线索。这时可能需要暂停top命令刷新,来记录和比对数据。

第一行:

img_cbe83224326bf2c329785165023da3b6.jpe

解释:

img_e07a53b22e1f19ded38823ddd70a0d15.jpe

第二行和第三行,当有多个CPU时,这些内容可能会超过两行。内容如下:

img_9208da3cdbdec7cc4a7be356fab4f219.jpe

最后两行为内存信息。内容如下:

img_bab2971ad12804acac28b5e3949ba908.jpe

进程信息区统计信息区域的下方显示了各个进程的详细信息。首先来认识一下各列的含义。

img_933375fc88fec1286af7901faccfccea.jpe

查询登录当前系统的用户信息:w命令

img_86261d39e6c24431f5f17313316b9d5f.jpe

可查询登录当前系统的用户信息,以及这些用户目前正在做什么操作

iostat

运行时,如果出现下面的提示信息

img_73b4e37f2ceaad424e966032c4bcbe5e.jpe

执行下 sudo apt-get install sysstat 即可。

Iostat提供三个报告:CPU利用率、设备利用率和网络文件系统利用率,使用-c,-d和-h参数可以分别独立显示这三个报告。

内存分析命令:free m

img_63e9dca3cbaf02051f55386df5943611.jpe

free: 查看系统内存的使用情况,-m参数表示按照兆字节展示。

最后两列分别表示用于IO缓存的内存数,和用于文件系统页缓存的内存数。需要注意的是,第二行-/+ buffers/cache,看上去缓存占用了大量内存空间。这是Linux系统的内存使用策略,尽可能的利用内存,如果应用程序需要内存,这部分内存会立即被回收并分配给应用程序。因此,这部分内存一般也被当成是可用内存。如果可用内存非常少,系统可能会动用交换区(如果配置了的话),这样会增加IO开销(可以在iostat命令中提现),降低系统性能。

查看CPU的占用情况 mpstat

显示每个CPU的占用情况,如果有一个CPU占用率特别高,那么有可能是一个单线程应用程序引起的。

img_0d51409156acd183597d9e7a235d038c.jpe

5、前端

由于我不是做前端的工作,所以没有太多的经验总结。不过代码方面性能优化有些是可以运用到前端。同事也可以减少前端的请求链接等等手段去优化。这里由于本人不了解,不做过多的阐述。

相关文章
|
7月前
|
消息中间件 缓存 NoSQL
如何做性能优化?
如何做性能优化?
|
25天前
|
存储 缓存 监控
后端性能优化:从理论到实践
在数字化时代,后端服务的性能直接影响着用户体验和业务效率。本文将深入探讨后端性能优化的重要性,分析常见的性能瓶颈,并提出一系列切实可行的优化策略。我们将从代码层面、数据库管理、缓存机制以及系统架构设计等多个维度出发,结合具体案例,详细阐述如何通过技术手段提升后端服务的响应速度和处理能力。此外,文章还将介绍一些先进的监控工具和方法,帮助开发者及时发现并解决性能问题。无论是初创公司还是大型企业,本文提供的策略都有助于构建更加高效、稳定的后端服务体系。
44 3
|
2月前
|
SQL 数据库 开发者
YashanDB产品调优实战:分享日常调优技巧及提升系统性能的实战经验
YashanDB产品调优实战:分享日常调优技巧及提升系统性能的实战经验
|
7月前
|
缓存 Java 数据库
后端性能优化的实践与经验分享
【5月更文挑战第15天】在互联网环境中,后端性能优化对提供卓越用户体验至关重要。关键领域包括:数据库优化(查询优化、索引优化、表结构优化、数据库维护)、缓存策略(内存缓存、CDN内容分发、HTTP缓存)、服务器配置优化(硬件升级、网络优化、操作系统调整)和代码优化(算法与数据结构、懒加载与异步处理、减少冗余计算、多线程与并发)。通过这些方法,可以提升响应速度,增强用户满意度,促进业务增长。
205 3
|
7月前
|
缓存 监控 前端开发
前端如何做性能优化?
【4月更文挑战第21天】前端性能优化涉及代码、图片、资源加载、渲染、网络等多个层面,包括压缩合并代码、利用缓存、压缩图片、使用CDN、减少DOM操作、启用HTTP/2等策略。其他方法还包括代码拆分、使用Web Workers和性能监控。优化过程应根据项目实际需求灵活调整,并注意平衡性能与代码可读性。
66 2
|
7月前
|
算法 编译器 C++
【C++】C++代码性能优化的方法(全网最适用)
【C++】C++代码性能优化的方法(全网最适用)
|
7月前
|
缓存 小程序 前端开发
小程序 如何做性能优化?
小程序 如何做性能优化?
|
数据采集 算法 编译器
倚天710规模化应用 - 性能优化 -自动反馈优化分析与实践
编译器优化分成静态优化与动态优化,静态优化指传统编译器gcc/llvm时,增加的优化等级,如O1,O2,O3,Ofast,此时,编译器会依据编译优化等级增加一些优化算法,如函数inline、循环展开以及分支静态预测等等。一般情况下,优化等级越高,编译器做的优化越多,性能会更会好。在阿里生产环境中,单纯依赖于静态优化,并不能达到程序运行流畅目的,通过分析CPU硬件取指令、执行指令,往往会出现一些分支预测失败导致iCacheMiss率高的场景,限制了程序的性能进一步提升。基于此,业务引入了动态反馈优化工具,依据生产环境的实际运行数据,反哺指导编译器对程序代码进一步调整编译优化策略,提高分支预准确率
|
监控 网络协议 Java
【深入了解系统性能优化】「实战技术专题」全方面带你透彻探索服务优化技术方案(系统服务调优)
系统运行缓慢,执行速度较差虽然没有对用户或公司造成实质性的损失,但它从侧面反映出系统在某些方面存在问题。可能需要对系统参数进行优化,或者对系统的设计和交互进行调整,这是后续系统性能优化的一个重要过程。我们将继续努力优化系统,以确保其高效运行和良好性能,以提升用户体验并最大程度地满足业务需求。我们希望通过系统调优的历程,解决当前存在的问题,并不断改进系统的运行,为用户提供更好的服务。
370 0
【深入了解系统性能优化】「实战技术专题」全方面带你透彻探索服务优化技术方案(系统服务调优)
|
存储 缓存 JavaScript
我工作中用到的性能优化全面指南(1)
在Web开发中,Web的性能优化是一个重要的话题。无论是页面加载速度,用户体验,或者是程序运行效率,都与Web的性能优化息息相关。 最小化和压缩代码 在构建过程中,为了减少文件的大小和加载时间,通常会对JavaScript代码进行最小化和压缩处理。这包括移除不必要的空格、换行、注释,以及缩短变量和函数名。工具如UglifyJS和Terser等可以帮助我们完成这个任务。
71 0