前言
面试中有问到雪花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的
结果如下;
扫描二维码关注公众号,回复:
15593748 查看本文章
插入总耗时:{
}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让数据插入性能受到了影响,但是目前没发现更好的解决方案,牺牲一些性能也可以接受。