您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

UUID 及其在 MySQL 中的使用

时间:2020-10-09 11:00:49  来源:  作者:
UUID 及其在 MySQL 中的使用

 

1. UUID 是什么?

UUID(Universally Unique Identifier 通用唯一识别码)用于标识资源唯一性。理论上说,门牌号、电话号码、邮编、身份证号都是用来标识资源唯一性的,但为使用方便,不适合用一个无规律的字符串表示,UUID 主要还是在程序中使用。

UUID 源自1980年代的 Apollo 电脑公司,是一个 128 位的标识符,理论上的总数有 2128个,也就是说,哪怕每纳秒产生 1 万亿个 UUID,也要 100 亿年才能用完。因此,只要保证生成方法的散布足够好,统计概率上,UUID 重复的可能性约等于 0 。

UUID 的具体规范可以参考 RFC 4122。这个标准定义了 5 个版本的 UUID:

  1. 版本 1 根据时间和 mac 地址来生成 UUID。MAC 地址用于保证设备唯一性。通过在时间戳后加入 13-14 位的时钟序列,可以保证在同一台设备,同 1 秒内生成的 1630 亿个 UUID 不重复。 这个版本的 UUID 我们用得相对较少,一个原因是其中携带了设备信息。1999 年,著名病毒梅丽莎的作者,因为代码中的 UUID 暴露了 MAC 地址信息,不到一个星期就被抓住了。另一个原因是这个版本的 UUID 生成有规律,比较容易根据一个 UUID 推断到下一个 UUID。
  2. 版本 2 是一个 DEC 安全的版本,RFC4122 中也没有详细说明具体实现方式,我们一般也用不到。
  3. 版本 3 根据字符串和命名空间散列值(HASH)来获取 UUID。由于 HASH 函数本身的特性,一般不用担心 UUID 冲突,或者别人根据散列值反推原数据的问题。这个版本采用的是 MD5 散列值。
  4. 版本 4 根据随机数生成 UUID,是我们比较常用的版本。
  5. 版本 5 和版本 3 一样,也是根据散列值获取 UUID,不过采用的散列算法是 SHA-1 而不是 MD5,相较而言,RFC4122 推荐大家使用版本 5 而不是版本 3。

我们常看到的 UUID 往往被表示为 16 进制数字和横杠组成的字符串,比如:a3535b78-69dd-4a9e-9a79-57e2ea28981b,其中第二个横杠之后的第一个数字表示 UUID 版本,例子中这个 UUID 就是版本 4 的。


2. 为什么在数据库中使用 UUID?

大多数人在数据库中存储 UUID 的直接原因,是需要一个不暴露内部信息的唯一标识。例如博客文章,Title 无法保证不重复,数字 ID 则会暴露内部信息,于是,可以生成一个 UUID 作为唯一标识。类似地,我们在网上请求的许多公开资源,如图片、音频、以及其他文件等,都是以 UUID 作为标识的。

第二个原因,是为了方便数据管理:

  1. 当数据量过大,不得不进行分片管理的时候,数字 ID 的唯一性不好保证;万一需要重建部分数据,数字 ID 也很难确保与原表一致。
  2. UUID 作为预先生成的值,可以在插入数据库之前拿到,会方便一些数据操作。

3. UUID 作为主键有什么问题?

一般不推荐把 UUID 作为主键,它会带来不少问题:

3.1 数据碎片化

我们知道,使用自增 ID 作为主键时,插入新的数据行往往是连续的,插入多条数据只需要读写少数数据页。但由于 UUID 的随机性,新插入的数据往往会落在不同的数据页上,导致数据碎片化,同样的数据量,可能需要更大的空间才能存储。

同时,当数据量上升,内存中无法暂存足够多的数据页时,每次插入数据都可能涉及硬盘读写,极大地拖慢了数据插入效率。

3.2 索引占用空间过大

大多数人会把 UUID 保存为 16 进制数字和横杠组成的字符串,也就是 char(36),如果采用 UTF-8 字符集,它所占的字节数是 2 + 3 * 36 = 110 字节(前面 2 个字节为长度,后面每个字符 3 个字节)。相较而言,一个整数只有 4 个字节,相差 27 倍。

