当前位置: 代码网 > it编程>数据库>Mysql > MySQL中UUID主键的优化小结

MySQL中UUID主键的优化小结

2024年09月04日 Mysql 我要评论
uuid(universally unique identifier 通用唯一标识符),是一种常用的唯一标识符,在mysql中,可以利用函数uuid()来生产uuid。因为uuid可以唯一标识记录,因

uuid(universally unique identifier 通用唯一标识符),是一种常用的唯一标识符,在mysql中,可以利用函数uuid()来生产uuid。因为uuid可以唯一标识记录,因此有些场景可能会用来作为表的主键,但直接用uuid来作为主键可能存在性能缺陷,我们需要采取一些优化手段。

一、uuid主键的缺陷

在mysql中,innodb是按照表的聚簇索引(主键)来组织数据存储的,也就是主键的顺序决定了数据存储的顺序。这也是为什么我们通常推荐用整型,自增的数字来作为表的主键,当新数据插入时,主键一定是最大的,只要放在叶子层中最后的数据页即可,对已有的数据不会有影响。

而如果用uuid来做主键,则会有2个缺陷:

  • uuid的值是随机的,因此新插入的数据有可能会插到已有数据的中间,这会导致整个索引树的重新平衡和节点分裂,降低插入性能,数据量越大越严重。
  • uuid是字符型,相对数字占用的存储空间很大,这意味着主键很大,而主键又会附加到所有的二级索引中,因此所有的索引都很臃肿,消耗额外的磁盘和内存资源,降低查询性能。

uuid的生成方式有很多版本,这里举2个最常用的:

  • uuid v1: 通过时间戳和mac地址来生成,可以生成顺序的uuid。
  • uuid v4: 通过随机数来生成,无法生成顺序的uuid。

mysql自带的函数uuid()是通过uuidv1生成,因此上面第一个缺陷通常不存在,你需要注意的是某些应用是否会自己生成非顺序的uuid插入表中。

下面通过示例来看差别,我们创建两张结构一样的表,一张用数字作为主键,一张用uuid作为主键:

create table digital_pk(
id int auto_increment primary key,
serial int);

create table uuid_pk(
id varchar(36) default(uuid()) primary key,
serial int);

我们分别向2张表中插入5条数据:

insert into digital_pk(serial) values(1);
insert into digital_pk(serial) values(2);
insert into digital_pk(serial) values(3);
insert into digital_pk(serial) values(4);
insert into digital_pk(serial) values(5);

insert into uuid_pk(serial) values(1);
insert into uuid_pk(serial) values(2);
insert into uuid_pk(serial) values(3);
insert into uuid_pk(serial) values(4);
insert into uuid_pk(serial) values(5);

我们通过explain来查看索引的信息:

  • explain select * from digital_pk where id=1\g

explain select * from uuid_pk where id='71b49d70-7f98-11ee-a9a1-0050569c9844'\g

可以看到uuid作为主键的长度是146,而数字做主键的长度为4,这意味着当数据量非常大的时候,uuid的索引会非常臃肿,查询性能会很低。

二、优化方案

虽然通常不推荐使用uuid作为表的主键,但某些场景如果我们必须要用uuid作为主键,我们也可以通过一些方法来规避上述缺陷。

mysql为了优化uuid的存储,专门提供了两个函数:

  • uuid_to_bin(uuid, swap_flag),将字符型uuid转换为二进制uuid,转换后返回的数据类型是varbinary。
  • bin_to_uuid(uuid, swap_flag),将二进制uuid转换为字符型uuid

在存储的时候用uuid_to_bin(uuid, swap_flag)将uuid由字符型转化为二进制,可以大大缩小索引的长度,函数中的swap_flag有2个取值:

  • 0 代表转换后的数据依然是和uuid字符排序相同
  • 1 代表转换后将uuid中的time-low和time-high部分(第一和第三组)交换位置,转换后数据可以按时间连续递增,对innodb的聚簇索引还会有性能提升。注意这个仅对uuid v1版本基于时间戳生成的uuid才有效,如果是其他类型的uuid,不会得到性能提升。

下面我们利用这个函数新建一个表uuid_pk_v2:

create table uuid_pk_v2(
id binary(16) default(uuid_to_bin(uuid(),1)) primary key,
serial int);

  • 这里id列的数据类型变成了binary(16),同时uuid在存储时转换为二进制型存储。

插入1条数据

  • insert into uuid_pk_v2(serial) values(1);

select id, serial from uuid_pk_v2;
select bin_to_uuid(id,1), serial from uuid_pk_v2;

  • 直接查询是以16进制显示的数据,这对我们没有意义,我们需要用bin_to_uuid()函数将数据还原为字符串型uuid。

我们再看一下索引:

explain select * from uuid_pk_v2 where id=uuid_to_bin('a292725f-7fa1-11ee-a9a1-0050569c9844',1)\g

  • 索引的长度从164缩短为16,只有原来的十分之一,这代表索引在磁盘和内存占用的空间也会缩小至十分之一,扫描速度会快的多。
  • 因此,虽然在插入和查询的时候多了一层函数的处理,但是这可以完美解决前面uuid的两个缺陷,带来的性能提升是完全值得的。

到此这篇关于mysql中uuid主键的优化小结的文章就介绍到这了,更多相关mysql uuid主键优化内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网! 

(0)

相关文章:

  • Mysql连接数的基本知识讲解

    基本知识连接总数(total connections)自mysql服务器启动以来,所有客户端建立的连接总次数,包括成功和失败的连接尝试活跃连接数(active connection…

    2024年09月04日 数据库
  • MySQL Prepared语句的具体使用

    在数据库应用中,很多sql语句都会重复执行很多次,每次执行可能只是where条件中的变量值不同,但mysql依然会解析sql语法并生成执行计划。对于这类情况,可以利用prepare…

    2024年09月04日 数据库
  • MySQL加减间隔时间函数DATE_ADD和DATE_SUB的实现

    MySQL加减间隔时间函数DATE_ADD和DATE_SUB的实现

    前言mysql中内置函数date_add 和 date_sub能对指定的时间进行增加或减少一个指定的时间间隔,返回的是一个日期。语法添加时间间隔date_add... [阅读全文]
  • MySQL虚拟列的具体使用

    MySQL虚拟列的具体使用

    在mysql中,虚拟列(也称为生成列)是一种特殊类型的表列,它不像普通列直接存储数据,而是根据其他列中的数据动态生成。虚拟列可以基于一个或多个其他列的值进行计算... [阅读全文]
  • mysql查询锁表的实现方法

    mysql查询锁表的实现方法

    今天在做数据更新的时候,发现表中数据量不大,但是更新语句执行很久都没成功,经过查询后发现是表锁死导致的,本文记录一下锁表解决步骤:1.查看表是否被锁(1)直接在... [阅读全文]
  • MySQL自连接与子查询方式

    MySQL自连接与子查询方式

    1. 自连接自连接是表自身与自身做笛卡尔积,在sql中进行条件查询,都是指定某一列或多个列之间进行关系运算,无法进行行与行之间的运算,在某些情况下需要对行与行之... [阅读全文]

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com