通用唯一识别码的介绍和使用
前言
在日常数据库使用中,经常会遇到UUID这种数据类型,此次博文主要向大家分享一下UUID的基本概念及如何在华为云数仓GaussDB(DWS)中生成UUID。
1. UUID的定义
UUID含义是通用唯一识别码 (Universally Unique Identifier),这是一个软件建构的标准,也是被开源软件基金会 (Open Software Foundation, OSF) 组织应用在分布式计算环境 (Distributed Computing Environment, DCE) 领域的重要部分。其目的是让分布式系统中的所有元素都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。目前最广泛应用的UUID,是微软公司的全局唯一标识符(GUID),而其他重要的应用,则有Linux ext2/ext3文件系统、LUKS加密分区、GNOME、KDE、Mac OS X等等。
2. UUID的格式
UUID由开放软件基金会标准化,作为分布式计算环境的一部分,在互联网工程任务组(IETF)公布的RFC 4122标准中对UUID进行了标准化。标准的UUID由36个字符组成,其中包括32个16进制数字和4个连字分隔符‘-’,形式为8-4-4-4-12,标准的UUID示例如下:
a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
GaussDB(DWS)同样支持以其他方式输入:大写字母和数字、由花括号包围的标准格式、省略部分或所有连字符、在任意一组四位数字之后加一个连字符,示例如下:
A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
a0eebc999c0b4ef8bb6d6bb9bd380a11
a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}
3. UUID的组成
UUID采用时间信息和空间信息确保全局唯一,通常由时间戳信息、时钟序列和节点ID(MAC地址)组成。而GaussDB(DWS)分布式集群中多个节点可能部署在同一个机器上,其MAC地址相同,UUID存在冲突的风险。因此GaussDB(DWS)将最后48bit为的MAC地址替换为生成UUID的CN或DN的序号和当前的线程ID,确保UUID在分布式集群内部做到全局唯一,其组成如下图所示:
4. 生成UUID
GaussDB(DWS)提供接口函数uuid_generate_v1生成一个UUID类型的的序列号,示例如下:
SELECT uuid_generate_v1();
uuid_generate_v1
--------------------------------------
5fe5aaf3-076a-0279-6049-c927e700fffe
(1 row)
注意:uuid_generate_v1函数根据时间信息、集群节点编号、生成该序列的线程号和时钟序列生成UUID,可以确保在单个集群内部全局唯一,但在多个集群间时间信息、集群节点编号、线程号和时钟序列仍然存在同时相等的可能性,因此多个集群间生成的UUID存在极低概率冲突的可能性。
GaussDB(DWS)提供兼容Oracle的sys_guid函数,生成Oracle的类似UUID的GUID序列,示例如下:
SELECT sys_guid();
sys_guid
----------------------------------
5FE5ADAF0D3109BF2AB7C927E700FFFE
(1 row)
注意:sys_guid函数内部实现原理同uuid_generate_v1函数,因此多个集群间生成的GUID同样存在极低概率冲突的可能性。
5. UUID的应用
UUID全局唯一的特点,可以作为数据表生成主键,也可以作为数据表的分布列,uuid_generate_v1作为数据表分布列的默认值时,通过Hash分布可以将数据均匀分布到各个DN上,防止数据倾斜。示例如下:
--int类型作为分布列
testDB=# CREATE TABLE tt01(a INT, b INT) DISTRIBUTE BY hash(a);
CREATE TABLE
testDB=# INSERT INTO tt01 VALUES(1, 10);
INSERT 0 1
testDB=# INSERT INTO tt01 VALUES(1, 10);
INSERT 0 1
testDB=# INSERT INTO tt01 VALUES(1, 10);
INSERT 0 1
testDB=# INSERT INTO tt01 VALUES(1, 10);
INSERT 0 1
testDB=# INSERT INTO tt01 VALUES(1, 10);
INSERT 0 1
testDB=# SELECT * FROM tt01;
a | b
---+----
1 | 10
1 | 10
1 | 10
1 | 10
1 | 10
(5 rows)
testDB=# SELECT table_skewness('tt01');
table_skewness
-------------------------------------
("datanode1 ",5,100.000%)
("datanode2 ",0,0.000%)
(2 rows)
--UUID类型作为分布列
testDB=# CREATE TABLE tt02 (id UUID default uuid_generate_v1(), a INT, b INT) DISTRIBUTE BY hash(id);
CREATE TABLE
testDB=# INSERT INTO tt02(a, b) VALUES(1, 10);
INSERT 0 1
testDB=# INSERT INTO tt02(a, b) VALUES(1, 10);
INSERT 0 1
testDB=# INSERT INTO tt02(a, b) VALUES(1, 10);
INSERT 0 1
testDB=# INSERT INTO tt02(a, b) VALUES(1, 10);
INSERT 0 1
testDB=# INSERT INTO tt02(a, b) VALUES(1, 10);
INSERT 0 1
testDB=# SELECT * FROM tt02;
id | a | b
--------------------------------------+---+----
5fe5b85c-92a6-09c3-3690-f42fd700fffe | 1 | 10
5fe5b85c-e7e4-098b-3693-f42fd700fffe | 1 | 10
5fe5b85c-051c-0a77-3694-f42fd700fffe | 1 | 10
5fe5b85c-b09c-09fa-3691-f42fd700fffe | 1 | 10
5fe5b85c-ce27-0941-3692-f42fd700fffe | 1 | 10
(5 rows)
testDB=# SELECT table_skewness('tt02');
table_skewness
------------------------------------
("datanode1 ",3,60.000%)
("datanode2 ",2,40.000%)
(2 rows)
6. 总结
UUID的显著优点就是全局唯一,不需要中心节点,单个节点独立生成,程序在不同的数据库中迁移时效果不受影响。缺点也很显著,UUID比INT占用更多的存储空间,索引效率低,生成的ID很随机,没有递增的特性,同时辨识困难。因此,在应用中,要根据实际情况选择UUID还是Sequence作为数据表主键。
- 点赞
- 收藏
- 关注作者
评论(0)