oracle:更新时选择前 10 行
我有一个 ITEM
表,其中一列为 CREATED_DATE
。在集群环境中,许多服务副本将从该表中选取项目并进行处理。每个服务应该从 ITEM 表中选择最旧的 10 个项目。
我可以在存储过程中使用它来选择前 10 行:
select * from (
select item_id, row_number() over (order by CREATED_DATE) rownumber
FROM item )
where rownumber < 11
由于许多服务应该使用它,所以我使用 select ... for update
将行更新为“处理”。但下面的 FOR UPDATE
语句对于上述 select 语句失败,并出现错误“ORA-02014:无法从具有 DISTINCT、GROUP BY 等的视图中选择 FOR UPDATE”。
OPEN items_cursor FOR
**select Statement**
FOR UPDATE;
请帮我提供解决方案。
I have an ITEM
table with one of the column as CREATED_DATE
. In a clustered enviroment, many copies of services will pick items from this table and process it. Each service should pick the oldest 10 items from the ITEM table.
I am able to select top 10 rows using this in a Stored Procedure:
select * from (
select item_id, row_number() over (order by CREATED_DATE) rownumber
FROM item )
where rownumber < 11
Since many service should use this, I am using select ... for update
to update the rows as "processing". But the below FOR UPDATE
statement, fails for the above select statement with error "ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc."
OPEN items_cursor FOR
**select Statement**
FOR UPDATE;
Please help me with a solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这适合您的情况吗?
Does this work for your situation?
DCookie 的答案没有解决多会话处理(它只是用于 UPDATE 语法修复)。如果您不操作行号范围,则每个服务实例都会选择更新相同的行。如果您在两个会话中执行 that_for_update_select,则第二个会话将等待第一个会话完成事务。并行处理将是一种幻想。
我会考虑将高效的批量处理与
更新跳过锁定
方法结合起来。我的回答如下:可能的长交易可能是一个缺点。考虑使用 Oracle Streams 高级队列 (DBMS_AQ) 作为此解决方案的替代方案。
DCookie's answer doesn't solve multisession processing (it's just FOR UPDATE syntax fix). If you won't manipulate rownumber range, every instance of service if going to select for update the same rows. If you execute that_for_update_select in two sessions, the second one is going to wait until first finishes the transaction. Parallel processing will be an illusion.
I would consider efficient bulk processing together with
for update skip locked
approach. My answer below:Possible long transaction could be a disadvantage. Consider using Oracle Streams Advanced Queuing (DBMS_AQ) as an alternative to this solution.
您可以使用
跳过锁定
和计数器来实现此目的,只要您不一定需要每个会话都获取连续的行。例如:如果您从两个会话同时运行此命令,它们将获得不同的对象(尽管您可能需要在
found
块内启用对dbms_lock.sleep
的调用,以使它足够慢以至于可见)。根据 这篇文章,当使用
skip锁定
选定的行在被提取之前不会被锁定,并且在游标打开后被另一个会话锁定的任何行都将被忽略。You can use
skip locked
and a counter to achieve this, as long as you don't necessarily need each session to get contiguous rows. For example:If you run this simultaneously from two sessions they'll get different objects (though you may need to enable the call to
dbms_lock.sleep
inside thefound
block to make it slow enough to be visible).According to this post, when using
skip locked
the selected rows aren't locked until they're fetched, and any rows locked by another session after the cursor is opened are just ignored.每个人都建议使用带有循环的 PL/SQL 代码,但也有一个简单的 SQL 解决方案:
Everyone is suggesting PL/SQL code with loops, but there's also a plain SQL solution: