• 性能测试新手误区(二):为什么我模拟的百万测试数据是无效的


      系列原创:性能测试新手误区

      测试环境的重要性无需多说,大家都知道测试环境要尽量的模拟生产环境,当然也包括数据。这样测试的结果才会更加准确的反应真实的性能。就连开发过程,都已经开始在大数据量下加压开发了。那么,关于测试数据,你了解多少呢?

      通常说的测试数据可以分为两类:

      一是为了测试性能而准备的数据,这是用来模拟“压力”的数据。也就是常说的数据量、历史数据等。一般都会根据需求或者经验很容易估算出来,比如案件年增长量为5%,去年数据量为100W,测试需要保证3年后系统仍可正常运行,那么就需要计算并模拟出3年后的总数据量,在这个基础上进行测试。

      二是用来辅助测试使用的数据。比如有一个对案件进行打分的功能,只有符合一定条件的案件才会出现在打分列表中。那么我们要测这个打分的操作,首先就要保证有可用的案件,这就需要去生成测试数据,该数据可能一经使用就失效了(已经打过分就不能再打了)。这样,每次测试这个功能,就需要准备这样一批数据。这里的测试数据,更多的是和测试流程有关,是为了能够正常的进行测试,而不是涉及到性能的。

      我们这里要说的是第一类,对性能测试结果产生直接影响的数据。

      先看两个小案例,涉及到了案件表(T_AJ)和法院编号列(N_FY)、立案日期列(D_LARQ)。案件表中模拟了一百万测试数据,测试简单的查询操作,根据经验,预期响应时间在2秒之内。

      案例1. 查询本院案件列表,相应的SQL如下:

    select * from T_AJ
    where N_FY=10
    order by D_LARQ desc
      执行这个操作耗时近10s,显然达不到正常预期。

      经排查,生成的100W测试数据中,所有的N_FY列值都为10。这样,最明显的问题就是,查询的结果集数量完全偏离了正常范围。如果实际有100家法院,正常分布下,每家法院只有1W的案件,但测试数据的FY只有一个值,通过这个查询,查出了原来100家法院的数据。无论是在数据库处理中(如本例的排序),还是在程序的处理中(如展现或者是对数据做进一步处理),两者的性能差异都是很显著的。所以这个测试结果是无效的。

      有人说,这个例子太弱了,结果集差了100倍,性能当然不一样了。那是不是数据总量和结果集大小都一致,测试结果就是有效了呢?

      案例2. 查询本院一个月内收的案件,相应SQL如下:

    select * from T_AJ
    where N_FY=10 and D_LARQ between '20110101' and '20110201'

      这个操作,查出来的结果只有一千条数据,属于正常范围。但查询的时间还是超过5秒,依然超出了我们的预期。

      查看数据发现,N_FY=10的数据有近50万,占了总数据量的一半,D_LARQ在一月份的数据也占了差不多一半。但是同时符合两个条件的数据还是一千条左右。那么这里的问题就不在于结果集了,而是是否能利用索引进行查询,看如下两个图就能很好理解了。

      在正常数据中,每家法院的数据可能占总数据量的1%,一个月时间段内的数据可能占总数据量更少,假设是0.5%。那么这时我们通过N_FY和D_LARQ两个条件进行查询,数据库会进行估算:符合D_LARQ查询条件的数据大概有5000条,符合N_FY查询条件的数据大概有1万条,那么用D_LARQ上的索引进行查询是最快的,可以迅速的将查询范围缩小到5000条,然后在这5000条中去检查N_FY是否也符合条件。

      过程如图一所示(手绘草图^_^)。

      

    图一

      注:数据按行存储,小方块表示符合该列查询条件的数据,阴影表示符合所有查询条件,也就是最终的结果集。箭头线段表示为了完成查询,需要扫描的数据量,本图中即符合LARQ查询条件的数据。下同。

      但在本例中不正常的数据条件下,数据库会知道:符合N_FY查询条件的数据有50万条,符合D_LARQ的也有近50万条,如果使用其中一列的索引将一百万的范围缩减到50万,比从头到尾扫描整个表做的工作还要多(为什么呢?需要了解索引的结构和原理),那还是不要用索引了吧。于是数据库会依次检查每一条数据,判断N_FY和D_LARQ是否符合条件。

      如图二所示。

    图二

    注:本图中实际扫描的数据量就是整张表的数据,但结果集和图一是一样大的。

      这样,就可以知道,总数据量一样,结果集大小一样,为什么性能差了很多了。就是因为数据分布不合理,导致数据库无法正常使用索引,从而进行了全表扫描。当然,这个数据分布,我们依然可以归类到结果集中去,那就是要保证每一个查询条件“单独的结果集”都要符合真实情况,而不仅仅是整个查询最终的“总结果集”。

      看个这两个简单的小例子,我们再来总结一下关于测试数据,需要注意的内容:

    1. 最根本、也是大家都知道的就是数据量,性能测试必须保证能在预期的数据量下进行测试。在一万条记录中查询,和在一百万数据中查询,显然是大大不同的,可以把数据量看做一种“压力”,这个就不用再解释了。

      但是在比较大型的系统中,这一点可能也不是很容易做好,因为这类系统往往有着复杂的数据库,上百张的数据表。对每张表都进行数据模拟显然是不现实的,也是没有意义的,因为不是每张表都涉及到大数据量。那么如何选取不容易遗漏呢?通常通过两种方式:从设计和业务角度分析表间关系、从现有实际数据量进行分析推测。

    2. 确保结果集在正常范围内。结果集的大小直接影响后续很多工作的性能,如数据排序分组、分页、程序中的逻辑校验或者是展现。

    3. 数据分布必须合理,尽量接近真实。数据的分布,其实也就是数据的真实性,它直接决定了数据库是否使用索引、选用哪个索引,也就是常说的查询计划。不同的查询计划也就是不同的数据访问路径,性能差别可能会很大。

      这里主要涉及到的是索引的问题,需要大家对索引的原理有一定的了解,索引如何工作、数据库如何选择索引、和索引有关的一写重要概念如区分度(selectivity)等等。

    4. 最好的数据来自生产环境。这是显而易见的,使用真实的数据测出来的结果才是最准确的。但是绝大多数情况下,我们没有这样的好运,可能是客户禁止、也可能是生产环境数据量比较小。那就只好自己想办法来模拟了,需要注意的也就是上面说到的几点。这里再推荐一种方法,数据翻倍。比如已经有了真实的数据十万条,但我们需要一百万条,那就可以通过写一些SQL或者存储过程,将现有的数据不断翻倍(简单的说,复制到临时表,根据需要修改一些列,再插回到原表),这样的数据真实性还是比较高的。

      关于测试数据,我想说的就是以上几点了。另外再补充上一些相关内容,也是性能测试人员需要关注的。

    • 重点了解IO的概念,更准确的说应该是物理IO。一般来讲,数据库的瓶颈或者查询的主要耗时就是IO。所以,数据库优化的一个重要方向就是尽量减小IO。

      IO是不是只和数据量(行数)有关呢?举一个例子:

      select co1, col2, col3, col4, col5 from T_AJ 
      where condition...

      T_AJ数据量有100万,表中有近200列,此查询耗时大于10秒。而另一种实现方式,首先将col1-col5以及查询条件中的几个列的数据抽取到一张临时表(#T_AJ)中。然后,

      select co1, col2, col3, col4, col5 
      from #T_AJ where condition...

      临时表#T_AJ和原数据表有同样的数据量(行数),但是此查询却只需要1秒(暂不考虑抽取到临时表的耗时),这就是不同IO引起的差异。通常我们使用的数据库都是行式存储的,可以简单的理解为,一行数据从头读到尾,才能进入到下一行。这样,不管一行中的200列,你只读取其中的一列还是几列,其余的190多列仍然需要一定的IO。在大数据量下,这个性能差异就很明显了。所以上面的这个例子就是一种典型的优化手段,索引覆盖也是处理类似问题的典型方法,各位自行了解吧。列式存储数据库(如Sybase IQ)之所以性能这么高,也是同样的道理。

    • 尽量深入了解这些概念,如执行计划,基于开销的估算,统计信息等等。我用一句话来简单描述:数据库通过统计信息来估计查询开销,统计信息不准时,开销估计就可能不准确,从而导致选择了错误的执行计划。

    • 测试过程中数据的清理。性能测试过程中可能又会生成大量的数据,积累到一定程度又会对性能结果造成影响,所以每一轮测试时都应该清理掉之前测试过程中产生的数据,保证每次测试是在相同的条件下进行的。

    • 性能测试过程中,如果定位到了某一个查询或SQL有问题,首先要确认的是数据是否合理。通过查询计划来判断是否按预期进行了查询,如果不是,查看数据的分布是否真实。一般数据库会提供很多种手段来进行验证。

      最后,本文所写内容都是针对传统的行式存储数据库的,还请大家注意。

    作者:CaliforniaDream

    出处:http://www.cnblogs.com/twocats/

    邮件:cyj86@163.com

    如果您想进一步交流,请邮件联系我

  • 相关阅读:
    AJAX.NET应用异步注册
    [原创]ASPNET1.1分页控件源代码
    prototype.js 1.4版开发者手册
    vs.Net2003无法打开或创建Web应用程序若干解决办法.
    连连看算法
    WEB连连看
    最近公司要搞WEB在线小游戏,我却对游戏人工AI开始了性趣。。
    在vs2003的Win32项目中使用 MFC
    javascript 拼图游戏 v1.0
    IP包过滤
  • 原文地址:https://www.cnblogs.com/twocats/p/2395797.html
Copyright © 2020-2023  润新知