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

 

常见问题一:打开页面非常慢,有的项目打开一个页面竟然要 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. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  2. 两个 viewports 的故事-第二部分

    原文链接:A tale of two viewports — part two 译者:nzbin 在这个迷你系列中,我将解释 viewports 和各种重要元素的宽度是如何工作的,比如说 <ht ...

  3. vue双向数据绑定原理探究(附demo)

    昨天被导师叫去研究了一下vue的双向数据绑定原理...本来以为原理的东西都非常高深,没想到vue的双向绑定真的很好理解啊...自己动手写了一个. 传送门 双向绑定的思想 双向数据绑定的思想就是数据层与 ...

  4. 你真的会玩SQL吗?之逻辑查询处理阶段

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  5. 自己写的数据交换工具——从Oracle到Elasticsearch

    先说说需求的背景,由于业务数据都在Oracle数据库中,想要对它进行数据的分析会非常非常慢,用传统的数据仓库-->数据集市这种方式,集市层表会非常大,查询的时候如果再做一些group的操作,一个 ...

  6. animate.css(第三方动画使用方法)

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 17.0px Monaco; color: #a5b2b9 } animation 语法: animatio ...

  7. JAVA的内存模型(变量的同步)

    一个线程中变量的修改可能不会立即对其他线程可见,事实上也许永远不可见. 在代码一中,如果一个线程调用了MyClass.loop(),将来的某个时间点,另一个线程调用了MyClass.setValue( ...

  8. iOS网络4——Reachability检测网络状态

    一.整体介绍 前面已经介绍了网络访问的NSURLSession.NSURLConnection,还有网页加载有关的webview,基本满足通常的网络相关的开发. 其实在网络开发中还有比较常用的就是网络 ...

  9. 转:ORA-15186: ASMLIB error function = [asm_open], error = [1], 2009-05-24 13:57:38

    转:ORA-15186: ASMLIB error function = [asm_open], error = [1], 2009-05-24 13:57:38http://space.itpub. ...

  10. 【repost】JS错误类型的学习

    SyntaxError是解析代码时发生的语法错误 // 变量名错误  var 1a;  // 缺少括号  console.log 'hello'); (2)ReferenceError Referen ...