最近帮忙公司的几个项目组进行了不同方面的性能优化,发现几个项目都出现了一些共性的问题。这里写一篇文章,总结一下这几类问题,以及其对应的解决方案。方便其它项目组参考。

 

常见问题一:打开页面非常慢,有的项目打开一个页面竟然要 20 多秒。


优化步骤:

  1. 降低每一个页面的请求数:使用浏览器跟踪打开页面后所有的请求,并逐一排查,把没有必要向服务端发起的请求优化掉,减少 Round Trip 次数。
  2. 针对每一个请求进行优化:对请求逐一排查,看看分别是哪些请求占用了较多的时间。
    如果该请求是 JS 文件,则考虑使用压缩版本(例如正在使用的 EXTJS,应该使用 ext-all.js 1.9M,而不是 ext-all-debug.js 4.5M)。
    静态资源要尽量启用缓存。
  3. 将每次请求所对应的数据库访问次数降低到最低:这一步属于后端优化。
    每一个请求到达服务端后,都会做一系列的操作,例如:初始化当前用户、角色、权限、当前模块、业务逻辑、日志等。
    对于前四个操作,往往是所有页面都需要初始化的,那么我们需要使用 Session 或 Cache 等技术来优化,以防止每次请求都重新访问数据库。
    对于业务逻辑、日志等,我们主要解决的是《ORM 中的 N+1 问题》、优化掉多余的数据库访问(需要记住,每一次数据库访问,其实都是一次远程访问)。
  4. 另外,Web 页面的前端优化,还可以参考《 YAHOO Web 优化的 14 条法则》。

 

常见问题二:单条 SQL 语句执行较慢


在数据量较大的情况下,一些 SQL 语句执行得非常慢。

优化步骤:

  1. 是否 SQL 本身有性能问题?
  2. 是否建立了表分区?
    http://www.cnblogs.com/leiOOlei/archive/2012/06/08/2541306.html
    http://blog.csdn.net/hijiankang/article/details/9173877
  3. 是否对主要查询的字段建立了索引?
  4. 测试数据是否有效?(尽量按照真实场景来准备测试数据)
  5. 是否需要限制用户的数据查询范围?
  6. 是否需要优化业务结构?
    是否真的需要为用户提供一个查看几十万页的数据的页面?这样的数据对于用户来说,往往是没用的。我们应该在功能模块方面重新设计?
  7. 不要使用 JOIN,而是使用 IN 语句。
  8. 不要查询全字段,而是只查询 ID。

 

例如,下面这个 SQL,在压力测试 1000 万行数据时,已经需要 8 秒左右:

SELECT * FROM
(
SELECT T.*, ROWNUM RN
FROM
(
SELECT *
FROM "T_PRIMITIVEDETAIL" "T0"
WHERE "T0"."ORDERGOODSDATE" >= :p0 AND "T0"."ORDERGOODSDATE" <= :p1 AND "T0"."CORPORATION" = :p2 AND "T0"."DBI_ISPHANTOM" = :p3
ORDER BY "T0"."ID" ASC
) T
WHERE ROWNUM <= 5000010
)
WHERE RN >= 5000000
--Parameters:2016/5/1 0:00:00,2016/5/31 23:59:59,"惠州酷友网络科技有限公司","0"

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

ID 列和 ORDERGOODSDATE 列都是建立了索引的,同时也为 ORDERGOODSDATE 列建立了表分区。经过几次测试,发现通过索引列排序进行查询速度还是较慢(索引 Id 列:首次5秒,后面都是2.3秒;有索引的时间列:6秒;不排序:2秒)。

同时,我们还对分页 SQL 进行的测试。目前有三种较为通用的分页格式:

1.根据ROWID来分

select * from t_xiaoxi where rowid in(

  select rid from (

    select rownum rn,rid from(

     select rowid rid,cid from

     t_xiaoxi  order by cid desc

    ) where rownum<10000

  ) where rn>9980

)

order by cid desc;

2.按分析函数来分

select * from (

  select t.*,row_number() over(order by cid desc) rk from t_xiaoxi t

) where rk<10000 and rk>9980;

3.按ROWNUM来分

select * from(

  select t.*,rownum rn from(

    select * from t_xiaoxi order by cid desc

  ) t where rownum<10000

) where rn>9980;

结果发现,原来的分页格式,效率是最高的。下面的 SQL 查询需要 4 秒:

select * from (

  select t.*,row_number() over(order by id ASC) rk from T_ENTERPRISETRANSACTION t

) where rk <= 5000010 and rk >= 5000000

