Oracle(PL/SQL):更新是否返回并发?
我使用带有计数器的表来确保子元素上的唯一id 我知道使用序列通常更好,但我不能使用它,因为我有很多计数器(客户可以创建几个桶,每个桶都需要有自己的计数器,它们必须从1开始(这是一个要求,我的客户需要“人类可读”的键) 我正在创建具有prikey(bucket\u id,num=counter)的记录(我们称之为items) 我需要保证bucket_id/num组合是唯一的(因此使用序列作为prikey不会解决我的问题) 在pl/sql中不会创建行,所以我需要声明这个数字(顺便说一句:有间隙并不违反要求) 我的解决办法是:Oracle(PL/SQL):更新是否返回并发?,oracle,concurrency,plsql,Oracle,Concurrency,Plsql,我使用带有计数器的表来确保子元素上的唯一id 我知道使用序列通常更好,但我不能使用它,因为我有很多计数器(客户可以创建几个桶,每个桶都需要有自己的计数器,它们必须从1开始(这是一个要求,我的客户需要“人类可读”的键) 我正在创建具有prikey(bucket\u id,num=counter)的记录(我们称之为items) 我需要保证bucket_id/num组合是唯一的(因此使用序列作为prikey不会解决我的问题) 在pl/sql中不会创建行,所以我需要声明这个数字(顺便说一句:有间隙并不违
UPDATE bucket
SET counter = counter + 1
WHERE id = param_id
RETURNING counter INTO num_forprikey;
PL/SQL返回var_num_forprikey,以便创建项记录
问题:
即使用户同时请求bucket中的新项目,我也会始终获得unique num\u forprikey吗?我会想出如何使序列工作。这是唯一的保证,尽管可以编写一个例外子句 序列的好处(它们可以动态创建,可以指定nocache并保证顺序) 我会一直得到唯一的num\u for prikey吗 即使用户同时请求 桶里有新东西吗 是的,至少在一定程度上是这样。第一个发出更新的用户将获得该行的锁。因此,在用户numero uno提交(或回滚)之前,其他用户无法成功发出相同的语句。因此,唯一性得到了保证
显然,问题在于并发性。您对行的访问是序列化的,因此两个用户无法同时获得新的PRIKEY。这不一定是问题。这取决于您创建新项目的用户数量以及他们创建新项目的频率。在同一会话中,一个用户剥下数字不会注意到任何事情.我似乎回忆起许多年前在安格尔数据库上工作时遇到的这个问题。在那些日子里,没有序列,所以当时安格尔的顶尖人物花了很多精力来寻找这个问题的最佳扩展解决方案。我很幸运地与他们一起工作,所以即使我的思维是比他们中的任何一个都小得可怜,proxmity=残余影响,我保留了一些东西。这是其中之一。让我看看我是否还记得
1) for each counter you need row in a work table.
2) each time you need a number
a) lock the row
b) update it
c) get its new value (you use returning for this which I avoid like the plague)
d) commit the update to release your lock on the row
提交的原因是为了尝试获得某种可伸缩性。总是有限制的,但在任何时间段内都不会对获取的数字进行序列化
在oracle世界中,我们将通过使用定义为自治_事务的函数来改善这种情况,以获取下一个数字。如果您仔细考虑,此解决方案要求允许空白,您认为这是可以的。通过独立于主事务提交数字更新,您可以获得可扩展性,但您引入了g阿平
您必须接受这样一个事实,即在这种情况下,您的可伸缩性将急剧下降。这至少是由于两个原因:
1) update/select/commit序列尽最大努力减少键行被锁定的时间,但它仍然不是零。在重载情况下,您将序列化并最终受到限制
2) 你对每一个关键点都很投入。提交是一项昂贵的操作,需要数据库执行许多内存和文件管理操作。这也会限制你
最后,您可能会看到并发事务负载下降了三个或更多个数量级,因为您没有使用序列。这是基于我过去的经验
但如果您的客户需要它,您可以做什么正确的
祝你好运。我没有测试代码的语法错误,我把它留给你
create or replace function get_next_key (key_name_p in varchar2) return number is
pragma autonomous_transaction;
kev_v number;
begin
update key_table set key = key + 1 where key_name = key_name_p;
select key_name into key_name_v from key_name where key_name = key_name_p;
commit;
return (key_v);
end;
/
show errors
您仍然可以使用序列,只需使用row_number()分析函数来取悦您的用户。我在这里更详细地描述了它: 问候,,
Rob。每个桶都应该有自己的计数器,所以我不能使用序列!动态创建序列不是一个选项,因为将会有很多桶…我想是的,但是我找不到关于这个的文档!!APC说的是实话。但是,如果会话没有提交更新,这是让应用程序停止的一种好方法。