现在遇到这样的一个问题,就是一个表中比如有500w条数据,有3个进程在访问这个表,读取规则是 每个进程读取这个表的前100条数据(按时间字段来排序即可) 然后删除掉该进程读取到的100条数据,但是必须保证每个进程读取到的都不能有相同数据,(注:该表没有主键),请问各位大牛,大哥该怎么编写语句来实现如上功能啊。oracle

解决方案 »

  1.   

    随便什么字段都行。 比如“RandomKey”,“Re”,"time" 这3个字段吧,主要想用的就是这个RanomdKey 数据,这个字段数据不会重复的。
      

  2.   


    当然有,不过这样设计效率不高,只要选取数据时后面加个for update nowait就行了。
    select RanomdKey from (
    select RanomdKey,rownum rn from your_table order by time
    ) where rn<=100 for update nowait;加了nowait后如果有多个进程选择同样的数据会报错,应用catch exception后做相应的处理,比如弹出警告信息,不加nowait则不会报错,不过进程会等待,直到其他进程操作完毕并释放锁。不过我个人觉得每个进程按时间段分开提取数据效率会更高,不会发生不必要的阻塞,另外如果CPU资源足够的话可以考虑使用parallel hint来代替多进程。
      

  3.   

    怎么样给表加锁啊,而且还必须删除掉select出来的
      

  4.   

    其实也简单,你往该表加一个字段process_sid。每个进程处理前,先将该字段为空的前100条更新为某个特定值,立刻提交。不同的进程保证唯一,比如sid。
    然后对有该值的进行处理。
    update t set process_sid = userenv('sid') where process_status is null and rownum <=100;
    commit;
      

  5.   

    至于你要再借其他的条件,往where后面加就好了
      

  6.   


    呵呵,前后字段名不一样写错了
    update t set process_sid = userenv('sid') where process_status is null and rownum <=100;
    commit;
      

  7.   


    你看是不是这个意思哈:
    我在这个表中添加一个字段用以标识作用,加了标识以后就不会存在冲突了。
    然后锁定这个表lock table test in exclusive mode; //给表加排他锁
    update test  set sessionid='1' and rownum<=100 and sessionid=0 //给表的某个字段添加标识
    commit
    select * from test  where sessionid = '1'  //选出来唯一的这100个标识
    delete * from test  where sessionid = '1' //删除唯一的这100个标识注: 这里的sessionid = '1' 中的1 每个进程都不一样。但是,在某个进程执行lock table test in exclusive mode; 其他进程也执行这句会怎么样?会报错还是阻塞,其实我想要的就是让其他进程阻塞,直到第一个commit释放表锁,这样的话该怎么处理?
      

  8.   

    不能lock table啊,那样会粗大四滴……
    问题是你何必要加锁呢,每次你只管加sessionid,然后只处理你的sessionid的,互相之间自然不会影响。。
      

  9.   

    那啥……之前还是写错了的
    给process_sid 为空的打上自己的标志,下个进程自然就不会理会这些数据了。update t set process_sid = userenv('sid') where process_sid is null and rownum <=100;
    commit;
      

  10.   

    该标志为null的才加,你加过后变成了自己的了,他的语句就看不到了。
      

  11.   

    感觉首先的把逻辑搞清楚,这个问题类似于操作系统中的“同步-互斥”,如果3个进程的业务逻辑是相同的话。3个进程和一个进程处理数据的速度没有什么大的区别,因为A进程处理数据的话,b,c都在等待。没有发挥作用。资源是共享的话,且不允许同时操作的话,没有必要用多个进程啊。除非他们的业务逻辑不同。
      

  12.   

    在时间字段上加索引,然后用select * from ... for update,是不是更简单易于理解
      

  13.   

    可以用rowid,用系统函数得到数据块号,和块内号
    用这两个分散到不同的session
    分散方式可以考虑取模建议只是用数据块号
    dbms_rowid.rowid_block_number(rowid)
    保证多个session不会访问同一个数据块,
    这样开几十个并发都可以了