在Oracle中如何跳过被别人锁住的记录?

    Oracle的AQ可用于消息处理, 可有一个或几个消息产生者将不同的消息插入到AQ表中, 然后由多个进程来获取并处理这些消息, 虽然这儿的解释很简单, 但要实现一个可靠具有事务功能的消息处理系统还是件不容易的事情. 在这儿我要讲的是当有多个消息处理进程时, Oracle是如何让他们能最快地并行地处理的?

    这个问题可以简化为, 在一个表中有很多的记录(消息), 然后有很多进程来将这个表中的记录取出来, 进行处理后, 并在这个表中删除已经处理过的记录, 如果只有一两个这样的进程时, 可能什么事情也看不出来, 但是当有很多同样的进程来并行地处理这些记录时, 就会遇到数据库中常会遇到的Enqueue等待.

    按照一般的处理方法可能会使用如下的代码:

declare
   cursor msg is select ... from message_table
       where rownum < n and .....;
begin
   open msg;
   loop
      fetch msg into ....;
      process_message;
      delete message_table where pk=msg.pk;
      exit when msg%notfound;
   end loop;
   close msg;
exception
   when others then
        rollback;
end;
/

    当有很多进程并行运行这段代码时, 就有可能会出现很严重的Enqueue Wait, 在Oracle AQ的Dequeue过程中,使用了Skip Locked这样的关键字, 以跳过别其他进程锁住的记录, 更改后的代码如下:

declare
   cursor msg is select ... from message_table
       where rownum < n and ..... for update skip locked;
begin
   open msg;
   loop
      fetch msg into ....;
      process_message;
      delete message_table where pk=msg.pk;
      exit when msg%notfound;
   end loop;
   close msg;
exception
   when others then
        rollback;
end;
/

    我是在研究AQ时顺便用SQL_TRACE去跟踪了一把才发现的, 一转眼已经是两年多以前的事了.

留言 (3)

很有用啊。要多推广~

不知道这一次写清楚了没有?

This sounds like a classic undocumented SELECT FOR UPDATE SKIP LOCKED command.

用着放心吗? 以后不支持了咋办...

发表留言:

« Previous | Main | Next »

英语900句 | English 900

  • She has a particular interest in painting.
  • 她特别爱好绘画.
  • I often take my mind off my work by reading an interesting novel.
  • 通常我通过阅读小说使我的注意力从工作上转移过来.
  • He plays violin just for enjoyment.
  • 他拉小提琴只是为了自娱自乐.
  • Photography is an expensive hobby.
  • 摄影是门花费很多的爱好.
  • What's your favorite sport?
  • 你最喜欢什么活动?