sql 性能测试

       策略模式的定义
        策略模式是应用最普遍的设计模式之一。Gof 把策略模式归类到对象行为型模式,《 设计模式:可复用面向对象软件的基础 》对策略模式做出了明确的定义:“ Define a family of algorithms, encapsulate each one, and make theminterchangeable.Strategy lets the algorithm vary independently fromclients that use it. ”,翻译过来就是:“ 定义了一族算法,将每个算法分别封装起来,并且互相之间可以替换。策略模式可以使算法的变化独立于使用算法的客户 ”。
         why 策略模式?
  • 客户端程序直接包含业务算法代码的话会变的复杂,这样会使客户程序庞大且难以维护,尤其是需要支持多种业务算法时。
  • 不同的时候需要不同的算法,我们不想支持我们并不使用的业务算法。
  • 当业务功能是客户程序的一个难以分割的成分时,增加新的业务算法或改变现有算法将十分困难。
        策略模式定义一些类来封装不同的业务算法,从而避免上述问题。
         策略模式的使用场合
  • 许多相关类仅仅是行为不同。
  • 需要使用一个算法的不同实现。
  • 算法使用了客户不应该知道的数据。策略模式可以避免暴露复杂的、与算法相关的数据结构。
  • 一个类定义了很多行为,而且这些行为在这个类里的操作以多个条件语句的形式出现。策略模式将相关的条件分支移入它们各自的 Strategy 类中以代替这些条件语句。
         sql 性能测试需求
        在一个 jee 项目中,有一张表,单表千万数据,有五条 sql 语句可能需要优化,现在处于上线前紧张的 coding 阶段,为了避免产品上线后因数据量暴涨而造成 sql 性能下降,现在需要一个程序来模拟真实场景下的 jee 数据库操作,通过这些操作用时分析 sql 性能和潜在问题,进而优化。
         sql 性能测试分析
        为了模拟真实场景,数据库、框架产品项目保持一致自不必说。数据库单表也需要制造模拟数据到上千万条,记录之间尽量遵循真实场景。
        数据制造好以后,需要模拟不同用户进行操作。比如有用户模拟插入操作,有用户模拟查询操作。模拟操作的数量、执行频率最好也根据真实场景得出。
         sql 性能测试类设计
        jee 用了 spring mvc + spring IOC + iBatis 框架,为了便于理解我们模拟程序也分出 dao、service。为了不和 service 产生混淆,我们具体的“策略”算法封装在了 user 类里头(user 相当于 Gof《设计模式:可复用面向对象软件的基础》中的 Strategy 接口),runner 作为使用算法的客户(即 Gof《设计模式:可复用面向对象软件的基础》中的 Context 对象)。具体类图如下:

         sql 性能测试时序图
时序图
         sql 性能测试源码实现

        Strategy 角色 User 源代码:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.defonds.mysql.user;  
  2.   
  3. public interface User {  
  4.     // 策略模式的应用:把具体做法让每个 User 分别封装起来,做法独立于调用 User 的 thread  
  5.     public void doMyThing();  
  6. }  

        ConcreteStrategy 角色之一 RawAddUser 源代码:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.defonds.mysql.user.raw;  
  2.   
  3. import com.defonds.mysql.raw.service.RawService;  
  4. import com.defonds.mysql.user.User;  
  5.   
  6. public class RawAddUser implements User {  
  7.     private RawService rawService;  
  8.     private int numCountor = 1// 记录次数  
  9.     public void setRawService(RawService rawService) {  
  10.         this.rawService = rawService;  
  11.     }  
  12.   
  13.     @Override  
  14.     public void doMyThing() {  
  15.         long uid = 111;  
  16.         long did = 1111;  
  17.         long fileId = 11111;  
  18.         long sectionId = 111111;  
  19.         long startTime = System.currentTimeMillis();  
  20.         String s3RawHeaderPath = "/usr/home/df/wefd.txt" + numCountor;  
  21.         String channelId = "1";  
  22.         if (numCountor >= 20) {  
  23.             numCountor = 1;  
  24.         }  
  25.         uid += numCountor;  
  26.         did += numCountor;  
  27.         fileId += numCountor;  
  28.         sectionId += numCountor;  
  29.         rawService.addTimeLineRaw(uid, did, fileId, sectionId, startTime, startTime + 15000, s3RawHeaderPath, channelId);  
  30.         numCountor ++;  
  31.     }  
  32.   
  33. }  

        Context 角色 Runner 源代码:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.defonds.mysql.runner;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import com.defonds.mysql.user.User;  
  6. import com.defonds.mysql.util.dao.RecordDao;  
  7.   
  8. public abstract class Runner implements Runnable {  
  9.     protected RecordDao recordDao;  
  10.     protected User user;  
  11.     protected String sceneDesc;  
  12.     protected String type;  
  13.     protected String requestDesc;  
  14.     protected long interval;  
  15.     public void setRecordDao(RecordDao recordDao) {  
  16.         this.recordDao = recordDao;  
  17.     }  
  18.     public void setUser(User user) {  
  19.         this.user = user;  
  20.     }  
  21.       
  22.     /** 
  23.      *  
  24.      * @param sceneDesc // 场景名 
  25.      * @param type // 操作类型 [insert、delete、update、select] 
  26.      * @param requestDesc // 对应  timeline.xml 文件中的语句 id 
  27.      * @param interval // 两次执行之间的时间间隔 
  28.      */  
  29.     public Runner(String sceneDesc, String type, String requestDesc, long interval) {  
  30.         this.sceneDesc = sceneDesc;  
  31.         this.type = type;  
  32.         this.requestDesc = requestDesc;  
  33.         this.interval = interval;  
  34.     }  
  35.   
  36.     @Override  
  37.     public void run() {  
  38.         while (true) {  
  39.             try {  
  40.                 Thread.sleep(this.interval);  
  41.             } catch (InterruptedException e) {  
  42.                 // TODO Auto-generated catch block  
  43.                 e.printStackTrace();  
  44.             }  
  45.             Date startTime = new Date();  
  46.             long startTimeL = System.currentTimeMillis();  
  47.             this.user.doMyThing();  
  48.             Date endTime = new Date();  
  49.             long endTimeL = System.currentTimeMillis();  
  50.             this.record(this.sceneDesc, this.type, startTime, endTime, endTimeL - startTimeL, this.requestDesc, null);  
  51.         }  
  52.     }  
  53.       
  54.     protected void record(String sceneDesc, String type, Date startTime, Date endTime, long extendTime, String requestDesc, String requestDetail) {  
  55.         this.recordDao.addRecord(sceneDesc, type, startTime, endTime, extendTime, requestDesc, requestDetail);  
  56.     }  
  57.   
  58. }  

         sql 性能测试结果分析
        使用压力程序将 DB Server 负载到真实上线后的比例。然后模拟程序 19 * 5 个用户并发,TestMysql 跑起来,E7500 CPU 负载到 0.2%,4 G 内存负载 0%。可以参考《 关于一个具有配置文件的 Java Project 项目(非 web 项目)在服务器上的一个便捷部署 》的做法将本模拟程序部署在测试服务器。根据本模拟程序运行两天,五个 sql 性能走势如下图:
TestMysql运行效果图
         本文示例程序《sql 性能测试》源码下载
        已将本文用到的项目相关源代码上传至 CSDN 资源,有兴趣的朋友可以去看一下: sql 性能测试源代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值