MySQL中Update的执行效率测试及验证

[size=x-large][b]1、引言[/b][/size]
某日,在讨论解决生产环境的问题时,一同事问说增加条件的Update语句效率是否更高?虽然我当时就有了自己的判断,但本着严谨的态度,我还是编写了测试代码,对MySQL中Update的执行效率进行测试及验证。

[size=x-large][b]2、解决思路[/b][/size]
1、根据生产环境的情况,模拟不同数据量的测试数据,分别模拟以下数据量的数据进行比较
[table]
|1000|2000|5000|
|10000|20000|50000|
|100000|200000|500000|
|1000000|2000000|5000000|
[/table]
2、测试对比增加条件和不加条件两种的Update语句的执行时间

[size=x-large][b]3、解决过程[/b][/size]
[size=large][b]3.1 数据表名[/b][/size]
不同数据量存放在不同的数据表中,表名规则体现数据量,代码如下

// 根据数据量生成表名
private String getTableName(int count) {
return "call_charge_" + count;
}


[size=large][b]3.2 删除数据表[/b][/size]

// 删除数据表
private void dropTable(String tableName) {
String dropTableSql = "DROP TABLE IF EXISTS `" + tableName + "` ";
jdbcTemplate.execute(dropTableSql);
}


[size=large][b]3.3 创建数据表[/b][/size]

// 创建数据表
private void createTable(String tableName) {
String createTableSql = "CREATE TABLE `" + tableName + "` (";
createTableSql += "`caller_flag` int(11) NOT NULL,";
createTableSql += "`call_type` int(11) NOT NULL,";
createTableSql += "`e164no` char(64) NOT NULL,";
createTableSql += "`conf_begin_time` int(11) NOT NULL,";
createTableSql += "`begin_time` int(11) NOT NULL,";
createTableSql += "`end_time` int(11) NOT NULL,";
createTableSql += "`correct_begin_time` int(11) NOT NULL,";
createTableSql += "`correct_end_time` int(11) NOT NULL,";
createTableSql += "`correct_begin_time_string` varchar(32) NOT NULL,";
createTableSql += "`correct_end_time_string` varchar(32) NOT NULL,";
createTableSql += "`opposite_call_type` int(11) NOT NULL,";
createTableSql += "`opposite_e164no` char(64) NOT NULL,";
createTableSql += "`opposite_conf_begin_time` int(11) NOT NULL,";
createTableSql += "`company_guid` varchar(32) NOT NULL,";
createTableSql += "`band_width` int(11) NOT NULL,";
createTableSql += "`roam_flag` int(11) NOT NULL,";
createTableSql += "`out_flag` int(11) NOT NULL,";
createTableSql += "`incoming_flag` int(11) NOT NULL,";
createTableSql += "`csu_guid` varchar(32) NOT NULL,";
createTableSql += "KEY `correct_begin_time` (`correct_begin_time`),";
createTableSql += "KEY `company_guid` (`company_guid`)";
createTableSql += ") ENGINE=InnoDB DEFAULT CHARSET=utf8";
jdbcTemplate.execute(createTableSql);
}


[size=large][b]3.4 初始化数据[/b][/size]

// 初始化数据
private void initData(String tableName, int count) {
String insertSql = "insert into `" + tableName + "` ";
insertSql += "(`caller_flag`, `call_type`, `e164no`, `conf_begin_time`, `begin_time`, `end_time`, ";
insertSql += "`correct_begin_time`, `correct_end_time`, `correct_begin_time_string`, `correct_end_time_string`, ";
insertSql += "`opposite_call_type`, `opposite_e164no`, `opposite_conf_begin_time`, `company_guid`, ";
insertSql += "`band_width`, `roam_flag`, `out_flag`, `incoming_flag`, `csu_guid`) ";
insertSql += "values('1','2','051211#999548','1420075106','1420075107','1420075188','1420066067','1420066148',";
insertSql += "'2015-01-01 06:47:47','2015-01-01 06:49:08','1','0512114880046','2147483647','','960','0',";
insertSql += "'0','0','%s')";

for (int i = 0; i < count; i++) {
if (i % 3 == 0) {
jdbcTemplate.execute(String.format(insertSql, CSU_GUID1));
} else {
jdbcTemplate.execute(String.format(insertSql, CSU_GUID2));
}
}
}


