- 前言
在MySQL中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究竟有什么坏处?本篇博客我们就来分析这个问题,探讨一下内部的原因。
一、MySQL和程序实例
要说明这个问题,我们首先来建立三张表,分别是user_auto_key,user_uuid,user_random_key,分别表示自动增长的主键,uuid作为主键,随机key作为主键,其它我们完全保持不变.根据控制变量法,我们只把每个表的主键使用不同的策略生成,而其他的字段完全一样,然后测试一下表的插入速度和查询速度:
注:这里的随机key其实是指用雪花算法算出来的前后不连续不重复无规律的id:一串18位长度的long值
光有理论不行,直接上程序,使用spring的jdbcTemplate来实现增查测试
技术框架:springboot+jdbcTemplate+junit+hutool,程序的原理就是连接自己的测试数据库,然后在相同的环境下写入同等数量的数据,来分析一下insert插入的时间来进行综合其效率,为了做到最真实的效果,所有的数据采用随机生成,比如名字、邮箱、地址都是随机生成,程序已上传自gitee,地址在文底。
@SpringBootTest
class
MysqlDemoApplicationTests
{
@Autowired
private
JdbcTemplateService
jdbcTemplateService;
@Autowired
private
AutoKeyTableService
autoKeyTableService;
@Autowired
private
UUIDKeyTableService
uuidKeyTableService;
@Autowired
private
RandomKeyTableService
randomKeyTableService;
@Test
void
testDBTime() {
StopWatch
stopwatch =
new
StopWatch
(
"执行sql时间消耗"
);
/**
* auto_increment key任务
*/
final
String
insertSql =
"INSERT INTO user_key_auto(user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?)"
;
List
<
UserKeyAuto
> insertData = autoKeyTableService.getInsertData();
stopwatch.start(
"自动生成key表任务开始"
);
long
start1 =
System
.currentTimeMillis();
if
(
CollectionUtil
.isNotEmpty(insertData)) {
boolean
insertResult = jdbcTemplateService.insert(insertSql, insertData,
false
);
System
.
out
.println(insertResult);
}
long
end1 =
System
.currentTimeMillis();
System
.
out
.println(
"auto key消耗的时间:"
+ (end1 - start1));
stopwatch.stop();
/**
* uudID的key
*/
final
String
insertSql2 =
"INSERT INTO user_uuid(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)"
;
List
<
UserKeyUUID
> insertData2 = uuidKeyTableService.getInsertData();
stopwatch.start(
"UUID的key表任务开始"
);
longbegin
=
System
.currentTimeMillis();
if
(
CollectionUtil
.isNotEmpty(insertData)) {
boolean
insertResult = jdbcTemplateService.insert(insertSql2, insertData2,
true
);
System
.
out
.println(insertResult);
}
long
over =
System
.currentTimeMillis();
System
.
out
.println(
"UUID key消耗的时间:"
+ (over -
begin
));
stopwatch.stop();
/**
* 随机的long值key
*/
final
String
insertSql3 =
"INSERT INTO user_random_key(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)"
;
List
<
UserKeyRandom
> insertData3 = randomKeyTableService.getInsertData();
stopwatch.start(
"随机的long值key表任务开始"
);
Long
start =
System
.currentTimeMillis();
if
(
CollectionUtil
.isNotEmpty(insertData)) {
boolean
insertResult = jdbcTemplateService.insert(insertSql3, insertData3,
true
);
System
.
out
.println(insertResult);
}
Long
end
=
System
.currentTimeMillis();
System
.
out
.println(
"随机key任务消耗时间:"
+ (
end
- start));
stopwatch.stop();
String
result = stopwatch.prettyPrint();
System
.
out
.println(result);
}
!](https://img-blog.csdnimg.cn/20200907143300198.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lvbmh1MTIzamF2YQ==,size_16,color_FFFFFF,t_70#pic_center)
可以看出在数据量100W左右的时候,uuid的插入效率垫底,并且在后序增加了130W的数据,uudi的时间又直线下降。时间占用量总体可以打出的效率排名为:
auto_key>random_key>uuid,uuid的效率最低,在数据量较大的情况下,效率直线下滑。那么为什么会出现这样的现象呢?带着疑问,我们来探讨一下这个问题:
https://gitee.com/Yrion/mysqlIdDemo