[MySQL] 并发更新性能测试

MySQL 版本:5.7.9
表结构:

CREATE TABLE `award` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `award` varchar(255) DEFAULT NULL,
  `count` int(11) NOT NULL COMMENT '数量',
  `created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8

一、测试代码

原理可参看:CountDownLatch 模拟高并发

package com.wlm.test.concurrent;

import java.util.concurrent.CountDownLatch;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.wlm.test.award.AwardDao;

/**
 * @author wengliemiao
 */
@Service
public class ConcurrentTest {
    @Autowired
    private AwardDao awardDao;

    /**
     * 线程数量
     */
    public static final int THREAD_NUM = 50;

    /**
     * 开始时间
     */
    private static long startTime = 0L;

    @PostConstruct
    public void init() {
        try {
            startTime = System.currentTimeMillis();
            System.out.println("CountDownLatch started at: " + startTime);

            // 初始化计数器为1
            CountDownLatch countDownLatch = new CountDownLatch(1);

            for (int i = 0; i < THREAD_NUM; i ++) {
                new Thread(new Run(countDownLatch)).start();
            }

            // 启动多个线程
            countDownLatch.countDown();

        } catch (Exception e) {
            System.out.println("Exception: " + e);
        }
    }

    /**
     * 线程类
     */
    private class Run implements Runnable {
        private CountDownLatch startLatch;

        public Run(CountDownLatch startLatch) {
            this.startLatch = startLatch;
        }

        @Override
        public void run() {
            try {
                // 线程等待
                startLatch.await();

                // 执行操作
                awardDao.update(4);

                long endTime = System.currentTimeMillis();
                System.out.println(Thread.currentThread().getName() + " ended at: " + endTime + ", cost: " + (endTime - startTime) + " ms.");
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}

二、测试结果

并发50: 约381ms
[MySQL] 并发更新性能测试_第1张图片

并发100: 约387ms
[MySQL] 并发更新性能测试_第2张图片

并发200:约445ms
[MySQL] 并发更新性能测试_第3张图片

并发500:约1173ms
[MySQL] 并发更新性能测试_第4张图片

并发1000: 约1324ms
[MySQL] 并发更新性能测试_第5张图片

注:线程并发执行的时间取决于当时执行时的系统状态。

三、总结

此处可以看出,并发对同一条数据进行update操作时,随着并发数的增高,执行时间增长。这是由于 MySQL 的 InnoDB 存储引擎对 CUD 操作默认加排他锁,因此一次只能有一条数据执行update操作。

可参看:MySQL行级锁

四、有无索引情况下并发更新性能的测试

对以下几种情况进行测试:

  • 数据量少时,并发更新同一行数据;
  • 数据量少时,并发更新不同行数据;
  • 数据量大时,并发更新同一行数据;
  • 数据量大时,并发更新不同行数据;

1、数据量少时,执行5次,并发2000更新同一行数据性能测试结果为:

执行语句:

update `award` set `count` = `count` + 1 where `award` = '4' 

数据量为:
[MySQL] 并发更新性能测试_第6张图片

有索引数据表结构为:

CREATE TABLE `award` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `award` varchar(255) DEFAULT NULL,
  `count` int(11) NOT NULL COMMENT '数量',
  `created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `Index` (`award`,`count`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
执行次数 未加索引 加索引
1 2830ms 3414ms
2 3439ms 2870ms
3 2950ms 2689ms
4 2673ms 3325ms
5 3245ms 2916ms


从以上结果可以看出,数据量少时,有无索引情况下,并发更新同一行数据的性能大致相同。

2、数据量少时,执行5次,各并发1000更新不同行数据性能测试结果为:

执行次数 未加索引 加索引
1 2884ms 3002ms
2 2988ms 3007ms
3 2827ms 3184ms
4 3147ms 3763ms
5 2941ms 2675ms


从以上结果可以看出,数据量少时,有无索引情况下,并发更新不同行数据的性能大致相同。

3、数据量大时,执行5次,并发10更新同一行数据性能测试结果为:

执行语句:

update `category2` set `updated_time` = CURRENT_TIMESTAMP() where `name` = 'cate_1000'

加索引数据表结构为:

CREATE TABLE `category2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(220) NOT NULL,
  `created_time` datetime NOT NULL,
  `updated_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `Index` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10277277 DEFAULT CHARSET=utf8

数据量为:
[MySQL] 并发更新性能测试_第7张图片

执行次数 未加索引 加索引
1 55773ms 427ms
2 61479ms 311ms
3 55599ms 355ms
4 55280ms 357ms
5 53652ms 350ms


从以上数据可以看出,数据量大时,有索引并发更新同一行数据性能远远超过无索引。

4、数据量大时,执行5次,各并发5更新不同行数据性能测试结果为:

执行次数 未加索引 加索引
1 57077ms 318ms
2 56290ms 352ms
3 55726ms 361ms
4 55465ms 324ms
5 55483ms 365ms


从以上数据可以看出,数据量大时,有索引并发更新不同行数据性能远远超过无索引。

结论:
1、数据量少时,有无索引对并发更新性能影响不大;
2、数据量大时,有索引并发更新性能远远超过无索引;
3、从以上数据看出,单纯执行update操作时,有无索引情况下并发更新不同行性能大致相同(可能是由于无索引情况下 update 占据的表锁在执行完当前 update 操作之后,自动释放,参看MySQL行级锁)。

你可能感兴趣的:(mysql)