在Postgres中为插入语句生成UUID?


367

我的问题很简单。我知道UUID的概念,我想生成一个引用UDB的“存储”中的每个“项目”。看起来合理吧?

问题是以下行返回错误:

honeydb=# insert into items values(
uuid_generate_v4(), 54.321, 31, 'desc 1', 31.94);
ERROR:  function uuid_generate_v4() does not exist
LINE 2: uuid_generate_v4(), 54.321, 31, 'desc 1', 31.94);
        ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

我已在以下位置阅读该页面:http : //www.postgresql.org/docs/current/static/uuid-ossp.html

在此处输入图片说明

我在Ubuntu 10.04 x64上运行Postgres 8.4。


8
Postgres本机支持UUID作为数据类型,甚至能够被索引并用作主键。但是要生成 UUID值(例如为列建立默认值),则需要Postgres扩展名(插件)。Postgres的许多内部版本(发行版)都包含此类扩展名,但并未激活该扩展名。请参阅Craig Ringer正确答案,以了解如何激活它。
罗勒·布尔克

2
如果您已安装uuid-ossp且仍然出现此错误,请尝试使用您的架构名称为函数添加前缀,例如select dbo.uuid_generate_v4()
Richard

Answers:


435

uuid-ossp是contrib模块,因此默认情况下不会加载到服务器中。您必须将其加载到数据库中才能使用。

对于现代PostgreSQL版本(9.1及更高版本),这很容易:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

但对于9.0及以下版本,您必须改为运行SQL脚本来加载扩展。请参阅8.4中的contrib模块文档

对于Pg 9.1及更高版本,请阅读当前的contrib文档CREATE EXTENSION。这些功能在9.0或更早的版本(例如8.4)中不存在。

如果您使用的是PostgreSQL的打包版本,则可能需要安装包含contrib模块和扩展名的单独软件包。在软件包管理器数据库中搜索“ postgres”和“ contrib”。


6
@advocate您正在使用发行版打包的PostgreSQL,因此您应该能够使用公正apt-get install postgresql-contrib或类似的功能。尝试apt-cache search postgresql |grep contrib找到所需的程序包名称。
Craig Ringer 2012年

2
sudo apt-get install postgresql-contrib已成功运行。然后我必须运行psql -d dbname -f SHAREDIR / contrib / module.sql,现在它可以工作了!!!选择uuid_generate_v1(); 现在返回1。非常感谢!
anon58192932 '09年

5
请注意,如果您不安装postgresql-contrib软件包,则会收到错误消息:错误:无法打开扩展控制文件“ /usr/share/postgresql/9.3/extension/uuid-ossp.control”:没有此类文件或目录
Drew Noakes 2014年

1
我在错误字符串在Google上删除后发布了该评论。此外,它至少为Ubuntu提供了一个特定的程序包名称。
Drew Noakes 2014年

2
如果导入的数据库扩展中已经包含uuid-ossp,则uuid_generate_v4()可能不起作用。如果是这种情况,只需删除扩展名,然后再次创建它即可。
Dragos Rusu 2015年

302

没有扩展名(作弊)

SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);

output>> c2d29867-3d0b-d497-9191-18a9d8ee7830

(至少在8.4中有效)

  • 感谢@Erwin Brandstetter的clock_timestamp()解释。

如果您需要有效的v4 UUID

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);

在此处输入图片说明 *感谢@Denis Stafichuk @Karsten@autronix


另外,在现代Postgres中,您可以简单地进行以下转换:

SELECT md5(random()::text || clock_timestamp()::text)::uuid


5
要跟进您的PS,请执行以下操作:SELECTuuid_in(md5(random()::text || now()::text)::cstring);
Blaskovicz

4
@MattDiPasquale也许在任何意义上都不比使用“更好” uuid-ossp,但是例如我正在PostgreSQL实例上工作,而我没有足够的特权来安装扩展。
Stefan Haberl 2014年

25
@JosephLennox:clock_timestamp()在这两种情况下都是更好的选择。与now()或不同,CURRENT_TIMESTAMP它是易失的,并返回实际的当前时间。SELECT uuid_in(md5(random()::text || clock_timestamp()::text)::cstring);另外,在现代Postgres中,您可以简单地进行以下操作:SELECT md5(random()::text || clock_timestamp()::text)::uuid-不需要更多魔术。用例:stackoverflow.com/a/8335376/939860
Erwin Brandstetter

17
不。如果这样做确实奏效的话。一个UUID有一种格式,它不仅是随机的十六进制字符,而且第三个组的第一个数字是实例的uuid版本(通常是4天)。如果您的应用程序检查该数字以查看其处理的uuid版本,并进行相应的操作,则它将在您的代码中失败。
TuncayGöncüoğlu2016年

7
@TuncayGöncüoğlu:生成有效的v4 UUID非常简单(尽管字符串覆盖方法浪费了2位随机性):select overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing '8' from 17)::uuid;
Karsten

75

Craig Ringer答案是正确的。这是Postgres 9.1及更高版本的更多信息……

可以使用分机吗?

如果已为Postgres安装(您的集群使用Postgres术语)构建了扩展名,则只能安装该扩展名。例如,我发现uuid-ossp扩展包含在EnterpriseDB.com 提供的Mac OS X安装程序的一部分中。几十个扩展中的任何一个都可用。

