前言
今天开发妹子发来一个问题,我的sys_guid怎么迁移到PostgreSQL中去。这不很简单的问题吗?直接使用uuid-ossp创建的扩展就可以了,之前迁移别的库都是这么淦的。我给她的库安装了uuid-ossp扩展。然后告诉她使用uuid_generate_v4函数。结果她又丢过来一个问题。
我们的guid字段是32位长度的,你这个guid长度不行?
我愣了一下,然后在测试环境中研究了一番,果然如她所说。
Oracle中guid和PostgreSQL uuid的差异
我们先看一下Oracle中的guid。
[oracle@Hbs1~]$ sqlplus / as sysdbaSQL*Plus: Release 12.2.0.1.0 Production on Tue May 11 15:47:08 2021Copyright (c) 1982, 2016, Oracle. All rights reserved.Connected to:Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit ProductionSQL> select sys_guid() from dual;SYS_GUID()--------------------------------C20A1A40C84C19ACE053A6CD00854D85
可以看到Oracle的guid长度确实为32个字符。而PostgreSQL的guid是标准的长度36个字符。
zys=# CREATE EXTENSION uuid-ossp;CREATE EXTENSIONzys=# zys=# SELECT uuid_generate_v4(); uuid_generate_v4 -------------------------------------- 41d2abab-6c68-48e9-b8ea-6d0bb5eb92db(1 row) zys=# \df uuid_generate_v4 List of functions Schema | Name | Result data type | Argument data types | Type --------+------------------+------------------+---------------------+------ public | uuid_generate_v4 | uuid | | func(1 row)
"你这把表的字段长度改成36就行了。"
"不行,我们这个guid很多表都引用了,这样的话,我需要修改很多张表的字段长度。你能不能给我想想办法转换一下。"
竟然劝不动,没办法只好想办法给她搞了一个replcae,把中间的-给替换掉了,但是又觉得这么干很low,于是想看看有没有其他的办法搞一搞,至少不要这么low。
zys=> SELECT replace(uuid_generate_v4()::text,'-',''); replace ---------------------------------- 9c0d8c474a4342479ec5798f5873c049
果然找了一个居然可以不需要使用插件,就能实现guid的办法。
手工测试了一下,能够正常生成uuid了。
zys=> SELECT uuid_in(overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing to_hex(floor(random()*(11-8+1) + 8)::int)::text from 17)::cstring); uuid_in -------------------------------------- 8ee4b1ba-5541-4781-8061-a8e9961d5b36(1 row)
但是问题来了,同样的是有 - 这个字符的。仔细看了一番,发现使用了uuid_in这个函数。
zys=> \df uuid_in List of functions Schema | Name | Result data type | Argument data types | Type ------------+---------+------------------+---------------------+------ pg_catalog | uuid_in | uuid | cstring | func
查看这个函数,它是把cstring格式转换成uuid格式,那么不带这个函数会怎么样。
zys=> SELECT overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing to_hex(floor(random()*(11-8+1) + 8)::int)::text from 17)::cstring; overlay ---------------------------------- b501a80f9f584d1fbdb95b612161d02a(1 row)
测试运行了一下,这直接就是开发想要的结果。使用uuid_in函数,就会变成带有 - 的uuid值。
既然是这样,有没有反向的函数,可以把uuid转换成cstring格式呢?
答案就是uuid_out。
zys=> \df uuid_out List of functions Schema | Name | Result data type | Argument data types | Type ------------+----------+------------------+---------------------+------ pg_catalog | uuid_out | cstring | uuid | func(1 row)
这样我就可以在把刚刚插件产生的uuid,直接转换成cstring。
zys=> SELECT uuid_out(uuid_generate_v4()); uuid_out -------------------------------------- a02fc982-bb62-4ce8-9022-3a08e97178e2
我去竟然不行啊。还是uuid的格式。看来这个是不可逆的,只要你用了uuid相关的函数,都会自动给你加上 -。
没有办法,还是把replace的方法告诉了妹子,虽然有点low,但是它的效率要比使用overlay、md5、clock_timestamp、to_hex、floor这一堆函数要强一些。
uuid的方法
介绍完uuid的兼容性,我们再来看看uuid的方法。
zys=> \df uuid_generate_* List of functions Schema | Name | Result data type | Argument data types | Type --------+--------------------+------------------+---------------------------+------ public | uuid_generate_v1 | uuid | | func public | uuid_generate_v1mc | uuid | | func public | uuid_generate_v3 | uuid | namespace uuid, name text | func public | uuid_generate_v4 | uuid | | func public | uuid_generate_v5 | uuid | namespace uuid, name text | func(5 rows)
这里不得不称赞一下pg,居然有5种生成方式。反观相关的uuid在线生成网站,也只支持Vserion 1和Version 4这两种版本的生成。
那么pg的这5种有什么区别呢?从官方文档可以看出。
uuid_generate_v1 版本1涉及到计算机的Mac地址和一个时间戳。
uuid_generate_v1mc 这个版本类似于上面的版本,它使用的是随机广播mac地址,而不是计算机真实mac地址。
uuid_generate_v3(namespace uuid ,name text) 这个版本有两个参数,分别是namespace和name,它首先对name值进行md5函数计算出hash值,然后在使用OSSP UUID库中的UUID生成器。官方文档举例如下:
SELECT uuid_generate_v3(uuid_ns_url(),'http://www.postgresql.org');
采用这种方法的UUID生成没有随机性并且不涉及依赖于环境的元素,因此是可以重现的。
uuid_generate_v4 这个版本是一个随机数+时间戳的版本。
uuid_generate_v5 这个版本和版本3类似,但是它采用的是SHA-1作为hash的方法。
我个人觉得使用uuid_generate_v4算是比较好的一个选择。
后记
妹子还是觉得弄个Replace影响了她,很多代码都要改,说让我在给她想想办法。
并丢给我一个insert语句。
insert into xxx values(sys_guid());
然后说:"程序有几百个这样的地方要改,你自己看着办吧!"
我靠,我只好给她创建了一个sys_guid的函数,并在里面封装了replace(uuid_generate_v4()::text,'-',''),并不完美的解法,主要还是我的精力有限,不想自己开发,想着还是当个白嫖党吧。
但我希望有志之士用c语言把uuid-ossp.c给改改,创建一个uuid_generate_v100函数,起码把那个 - 去掉行不行啊。
参考链接:
1.https://stackoverflow.com/questions/12505158/generating-a-uuid-in-postgres-for-insert-statement