由于我们的分页 SQL 是自动生成的,所以格式方面我们要保留一定的通用性,同时性能不能太差。所以还是决定继续保留原有的格式。

前面几个优化方案没有成功。我们就看了一下测试人员插入的一千条数据。原来这些数据的时间都是同一天的!!!造成了分区和索引失效。将数据按照真实场景录入后,不到 1s 就查询出来了。

另外,第 6 条:有 50 万页数据的页面,不应该设计给客户看到。所以我让项目组的同这考虑是否需要删除这个页面,换一种实现方案。

第8条,不查全字段,只查 ID:测试后,也有了比较明显的效果。

SELECT ID FROM
(
SELECT T.*, ROWNUM RN
FROM
(
SELECT ID
FROM "T_ENTERPRISETRANSACTION" "T0"
--order by T0.Id desc
--order by T0.DBI_CreatedTime
--order by T0.tradeDate
) T
WHERE ROWNUM <= 5000010
)
WHERE RN >= 5000000
--0.6秒
SELECT * FROM "T_ENTERPRISETRANSACTION" "T0" WHERE ID IN (7853679,7853680,7853681,7853682,7853683,7853684,7853685,7853686,7853687,7853688,7853689)
--0.1秒

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

一共只需要 0.7 秒。

 

常见问题三:大数据导入性能优化


公司产品的一个重要模块是一个数据导入引擎。基于 WF4 引擎,配合一定的活动,来实现从文件到数据库的导入。即:读取文件 –> 大量数据格式转换逻辑 & 大量业务逻辑 –> 导入数据库。

由于逻辑非常复杂,所以我们并没有把这些逻辑放到数据库中去编写存储过程,而是基于内存中的领域实体来执行业务逻辑。

对于此程序的优化步骤:

  1. 通过性能监控工具,找到性能损耗的核心位置,再针对该位置出方案进行优化。

    这一步应该作为第一个步骤。开发者在对性能进行优化时,往往出现“想当然”地去分析、优化的行为,最终是花费了时间也没有优化到点上!所以这里首重提出这一步骤。先让工具去帮我们找到这些核心位置!
  2. 降低数据库访问次数。(此项检查是所有数据库访问程序的首要优化方案,也是最容易出现问题的地方)。

    1.1 解决 ORM 中的 N+1 问题。

    1.2 在内存中一次性准备好数据后,再插入到数据库中。

    1.3 对于导入大数据量到数据库中,采用批量导入方案,而非逐条导入方案。

  3. 多线程技术。

    由于数据导入程序是 IO 密集型 + CPU 密集型操作,但是二者的运行阶段不同。所以合理地采用多线程,可以大大提升执行效率。

    使用多线程时,要注意线程安全的问题:尽量不要有太多的共享资源(文件、数据库中的行);共享资源要加锁(文件加锁、内存加锁、数据库事务(事务的级别))。

    另外,提前为各个线程准备好一些共用的数据,也可以优化一些不必要的 IO。

  4. 优化核心大数据的循环,以及嵌套循环的核心循环中的代码即可。这些位置的代码,需要处处小心,优化到极致。

    核心循环中,不要用 LINQ To Object:一个 Linq To Object 操作,至少生成了三个轻量级对象:一个委托、一个实现 IEnumerable 接口的对象,以及遍历集合时,生成的一个 Enumerator。

    核心循环中,要尽量减少循环的次数。例如:1000万数据和100万数据做循环匹配,不优化的循环就需要执行 1000万*100万次。所以我们需要引入一些算法来优化不必要的循环次数。

    只需要优化核心循环,不需要优化所有的代码。LINQ To Object 该用的时候,还要用。 

 

小结


本文对公司几个项目遇到的共性问题进行了总结。

希望能对其它的项目组有所帮助。也希望能收集到更多的优化建议。

