Postgresql 列默认函数无法创建唯一值
我有一张表是这样声明的:Postgresql 列默认函数无法创建唯一值,postgresql,stored-procedures,insert,unique,default,Postgresql,Stored Procedures,Insert,Unique,Default,我有一张表是这样声明的: CREATE TABLE my_table ( ... guid uuid UNIQUE DEFAULT create_guid('my_table') .... ); 我有一个计算唯一guid的函数 CREATE FUNCTION create_guid(in_table text) RETURNS uuid AS $$ DECLARE v_guid uuid; v_rows int; BEGIN v_guid :
CREATE TABLE my_table (
...
guid uuid UNIQUE DEFAULT create_guid('my_table')
....
);
我有一个计算唯一guid的函数
CREATE FUNCTION create_guid(in_table text)
RETURNS uuid AS $$
DECLARE
v_guid uuid;
v_rows int;
BEGIN
v_guid := md5(current_timestamp::text||random()::text);
EXECUTE 'SELECT 1 FROM ' || quote_ident(in_table) ||' WHERE guid=' || quote_literal(v_guid);
GET DIAGNOSTICS v_rows = ROW_COUNT;
WHILE v_rows > 0 LOOP -- can't use FOUND with EXECUTE
v_guid := md5(current_timestamp::text||random()::text||v_guid::text);
EXECUTE 'SELECT 1 FROM ' || quote_ident(in_table) ||' WHERE guid=' || quote_literal(v_guid);
GET DIAGNOSTICS v_rows = ROW_COUNT;
END LOOP;
RETURN v_guid;
END;
$$ LANGUAGE PLPGSQL VOLATILE;
我从未在我的生产环境中遇到过插入失败,但在我的测试环境中,我可以相当可靠地获得与以下类似的错误:
ERROR: duplicate key value violates unique constraint 'my_table_guid_key'
DETAIL: Key (guid)=(fed050ad-61c4-d548-3008-2de01301c2fc) already exists.
我意识到当前的时间戳可以是一个相同的值,我想,
random()
也可以,但这不太可能,也不是。即使它们是相同的,while循环不会防止重复吗
当然,我在插入时使用默认值。这怎么会发生?怎么解决呢
我有一个计算唯一guid的函数
这就是你的问题,你已经重新发明了UUID算法生成变体,这是一个有缺陷的变体。相反,只是:
CREATE EXTENSION "uuid-ossp";
SELECT uuid_generate_v4();
。。。产生如下输出:
uuid_generate_v4
--------------------------------------
d3e3a21c-877d-4731-a119-09b25015cb7a
(1 row)
v4 UUID不会发生冲突,即使生日悖论在起作用。包括时间戳实际上增加了冲突的机会,而不是减少冲突
当您使用它时,使用uuid
数据类型存储uuid,它更快、更紧凑。或者至少将它们作为大端值存储在bytea
格式中。除了一个填充的、格式化的文本表示之外,任何东西都将是缓慢和浪费的
即使它们是相同的,while循环不会防止重复吗 不,因为它是一种变体,两个并发事务可以各自插入相同的值,但都看不到另一个的值
我对函数进行了清理,使其更具可读性,并且除了非常弱的uuid生成方案之外,没有发现任何明显的逻辑错误,并且它在并发性面前无法工作
CREATE FUNCTION create_guid(in_table text)
RETURNS uuid AS $$
DECLARE
v_guid uuid;
v_matched boolean = 1;
BEGIN
WHILE v_matched
LOOP
v_guid := md5(current_timestamp::text||random()::text);
EXECUTE format('SELECT 1 FROM %I WHERE guid = %L', in_table, v_guid)
INTO v_matched;
END LOOP;
RETURN v_guid;
END;
$$ LANGUAGE PLPGSQL VOLATILE;
它被声明为volatile,它使用两个volatile函数,并执行一个复查循环。如果在目标表上持有独占锁,那么它看起来是正常的。(如果您没有持有独占锁,那么如果存在其他并发插入器,它仍可能失败并出现重复密钥错误)
问题可能出在测试线束或此处可见范围之外的其他部件中
我有一个计算唯一guid的函数
这就是你的问题,你已经重新发明了UUID算法生成变体,这是一个有缺陷的变体。相反,只是:
CREATE EXTENSION "uuid-ossp";
SELECT uuid_generate_v4();
。。。产生如下输出:
uuid_generate_v4
--------------------------------------
d3e3a21c-877d-4731-a119-09b25015cb7a
(1 row)
v4 UUID不会发生冲突,即使生日悖论在起作用。包括时间戳实际上增加了冲突的机会,而不是减少冲突
当您使用它时,使用uuid
数据类型存储uuid,它更快、更紧凑。或者至少将它们作为大端值存储在bytea
格式中。除了一个填充的、格式化的文本表示之外,任何东西都将是缓慢和浪费的
即使它们是相同的,while循环不会防止重复吗 不,因为它是一种变体,两个并发事务可以各自插入相同的值,但都看不到另一个的值
我对函数进行了清理,使其更具可读性,并且除了非常弱的uuid生成方案之外,没有发现任何明显的逻辑错误,并且它在并发性面前无法工作
CREATE FUNCTION create_guid(in_table text)
RETURNS uuid AS $$
DECLARE
v_guid uuid;
v_matched boolean = 1;
BEGIN
WHILE v_matched
LOOP
v_guid := md5(current_timestamp::text||random()::text);
EXECUTE format('SELECT 1 FROM %I WHERE guid = %L', in_table, v_guid)
INTO v_matched;
END LOOP;
RETURN v_guid;
END;
$$ LANGUAGE PLPGSQL VOLATILE;
它被声明为volatile,它使用两个volatile函数,并执行一个复查循环。如果在目标表上持有独占锁,那么它看起来是正常的。(如果您没有持有独占锁,那么如果存在其他并发插入器,它仍可能失败并出现重复密钥错误)
问题可能出在测试线束或此处可见范围之外的其他部件中
我有一个计算唯一guid的函数
这就是你的问题,你已经重新发明了UUID算法生成变体,这是一个有缺陷的变体。相反,只是:
CREATE EXTENSION "uuid-ossp";
SELECT uuid_generate_v4();
。。。产生如下输出:
uuid_generate_v4
--------------------------------------
d3e3a21c-877d-4731-a119-09b25015cb7a
(1 row)
v4 UUID不会发生冲突,即使生日悖论在起作用。包括时间戳实际上增加了冲突的机会,而不是减少冲突
当您使用它时,使用uuid
数据类型存储uuid,它更快、更紧凑。或者至少将它们作为大端值存储在bytea
格式中。除了一个填充的、格式化的文本表示之外,任何东西都将是缓慢和浪费的
即使它们是相同的,while循环不会防止重复吗 不,因为它是一种变体,两个并发事务可以各自插入相同的值,但都看不到另一个的值
我对函数进行了清理,使其更具可读性,并且除了非常弱的uuid生成方案之外,没有发现任何明显的逻辑错误,并且它在并发性面前无法工作
CREATE FUNCTION create_guid(in_table text)
RETURNS uuid AS $$
DECLARE
v_guid uuid;
v_matched boolean = 1;
BEGIN
WHILE v_matched
LOOP
v_guid := md5(current_timestamp::text||random()::text);
EXECUTE format('SELECT 1 FROM %I WHERE guid = %L', in_table, v_guid)
INTO v_matched;
END LOOP;
RETURN v_guid;
END;
$$ LANGUAGE PLPGSQL VOLATILE;
它被声明为volatile,它使用两个volatile函数,并执行一个复查循环。如果在目标表上持有独占锁,那么它看起来是正常的。(如果您没有持有独占锁,那么如果存在其他并发插入器,它仍可能失败并出现重复密钥错误)
问题可能出在测试线束或此处可见范围之外的其他部件中
我有一个计算唯一guid的函数
这就是你的问题,你已经重新发明了UUID算法生成变体,这是一个有缺陷的变体。相反,只是:
CREATE EXTENSION "uuid-ossp";
SELECT uuid_generate_v4();
。。。产生如下输出:
uuid_generate_v4
--------------------------------------
d3e3a21c-877d-4731-a119-09b25015cb7a
(1 row)
v4 UUID不会发生冲突,即使生日悖论在起作用。包括时间戳实际上增加了冲突的机会,而不是减少冲突
当您使用它时,使用uuid
数据类型存储uuid,它更快、更紧凑。或者至少将它们作为大端值存储在bytea
格式中。除了一个填充的、格式化的文本表示之外,任何东西都将是缓慢和浪费的
即使它们是相同的,while循环不会防止重复吗 不,因为它是w的变种