[size=large][b]3.5 复制数据[/b][/size]

// 复制数据
private void copyData(String templateTableName, int count, int step) {
String createSql = "CREATE TABLE `" + getTableName(count) + "` SELECT * FROM " + templateTableName;
jdbcTemplate.execute(createSql);

String copySql = "INSERT INTO `" + getTableName(count) + "` SELECT * FROM " + templateTableName;
for (int i = step; i < count; i += step) {
jdbcTemplate.update(copySql);
}
}


[size=large][b]3.6 公用测试代码[/b][/size]

private String CSU_GUID1 = "10103000000006000000000000000001";
private String CSU_GUID2 = "10103000000006000000000000000002";
private String CSU_GUID3 = "10103000000006000000000000000003";

// 公用单元测试方法
private void doTest(String templateTableName, int count, int step) {
dropTable(getTableName(count));
copyData(templateTableName, count, step);
doTest(count);
}

// 测试加条件和不加条件的update
private void doTest(int count) {
long startTime = System.currentTimeMillis();
String updateSql = "update " + getTableName(count) + " set csu_guid = '" + CSU_GUID3 + "' where csu_guid != '"
+ CSU_GUID1 + "'";
jdbcTemplate.update(updateSql);
long endTime = System.currentTimeMillis();
System.out.println(String.format("测试数据[%d]过滤Update=%d", count, endTime - startTime));

startTime = System.currentTimeMillis();
updateSql = "update " + getTableName(count) + " set csu_guid = '" + CSU_GUID2 + "'";
jdbcTemplate.update(updateSql);
endTime = System.currentTimeMillis();
System.out.println(String.format("测试数据[%d]直接Update=%d", count, endTime - startTime));
}


[size=large][b]3.7 Junit测试[/b][/size]

@Test
public void prepareData() {
dropTable("call_charge_data");
createTable("call_charge_data");
initData("call_charge_data", 100);
}

@Test
public void create1000() {
doTest("call_charge_data", 1000, 100);
}

@Test
public void create2000() {
doTest(getTableName(1000), 2000, 1000);
}

@Test
public void create5000() {
doTest(getTableName(1000), 5000, 1000);
}

@Test
public void create10000() {
doTest(getTableName(1000), 10000, 1000);
}

@Test
public void create20000() {
doTest(getTableName(10000), 20000, 10000);
}

@Test
public void create50000() {
doTest(getTableName(10000), 50000, 10000);
}

@Test
public void create100000() {
doTest(getTableName(10000), 100000, 10000);
}

@Test
public void create200000() {
doTest(getTableName(100000), 200000, 100000);
}

@Test
public void create500000() {
doTest(getTableName(100000), 500000, 100000);
}

@Test
public void create1000000() {
doTest(getTableName(100000), 1000000, 100000);
}

@Test
public void create2000000() {
doTest(getTableName(1000000), 2000000, 1000000);
}

@Test
public void create5000000() {
doTest(getTableName(1000000), 5000000, 1000000);
}


[size=large][b]3.8 测试结果[/b][/size]

