性能优化(基础流程)

   先说一下背景故事,最近经过几个迭代,新产品基础MVP版功能大体做完了。但是呢,由于都是测试数据,所以数据量不大,但是产品发布到用户环境,可能数据量呈几何增长,可能会导致系统性能出现各种各样的问题。于是这个迭代就做了各浏览器兼容问题,单用户点击性能问题,并发性能问题的测试优化。之前虽然做过一点点性能调优的东西,但是很不系统,而且遇到了也只是调调sql语句,看见死锁了直接KILL,于是呢,去年去面试时,被人血虐。所以最近刚好涉及到了这些知识点,而且天气又热,,没法去浪,就写一点东西。

      首先做性能优化,得数据量级起来,于是同事做了个数据翻倍工具(没有工具,可手动写sql插入,后续这个工具我去研究下,估计会放到git上)。我们是根据业务的高频性来进行翻倍的,也就是说高频业务数据量较大,但是整体平均下来,大概就是单表几百万。不算很多。 

 

 

 

 

 

          数据翻倍完成后,开始单用户点击测试。所谓单用户点击测试,就是用户根据公司所出具的性能测试的要求,进行单用户单次点击,查看各功能点的性能情况。那么例如公司要求的性能是1s,我们如何测算这个功能是否超过标准要求了,存在性能问题呢?

      这个时候打开fiddle抓包工具,查看每个请求的响应时间 。比如我一个保存操作,可能发了几个请求,那我就把这几个请求总时间加起来,看有没有超过预期的时间,超过了就需要优化。怎么优化呢?我们开发了一个fiddle插件,每个请求可以直接在fiddle上看到数据库的SQL语句,以及执行时间。那如果没有这个插件怎么办呢?打开本机的cmd命令或者powershells输入hostname得到自己的主机名,然后去profiler中根据主机名过滤跟踪出来的sql。查看sql的IO和执行时间。

       

  

   我们可以看到这个查询耗时并不是很高,但是这么一个简单的查询仍然耗时花了00.00.00.02的时间,可能是存在问题的,所以我把这个语句粘贴出来,放入执行查询器中,开启执行计划, 于是sqlserver自动提示我增加索引,我们用然后去profiler中看看这个sql的执行情况。

  

我们可以看到这么简单的一句SQL,IO竟然达到了11W,很明显不合理,于是我们找到上图中的执行计划,右键缺少索引的详细信息,这样我们就可以看到sqlserver推荐的要创建的索引了,这个推荐索引不一定完全正确,但是了解一些基本的索引知识。照着改,是没啥问题的。这里索引的话,一般单表我们不会超过4个,多了影响更新。另外我们用的比较多的是非聚集索引。其中应该基本建的都是INCLUDE索引。
      INCLUDE索引可以百度自己看一下,我只说一下执行计划的键查找,索引本质和数据是差不多的,也是会生成一个索引页,这个索引页,你可以把它当作数据表一样,他有一个键和一个指向数据的指针。索引页的每条数据呢,就放在B+树的叶子节点上,当你查数据时,数据库就先根据键找到叶子节点,再根据叶子结点里的指针找到数据,再把数据返回给用户。这个过程大概是键查找。说了键查找,那就说一下索引查找,还是用户查数据,根据键找到叶子节点,叶子节点上包含了你需要的数据直接返回了数据给用户。哪个效率高,是不是显而易见,现在大家应该能猜到include索引的意义了吧。

   可以理解为原本索引这个数据表中只有键 和指向数据的指针这两列数据,现在include了,把你所有的需要的数据加入到了这个表中,数据查询时,我不用去找真正的数据表,直接找这个索引数据表就好了,这样就很快。在大部分场景,加了索引,如果代码不是写的很烂,或者视图啥的不是写的很臭,基本单用户性能都是没问题的。如果有问题,建议重构代码或者视图,sql尽量遵循SARG。这样扫一轮后,基本的单用户性能就差不多了。(也可能我学的比较浅)。根据提示的信息,创建索引。然后我们再看看执行情况。IO 降到了16,搞定。

   单用户性能做完了就是高并发场景性能测试。我们会把整体代码打包给自动化测试的,让跑一遍并发测试,对于并发有性能问题的地方,会给我们出一个测试结果表,并标注出问题(超时,死锁)等等。那么出现了并发问题,我们怎么解决呢?而且怎么验证自己是否解决了这个并发问题呢?难道每个开发装一个loadrunner或者其他的测试软件?

 

我感觉自己装一个测试软件,不太可取,这样太重了。于是用了一个办法,打开fiddle找到请求,右键找到replay,然后可以设置并发请求。我是多并发20个时,出现了死锁,所以我在fiddle上设置并发数20。然后根据死锁语句去数据库查,结果发现这条语句执行时间,不超过10毫秒,IO只有37,很明显是正常的,看了执行计划,存在键查找,于是把全表字段加到了include索引,执行计划就只有索引查找,但是依旧死锁。

 

   原以为是大佬写的一个很复杂的计算引擎代码造成的原因,但是把这部分代码屏蔽掉依旧死锁。怎么办呢?这个时候,打开sqlprofiler,打开跟踪,选中跟踪事件LOCK GRAPH,这样死锁的时候我们就可以看见锁图,。

我们从网上随便找了一段,造成死锁的情况,针对这段sql我们跟踪一下,查看一下他的锁图

CREATE TABLE Lock1(C1 int default(0));
CREATE TABLE Lock2(C1 int default(0));
INSERT INTO Lock1 VALUES(1);
INSERT INTO Lock2 VALUES(1);

--Query 1
Begin Tran
  Update Lock1 Set C1=C1+1;
  WaitFor Delay '00:01:00';
  SELECT * FROM Lock2
Rollback Tran;

--Query 2
Begin Tran
  Update Lock2 Set C1=C1+1;
  WaitFor Delay '00:01:00';
  SELECT * FROM Lock1
Rollback Tran;

 

这样我们就可以根据锁图里的内容进行详细的分析,造成死锁的原因了。由于各个死锁造成的原因不同,需要具体情况具体分析。楼主死锁原因是我启用事务本来加了锁,但是呢,我们有个其他的位置又对相同数据进行了修改,造成了锁表,而且锁表原因,跟那个提示出来的死锁语句没有关系。于是在程序执行上加了资源锁,就解决了这个并发性能的问题。至于具体有哪些种类的死锁,后续再写。楼主也是学习阶段,欢迎拍砖指正!

 

posted on 2019-07-28 18:11  码农666  阅读(571)  评论(0)    收藏  举报

导航