MIS性能优化常见问题与方案(辅助项目组性能优化的总结贴)的更多相关文章

  1. 数据库SQL优化大总结之 百万级数据库优化方案(转载)

    网上关于SQL优化的教程很多,但是比较杂乱.近日有空整理了一下,写出来跟大家分享一下,其中有错误和不足的地方,还请大家纠正补充. 这篇文章我花费了大量的时间查找资料.修改.排版,希望大家阅读之后,感觉 ...

  2. SystemML大规模机器学习,优化算子融合方案的研究

    SystemML大规模机器学习,优化算子融合方案的研究 摘要 许多大规模机器学习(ML)系统允许通过线性代数程序指定定制的ML算法,然后自动生成有效的执行计划.在这种情况下,优化的机会融合基本算子的熔 ...

  3. 转--优化临时表使用,SQL语句性能提升100倍

    转自:http://www.51testing.com/html/01/n-867201-2.html [问题现象] 线上mysql数据库爆出一个慢查询,DBA观察发现,查询时服务器IO飙升,IO占用 ...

  4. 性能调优之访问日志IO性能优化

    性能调优之访问日志IO性能优化   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821 ...

  5. .NET-记一次架构优化实战与方案-底层服务优化

    目录 .NET-记一次架构优化实战与方案-梳理篇 .NET-记一次架构优化实战与方案-前端优化 .NET-记一次架构优化实战与方案-底层服务优化 前言 经过上一篇<.NET-记一次架构优化实战与 ...

  6. .NET-记一次架构优化实战与方案-前端优化

    目录 .NET-记一次架构优化实战与方案-梳理篇 .NET-记一次架构优化实战与方案-前端优化 .NET-记一次架构优化实战与方案-底层服务优化 前言 上一篇<.NET-记一次架构优化实战与方案 ...

  7. DeepMind提出新型超参数最优化方法:性能超越手动调参和贝叶斯优化

    DeepMind提出新型超参数最优化方法:性能超越手动调参和贝叶斯优化 2017年11月29日 06:40:37 机器之心V 阅读数 2183   版权声明:本文为博主原创文章,遵循CC 4.0 BY ...

  8. 【前端性能】高性能滚动 scroll 及页面渲染优化

    最近在研究页面渲染及web动画的性能问题,以及拜读<CSS SECRET>(CSS揭秘)这本大作. 本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的 ...

  9. 【前端性能】高性能滚动 scroll 及页面渲染优化--转发

    本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的关系,节流与防抖,pointer-events:none 优化滚动.因为本文涉及了很多很多基础,可以对照上面的知 ...

随机推荐

  1. 深入理解BFC

    定义 在解释BFC之前,先说一下文档流.我们常说的文档流其实分为定位流.浮动流和普通流三种.而普通流其实就是指BFC中的FC.FC是formatting context的首字母缩写,直译过来是格式化上 ...

  2. c#语言规范

    0x00 分类 C#语言规范主要有两个来源,即我们熟知的ECMA规范和微软的规范.尽管C#的ECMA规范已经前后修订4次,但其内容仅仅到C# 2.0为止.所以慕容为了方便自己和各位方便查询,在此将常见 ...

  3. Unable to create the selected property page. An error occurred while automatically activating bundle net.sourceforge.pmd

    解决方案: 在命令行到eclipse目录下使用 eclipse.exe -clean

  4. 【原】无脑操作:express + MySQL 实现CRUD

    基于node.js的web开发框架express简单方便,很多项目中都在使用.这里结合MySQL数据库,实现最简单的CRUD操作. 开发环境: IDE:WebStorm DB:MySQL ------ ...

  5. xss和sql注入原理学习

    8.4 Web跨站脚本攻击 8.4.1  跨站脚本攻击的原理(1) 跨站脚本在英文中称为Cross-Site Scripting,缩写为CSS.但是,由于层叠样式表 (Cascading Style ...

  6. Hadoop的安装与设置(1)

    在Ubuntu下安装与设置Hadoop的主要过程. 1. 创建Hadoop用户 创建一个用户,用户名为hadoop,在home下创建该用户的主目录,就不详细介绍了. 2. 安装Java环境 下载Lin ...

  7. 前端自学路线之js篇

    上一篇我们讲了前端切图的学习路线,不知大家有没有收获.今天来聊聊前端工程师的核心技能之——JavaScript.js这门语言看似简单,但要做到入门.熟练以至于架构的程度,还是有一段路要走的,今天就来聊 ...

  8. CSharpGL(29)初步封装Texture和Framebuffer

    +BIT祝威+悄悄在此留下版了个权的信息说: CSharpGL(29)初步封装Texture和Framebuffer +BIT祝威+悄悄在此留下版了个权的信息说: Texture和Framebuffe ...

  9. 微信小程序开发调试工具

    为了帮助开发者简单和高效地开发微信小程序,我们推出了全新的 开发者工具 ,集成了开发调试.代码编辑及程序发布等功能. 扫码登录 启动工具时,开发者需要使用已在后台绑定成功的微信号扫描二维码登录,后续所 ...

  10. Failure to find xxx in xxx was cached in the local repository, resolution will not be reattempted until the update interval of nexus has elapsed or updates are forced @ xxx

    问题: 在linux服务器上使用maven编译war时报错: 16:41:35 [FATAL] Non-resolvable parent POM for ***: Failure to find * ...