--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create1000] start...
测试数据[1000]过滤Update=30
测试数据[1000]直接Update=135
Test[com.hero.test.update.TestMysqlUpdate.create1000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create10000] start...
测试数据[10000]过滤Update=225
测试数据[10000]直接Update=852
Test[com.hero.test.update.TestMysqlUpdate.create10000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create100000] start...
测试数据[100000]过滤Update=7883
测试数据[100000]直接Update=43920
Test[com.hero.test.update.TestMysqlUpdate.create100000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create1000000] start...
测试数据[1000000]过滤Update=26170
测试数据[1000000]直接Update=460927
Test[com.hero.test.update.TestMysqlUpdate.create1000000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create2000] start...
测试数据[2000]过滤Update=53
测试数据[2000]直接Update=657
Test[com.hero.test.update.TestMysqlUpdate.create2000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create20000] start...
测试数据[20000]过滤Update=329
测试数据[20000]直接Update=2025
Test[com.hero.test.update.TestMysqlUpdate.create20000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create200000] start...
测试数据[200000]过滤Update=10867
测试数据[200000]直接Update=95978
Test[com.hero.test.update.TestMysqlUpdate.create200000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create2000000] start...
测试数据[2000000]过滤Update=42915
测试数据[2000000]直接Update=944865
Test[com.hero.test.update.TestMysqlUpdate.create2000000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create5000] start...
测试数据[5000]过滤Update=122
测试数据[5000]直接Update=1449
Test[com.hero.test.update.TestMysqlUpdate.create5000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create50000] start...
测试数据[50000]过滤Update=11848
测试数据[50000]直接Update=14608
Test[com.hero.test.update.TestMysqlUpdate.create50000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create500000] start...
测试数据[500000]过滤Update=14463
测试数据[500000]直接Update=222890
Test[com.hero.test.update.TestMysqlUpdate.create500000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.create5000000] start...
测试数据[5000000]过滤Update=90726
测试数据[5000000]直接Update=2322410
Test[com.hero.test.update.TestMysqlUpdate.create5000000] end...
--------------------------
Test[com.hero.test.update.TestMysqlUpdate.prepareData] start...
Test[com.hero.test.update.TestMysqlUpdate.prepareData] end...

整理后的测试结果如下所示
[table]
|数据量|加条件的执行时间(ms)|不加条件的执行时间(ms)|单元测试执行时间(s)|
|1000|30|135|5.103|
|2000|53|657|7.096|
|5000|122|1449|13.244|
|10000|225|852|9.859|
|20000|329|2025|26.353|
|50000|11848|14608|68.743|
|100000|7883|43920|102.544|
|200000|10867|95978|232.576|
|500000|14463|222890|560.074|
|1000000|26170|460927|1018.023|
|2000000|42915|944865|2052.403|
|5000000|90726|2322410|5145.207|
[/table]
[color=red][b]特别说明:[/b][/color]
测试结果,因机器及机器的工作状态而不同

[size=x-large][b]4、总结[/b][/size]
从测试结果的对比来看,增加条件的Update的执行效率明显比不加条件的Update的执行更短,效率也就更好

[size=x-large][b]5、附录[/b][/size]
1、测试基类BaseTest

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
* Junit测试基类
* @author chengesheng@gmail.com
* @date 2014-7-28 下午5:27:34
* @version 1.0.0
*/
// 使用@RunWith(SpringJUnit4ClassRunner.class),才能使测试运行于Spring测试环境
@RunWith(SpringJUnit4ClassRunner.class)
// @ContextConfiguration 注解有以下两个常用的属性:
// locations:可以通过该属性手工指定 Spring 配置文件所在的位置,可以指定一个或多个 Spring 配置文件
// inheritLocations:是否要继承父测试类的 Spring 配置文件,默认为 true
// 如果只有一个配置文件就直接写locations=“配置文件路径+名”
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class BaseTest {

@Rule
public TestName name = new TestName();

@Before
public void before() {
System.out.println("--------------------------");
System.out.println("Test[" + getClassName() + "." + getMethodName() + "] start...");
}

@After
public void after() {
System.out.println("Test[" + getClassName() + "." + getMethodName() + "] end...");
}

private String getClassName() {
return getClass().getName();
}

private String getMethodName() {
return name.getMethodName();
}
}


2、Spring配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>

<!-- 配置Spring JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
</beans>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值