MySQL uuid及其相关的一些简单性能测试

这篇具有很好参考价值的文章主要介绍了MySQL uuid及其相关的一些简单性能测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

运维同事导入一批大约500万左右的数据,耗时较久。他使用的是纯SQL导入,主键使用的是UUID,因为业务原因没有使用自增ID。
因为是内网,不能远程访问。
通过沟通,大致觉得有两个原因,一是因为UUID作为主键,二是表字段繁多,单行加起来接近10000的长度引起行溢出。

因为是临时一次性任务,同事没有做深纠,我在这里简单做一个验证。
版本:5.7.19
引擎:innodb


uuid主键的影响


mysql自带的UUID()函数简单方便,不重复。但是它缺点也是众所周知的。

  • UUID的返回值通常是随机的,而InnoDB的表实质是以主键组织存储的索引,插入新的记录不是顺序追加,而会往前插入,造成页分裂,表的再平衡。在数据量越大的情况,性能影响越严重。

  • 主键包含在每个二级索引中,过长的主键会浪费磁盘和内存的空间。


页分裂


为什么主键ID的顺序这么重要?

mysql innodb引擎数据结构为B+tree,查找的时候二分查找,这就要求数据是按顺序存储的。
而UUID是无序的,它作为主键在写入的时候,就可能会频繁的进行中间插入和页分裂。页分裂会造成已有的数据移位,类似于arraylist进行插入数据。
因此表数据越多,插入的效率就会越低。也会使得磁盘空间利用率降低。


除了UUID,其它还有两种常见的ID生成法。
一是自增id,最简单效率也最高,但不适合分布式唯一主键,和在一些敏感业务如订单注册用户时,可能通过ID值会暴露一些商业秘密。


雪花算法


再一个是雪花算法,最常见的分布式ID生成算法。

可以看到它跟时间戳(毫秒级)和服务器相关,通过12bit序列号区分同毫秒内产生的不同id。
因此能保证在单台服务器上的大致趋势递增。 在并发高的情况下不能保证完全递增,因此需考虑到这一点。

它有时钟回拨的问题,这里不展开。

MySQL uuid及其相关的一些简单性能测试


定量验证

以上只是定性的判断。


下面做一下定量的测试。

本文验证自增id,雪花算法ID,以及uuid作为主键3种情况,往3张空表插入500万条数据,每个批次10万,共50个批次。

        StopWatch stopWatch = new StopWatch();
        stopWatch.start("准备数据阶段");
        int count = 500 * 10000 ;
        List<TUser> list = new ArrayList<>(count);
        ExecutorService executorService = Executors.newFixedThreadPool(100);
        List<TUser> finalList = list;
        Semaphore semaphore = new Semaphore(100);
        for (int i = 0; i < count; i++) {
            executorService.submit(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    semaphore.acquire();
                    TUser user = new TUser();
                    // 雪花算法ID
                    user.setId(SnowflakeIdUtil.snowflakeId());
                    user.setName(testService.getRandomName());
                    // UUID
                    user.setId(UUID.randomUUID().toString());
                    finalList.add(user);
                    semaphore.release();
                }
            }).get();
        }

        stopWatch.stop();

        System.out.println("开始写入");

        List<Time> times = new ArrayList<>();
        stopWatch.start("写入数据阶段");
        List<TUser> subList = new ArrayList<>(100000);
        for (int i = 1; i <= count; i++) {
            TUser user = finalList.get(i-1);
            subList.add(user);
            if (i % 100000 == 0) {
                // finalList.remove(user);
                long start = System.currentTimeMillis();
                tUserDao.insertBatch(subList);
                long time = System.currentTimeMillis() - start;
                times.add(new Time(time));
                subList.clear();
                log.info("写入一次" + i);
            }
        }

        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        // 将每个批次耗时打印出来,放入excel生成图表
        times.stream().map(e -> e.getTime()).forEach(System.out::println);

总耗时情况

UU ID:414321ms
雪花ID 167748ms
自增ID 75829ms


将最后每个批次耗时的集合打印出来,放到Excel中,生成图表。

纵坐标表示耗时,单位ms
横坐标表示写入批次


MySQL uuid及其相关的一些简单性能测试


可以明显的观察到,使用UUID作为主键,在表数据量在350万以后,耗时上升极快,性能呈指数级下降。
同时自增ID效率高于雪花算法ID,都很稳定。

这是在行数据量极小(<50)的情况下。

在行大小> 8000,在页16KB至少两行数据的情况下,也必然会发生行溢出。这里再看看测试情况。


行溢出情况

MySQL单行数据最大能存储65535字节的数据,InnoDB的页为16KB,即16384字节,当行的实际存储长度超过16384/2的长度时,就会行溢出。
为什么是/2,因为页至少需要存储两行数据。
为什么单页至少存储两行数据,如果为1,B+tree就退化为了链表。

当行溢出的时候,会将大字段数据存放在页类型为Uncompress BLOB页中,在当前页就会对大字段建立一个引用,类假于二级索引。

所以设置测试表name长度大于大约16384/2的时候,就会发生行溢出现象。


行溢出时,3种不同ID的表现


测试代码跟上面类似。
再准备3张空表。
字段类型varchar,长度10000,user.setName()设置实际长度大于8000。

这次只写入50万条数据,每批次1万条数据,共50个批次。

MySQL uuid及其相关的一些简单性能测试

这次uuid在写入30万条记录后,耗时开始明显上升。


以上是行溢出的情况下,UUID,雪花算法,自增ID等 3种ID的写入性能情况。


uuid在溢出和不溢出下的表现


下面来测试一下,使用UUID在行溢出和不溢出的两种情况下写入性能情况。

