mybatis自增id数据插入和雪花id插入性能比较


前言

面试中有问到雪花id和自增id插入数据效率到底哪个快?个人觉得是数据库自增di快,具体快多少,没有做出解释。做个测试具体测试一下到底快多少,测试结果仅供参考。

二、使用步骤

1.引入雪花id生成工具hutool

代码如下(示例):

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>

2.建立实验使用的表

使用正常自增id表:

CREATE TABLE `a` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) DEFAULT NULL,
  `sex` int(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `insertTime` datetime DEFAULT NULL,
  UNIQUE KEY `id` (`id`),
  KEY `nameindex` (`name`,`sex`,`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=20001 DEFAULT CHARSET=utf8;

雪花id表

CREATE TABLE `a1` (
  `id` bigint(20) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `sex` int(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `insertTime` datetime DEFAULT NULL,
  UNIQUE KEY `id` (`id`),
  KEY `nameindex` (`name`,`sex`,`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.测试代码

control层如下:

    @RequestMapping(value = "/hello2",method = RequestMethod.GET)
    public String index3() {
    
    
        userService.insertUser1();
        //helloService.sayHello();
        // redisTemplate.opsForValue().set("aaa","xxx");
        return "xxxx";
    }

    @RequestMapping(value = "/hello3",method = RequestMethod.GET)
    public String index4() {
    
    
        userService.insertUser2();
        //helloService.sayHello();
        // redisTemplate.opsForValue().set("aaa","xxx");
        return "xxxx";
    }

service类如下
insertUser1为自增id插入,insertUser2为雪花id插入。

  @Override
    public void insertUser1() {
    
    
        long starTime = System.currentTimeMillis();
        for (int j = 0; j < 10; j++) {
    
    
            List<User> list = new ArrayList<>();
            for(int i = 0; i < 2000; i++) {
    
    
                User user = new User();
                Date date = new Date();
                user.setName("小红"+date.getTime());
                user.setAge(12);
                user.setSex(1);
                user.setInsertTime(date);
                list.add(user);
            }
            userDao.insertUser1(list);
        }
        System.out.println("插入总耗时:{}"+ (System.currentTimeMillis()-starTime)+"ms");
        }

    @Override
    public void insertUser2() {
    
    
        long starTime = System.currentTimeMillis();
        Snowflake snowflake = IdUtil.getSnowflake(31,31);
        for (int j = 0; j < 10; j++) {
    
    
            List<User1> list = new ArrayList<>();
            for(int i = 0; i < 2000; i++) {
    
    
                User1 user = new User1();
                Date date = new Date();
                user.setId(snowflake.nextId());
                user.setName("小红"+date.getTime());
                user.setAge(12);
                user.setSex(1);
                user.setInsertTime(date);
                list.add(user);
            }
            userDao.insertUser2(list);
        }
        System.out.println("插入总耗时:{}"+ (System.currentTimeMillis()-starTime)+"ms");
    }

IdUtil.getSnowflake(31,31)这里的两个参数一个是workerid,一个是datacenterid,两个参数组成机器id。

4.xml语句

 <insert id="insertUser1" parameterType="com.example.springdemo.demo.model.User">
        insert into a
        (name,sex,age,insertTime) values
        <foreach collection="list" item="item" index="index" separator=",">
            (
            #{
    
    item.name},
            #{
    
    item.sex},
            #{
    
    item.age},
            #{
    
    item.insertTime}
            )
        </foreach>
    </insert>

    <insert id="insertUser2" parameterType="com.example.springdemo.demo.model.User1">
        insert into a1
        (id,name,sex,age,insertTime) values
        <foreach collection="list" item="item" index="index" separator=",">
            (
             #{
    
    item.id},
            #{
    
    item.name},
            #{
    
    item.sex},
            #{
    
    item.age},
            #{
    
    item.insertTime}
            )
        </foreach>

5.开始测试

1.先测试两个都插入20000条记录测。
先调用自增id的
在这里插入图片描述
结果如下:

2023-02-20 11:26:35.003  INFO 10680 --- [nio-8008-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-02-20 11:26:35.003  INFO 10680 --- [nio-8008-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-02-20 11:26:35.005  INFO 10680 --- [nio-8008-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms
插入总耗时:{
    
    }7710ms

再调用雪花id的
在这里插入图片描述
结果如下;

插入总耗时:{
    
    }7880ms

自增的比雪花id快170ms

2.再测试两个表都插入200000条记录测试。
把两个表都清空,再测试。

truncate table a; 
truncate table a1; 

自增id测试
在这里插入图片描述

2023-02-20 11:39:11.374  INFO 14136 --- [nio-8008-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-02-20 11:39:11.374  INFO 14136 --- [nio-8008-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-02-20 11:39:11.375  INFO 14136 --- [nio-8008-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
插入总耗时:{
    
    }14814ms

雪花id测试
在这里插入图片描述
测试结果

插入总耗时:{
    
    }17030ms

自增比雪花id快2216ms
前后测试了多次,结果都是自增id的比较快。

总结

1.雪花id的数据库类型要使用bigint,java类型使用long类型,如果数据库类型不是bigint会报错如下

### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'id' at row 1
### The error may exist in file [D:\javaTools\ideaCode\springbootdemo\target\classes\com\example\springdemo\demo\dao\UserDao.xml]
### The error may involve com.example.springdemo.demo.dao.UserDao.insertUser2-Inline
### The error occurred while setting parameters

2.实验证明自增id的确是比雪花id要快,但是现在的系统基本上都是分布式系统,使用雪花id原因有
2.1 可以避免id重复,而且雪花id是在时间戳+机器id一定的情况下有序。基本符合索引的数据要求。
2.2 要提前生成id去做其他业务的操作,而不用插入数据再返回id。
2.3 数据安全要求,自增id可以让用户直接看到id是多少,猜测数据量多大。
3.雪花id让数据插入性能受到了影响,但是目前没发现更好的解决方案,牺牲一些性能也可以接受。

猜你喜欢

转载自blog.csdn.net/qq_34526237/article/details/129120749
今日推荐