数据库采用 B 树索引,其中主键索引的叶子节点指向数据行,而二级索引的叶子节点存储着主键,之后再通过主键索引回表查数据。也就是说,有多少个二级索引,主键就需要被存储几次,因此,索引的空间需求就极速扩张了。

在数据库运行过程中,为加快查询速度,这些索引往往需要被加载到内存中。那么,过大的索引导致内存不足,就会严重影响数据库查询效率。

3.3 字符比较比整数比较慢

CPU 每次最多可以比较 8 个字节的整数值,但对于字符串,必须一个字符一个字符比较过去。有测试说明,在查询比较时,使用整数的速度比使用字符串的速度快数倍到数十倍之间。

不过,一般来说,数据库不是一个 CPU 密集的应用,因此这方面的影响不是主要考虑因素。


4. 替代方案讨论

4.1 优化 UUID 的存储

将 UUID 存储为 16 进制值和横杠组成的字符串是非常低效的,UUID 本身只有 128 位,也就是 16 字节,存储成字符串后却有 110 个字节,膨胀了 7 倍,凭空多占了不少空间。优化的思路就是采用更好的格式,比如直接存储二进制,或者将二进制值存储为 base64 字符串。相对复杂一点的是将 UUID 映射到一个整数。

优化存储格式的具体实现都不困难,也能相当程度地节约存储空间,但并没有解决 UUID 的随机性带来的数据碎片化的问题。

针对碎片化的问题,有一个思路是控制随机性,也就是增加一个自己生成的字符串作为前缀,比如说日期(或它的哈希值)。因为字符串排序从前往后走,同样的前缀也就意味着接近的排序,那么,原本散布在整个数据库的值,就会集中分布在一定范围内的数据页,从而大大缓解了内存压力。

4.2 同时使用自增 ID 和 UUID

更常见的思路,是使用自增 ID 作为主键,同时使用 UUID 作为唯一标识和与其它表关联的外键。好处是有了一个可以比较安全地对外暴露的唯一标识,节约了索引空间,也不用担心数据分片和数据重建带来的危险。

但也存在一些问题,因为所有的外键关联都用的 UUID,所以占用的空间自然会大一些,同时,字符串比较速度较慢和所有查询都要回表也是值得考虑的因素。

4.3 避开 UUID

很多小型应用不需要考虑数据管理的问题,只是需要一个可以对外暴露的唯一标识,于是,干脆放弃 UUID,采用其他思路实现标识的唯一性。

比如说前面说的博客文章,鉴于 Title 没法保证唯一性,可以在 Title 前后加上一个前缀或者后缀,从而实现唯一性。一个思路是使用随机字符串,或者作者、日期等信息。

又比如说,将每个数据行映射到一个大整数作为唯一标识。某种意义上等于根据自己的实际需要写了一套新的唯一标识算法。

 

END



Tags:UUID   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
1. UUID 是什么?UUID(Universally Unique Identifier 通用唯一识别码)用于标识资源唯一性。理论上说,门牌号、电话号码、邮编、身份证号都是用来标识资源唯一性的,但为使用方便,...【详细内容】
2020-10-09  Tags: UUID  点击:(153)  评论:(0)  加入收藏
01 大数据时代的新挑战:实时流计算社会需求和科技进步是螺旋式相互促进和提升的。“大数据”一词最早由Roger Mougalas在2005年提出,所以我们姑且认为2005年是大数据时代的元...【详细内容】
2020-03-14  Tags: UUID  点击:(83)  评论:(0)  加入收藏
▌简易百科推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  爱可生    Tags:MySQL   点击:(6)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  python数据分析    Tags:MySQL记录锁   点击:(17)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  linux上的码农    Tags:mysql   点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  元宇宙iwemeta    Tags:mysql   点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  吴彬的分享    Tags:Mysql数据库   点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  秃头码哥    Tags:MySQL数据库   点击:(16)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  笨鸟学数据分析    Tags:MySQL   点击:(19)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  笨鸟学数据分析    Tags:SQL语句   点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Java云海    Tags:分布式锁   点击:(31)  评论:(0)  加入收藏
MySQL的进阶查询 一、 按关键字排序 使用ORDERBY语句来实现排序排序可针对一个或多个字段ASC:升序,默认排序方式 【升序是从小到大】DESC:降序 【降序是从大到小】ORDER BY的...【详细内容】
2021-11-05  Java热点    Tags:SQL语句   点击:(27)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条