再新建两张表,t_user_uuid_long,此表name字段长度100000,最终写入字符长度9995
t_user_uuid_short,此表name字段长度8000,最终写入字符长度7995

MySQL uuid及其相关的一些简单性能测试

写入耗时曲线大致相当,看不出明显差距。


但是读的差距非常明显!

因为t_user_uuid_long 中的name字段发生了行溢出,。。。。。select的时候需要跨页提取数据,类似于做了1次回表,而且回表还是跨页的。

select id,name from t_user_uuid_short order by id asc limit 1000
耗时0.145s

select id,name from t_user_uuid_long order by id asc limit 1000
耗时4.153s,性能相差接近30倍。

小结

以上测试结果只是在测试机上的粗糙测试结果,不是基准测试,只做参考。

测试结果表明,运维同事的慢操作可能受UUID影响 ,但大字段对写入的影响并不明显。
不过大字段对读取的性能影响明显。文章来源地址https://www.toymoban.com/news/detail-468175.html

到了这里,关于MySQL uuid及其相关的一些简单性能测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux服务器常见运维性能测试(3)CPU测试super_pi、sysbench

    最近需要测试一批服务器的相关硬件性能,以及在常规环境下的硬件运行稳定情况,需要持续拷机测试稳定性。所以找了一些测试用例。本次测试包括在服务器的高低温下性能记录及压力测试,高低电压下性能记录及压力测试,常规环境下CPU满载稳定运行的功率记录。 这个系

    2024年02月02日
    浏览(55)
  • Linux服务器常见运维性能测试(1)综合跑分unixbench、superbench

    最近需要测试一批服务器的相关硬件性能,以及在常规环境下的硬件运行稳定情况,需要持续拷机测试稳定性。所以找了一些测试用例。本次测试包括在服务器的高低温下性能记录及压力测试,高低电压下性能记录及压力测试,常规环境下CPU满载稳定运行的功率记录。 这个系

    2024年02月04日
    浏览(82)
  • Mysql8.0.x新特性及其性能优化分析

    8.0.17及之后的版本更新的内容比较多,推荐使用8.0.17及之后的版本。 参考文档: 添加弃用和删除的特性: https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshell.html 添加弃用和删除的参数: https://dev.mysql.com/doc/refman/8.0/en/added-deprecated-removed.ht ml Mysql8 InnoDB 架构: https://dev.mysql.com/doc/refm

    2024年04月26日
    浏览(30)
  • 性能测试很简单-JMeter性能测试实践

    最近破费买了一台服务器,准备搭建自己的网站,顺便将自己开发的一些测试小工具部署到服务器上,虽然机器配置一般,还是决定对服务器进行压测一番,看一下服务器性能如何。本次压测选择的工具是JMeter,这个工具也是接口测试工具,可以做接口自动化测试。话不多说

    2024年01月16日
    浏览(48)
  • MySQL 数据存储和优化------MySQL索引原理和优化 ---- (架构---索引---事务---锁---集群---性能---分库分表---实战---运维)持续更新

    Mysql架构体系全系列文章主目录(进不去说明还没写完) https://blog.csdn.net/grd_java/article/details/123033016 本文只是整个系列笔记的第二章:MySQL索引原理和优化,只解释索引相关概念。 索引可以提高查询效率,影响where查询和order by排序,它可以从多方面进行分类,但是实际创建时

    2024年02月02日
    浏览(54)
  • 【ceph相关】ceph基准性能测试工具

    参考文档:RedHat-Ceph性能基准 本篇主要介绍几种ceph原生基准性能测试工具以及各自对应使用方法 不同于fio、vdbench等上层应用接口测试工具,ceph提供了一些自带的基准性能测试工具,用于测试rados、rbd等底层存储基准性能,可以比对底层基准性能和上层应用基准性能,确定潜

    2023年04月08日
    浏览(43)
  • MySQL的索引——索引的介绍及其数据结构B+树 & 索引的类型 & 索引的使用及其失效场景 & 相关名词解释

    索引是存储引擎用于快速查找数据纪录的一种数据结构,索引是数据库中经常提及的一个词,究竟什么是索引,索引的数据结构是什么,索引有什么类型? 本篇博客尝试阐述数据库索引的相关内容,涉及什么是索引,索引的数据结构;对比了聚集索引和非聚集索引,分析了索

    2024年02月20日
    浏览(43)
  • 性能测试-压力测试-jmeter简单实战

    压力测试考察当前 软硬件环境 下系统 所能承受的最大负荷并帮助找出系统瓶颈所在 。压测都是为了系统在线上的 处理能力和稳定性维持在一个标准范围内 ,做到心中有数。 使用压力测试,我们有希望发现找到很多种其他测试方法很难发现的错误。 有两种错误类型是:内

    2024年02月10日
    浏览(48)
  • 功能测试也可以发现数据库相关的性能问题

    很多同学认为功能测试和性能测试是严格分开的,功能测试人员无法发现性能问题。其实不是这样的,功能测试人员在验证功能时也可以发现性能问题;一些功能反而在功能测试环境不好验证,需要在性能环境上测试。     今天咱们就说一下测试涉及数据库操作的功能时如何

    2024年02月14日
    浏览(51)
  • 性能测试、负载测试、压力测试、稳定性测试简单区分

    是一个总称,可细分为性能测试、负载测试、压力测试、稳定性测试。 以系统设计初期规划的性能指标为预期目标,对系统不断施加压力,验证系统在资源可接受范围内,是否能达到性能瓶颈。 提取理解 有性能指标,验证 性能测试目标 验证系统的性能指标,是否为

    2024年02月09日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包