要查看uuid-ossp扩展在Postgres集群中是否可用,请运行以下SQL查询pg_available_extensions系统目录:

SELECT * FROM pg_available_extensions;

安装扩展

要安装 UUID相关的扩展,请使用此SQL中所示的CREATE EXTENSION命令:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

请注意:尽管有相反的说明,但我发现仍需要在扩展名周围使用QUOTATION MARK字符。

SQL标准委员会或Postgres团队为此命令选择了一个奇怪的名称。在我看来,他们应该选择“安装扩展”或“使用扩展”之类的东西。

验证安装

您可以通过运行以下SQL来查询扩展名,以确认该扩展程序已成功安装在所需的数据库中 pg_extension系统目录:

SELECT * FROM pg_extension;

UUID作为默认值

有关更多信息,请参见问题: Postgres中 UUID的默认值”列

旧方法

上述用途的信息,新的扩展功能添加到Postgres的9.1。在以前的版本中,我们必须在.sql文件中查找并运行脚本。添加了扩展功能,以简化安装,为扩展创建者交易了更多的工作,而减少了扩展用户/用户的工作。查看我的博客文章以获取更多讨论。

UUID的类型

顺便说一句,Question中的代码调用了function uuid_generate_v4()。这将生成一种称为版本4的类型,其中几乎所有128位都是随机生成的。尽管这对于限制在较小的行集上的有限使用是很好的,但是如果您想消除冲突的可能性,请使用UUID的另一个“版本”。

例如,原始版本1将主机的MAC地址与当前日期时间和任意数字结合在一起,发生冲突的机会几乎为零。

有关更多讨论,请参见对相关问题的回答


1
CREATE EXTENSION IF NOT EXISTS ...如果您不确定并且不想检查(例如在脚本中),也可以使用
Uwe Allner

2
第4版UUID几乎适用于任何大小的数据集,不仅是“对较小的行集的限制使用”。在大约85年的时间里,您必须每秒生成10亿个UUID(或大约4500万兆字节的数据,比当今最大的数据库大数千倍),甚至有50%的冲突机会。除非您是国家安全局(NSA),否则第4版适用于任何目的。另一方面,版本1遭受MAC地址被顺序分配(并且经常被欺骗或不可用)的事实,这就是为什么引入更高版本的原因之一。
爵士

1
@BasilBourque v1的问题不是正确实现时发生冲突的可能性,而是错误实现时的可能性。正如Wikipedia所说:“版本1和2 UUID的唯一性……还取决于网卡制造商是否为其卡正确分配了唯一的MAC地址,这与其他制造过程一样容易出错。” 同样,在某些容器化或虚拟化环境中,底层硬件的真实MAC地址也不可用。如果许多容器具有相同的MAC但具有自己的clockseq计数器,则它们的v1 UUID可能会冲突。
爵士

1
但是,v1中的@BasilBourque弱点并不是我评论的重点。您最初的答案暗示v4不适合大型数据集,因为发生碰撞的可能性比v1高。尽管很难计算v1的碰撞概率,但它具有误导性,而且可能是错误的,因为它非常依赖于实现。
爵士

1
@BasilBourque例如,node-uuid项目计算出它们的clockseq计数器与4.6e18中的1相同的概率(这样两个进程将生成相同的v1 UUID序列)。是的,这是微小的,但是比v4中立即碰撞的机会(5.3e36中为1)的可能性更大。显然,生成v4 UUID的时间越长,发生冲突的可能性就越大,这对v1而言并非如此,但是您必须生成15.2亿个v4 UUID,才能使冲突的可能性超过节点的v1实现的可能性。大多数人每张桌子没有15.2亿条记录。
爵士

61

pgcrypto 延期

从Postgres 9.4开始,该pgcrypto模块包含该gen_random_uuid()功能。此函数生成基于随机数的UUID版本4类型之一

获取contrib模块(如果尚不可用)。

sudo apt-get install postgresql-contrib-9.4

使用pgcrypto模块。

CREATE EXTENSION "pgcrypto";

gen_random_uuid()功能现在应该可用;

用法示例。

INSERT INTO items VALUES( gen_random_uuid(), 54.321, 31, 'desc 1', 31.94 ) ;


引用Postgres文档中的uuid-ossp模块。

注意:如果只需要随机生成的(版本4)UUID,请考虑使用pgcrypto模块中的gen_random_uuid()函数。


3
是的,但也请参阅blog.starkandwayne.com/2015/05/23/…他们在其中警告碎片,并建议使用uuid-ossp。
Malik A. Rumi

3
实际上,请参阅postgresql.org/message-id/…,其中揭露了Postgres中的uuid碎片问题
Bob Kocisko,

但是Postgres的确已经聚集在最新版本的索引,使得上述评论链接定论和不正确后,我们又回到起点1
迈克尔Goldshteyn

1
@MichaelGoldshteyn:没有,Postgres并没有已经聚集索引(如Postgres的12)
a_horse_with_no_name

3
ALTER TABLE table_name ALTER COLUMN id SET DEFAULT uuid_in((md5((random())::text))::cstring);

阅读@ZuzEL的答案后,我将上面的代码用作列ID的默认值,并且工作正常。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.