楼主: fromeast

利用rowid快速在线更新海量数据

[复制链接]
论坛徽章:
27
会员2006贡献徽章
日期:2006-04-17 13:46:34奥运会纪念徽章:自行车
日期:2008-09-04 16:35:57数据库板块每日发贴之星
日期:2008-09-24 01:03:37生肖徽章2007版:鼠
日期:2008-11-14 12:38:47生肖徽章2007版:马
日期:2008-11-24 08:53:01生肖徽章2007版:羊
日期:2008-12-05 09:36:23生肖徽章2007版:龙
日期:2008-12-08 09:33:53八级虎吧徽章
日期:2008-12-08 16:10:58数据库板块每日发贴之星
日期:2008-12-09 01:01:05生肖徽章2007版:龙
日期:2009-03-16 17:39:22
31#
发表于 2008-9-8 10:36 | 只看该作者
LZ 避重就轻

使用道具 举报

回复
论坛徽章:
0
32#
发表于 2008-9-8 10:39 | 只看该作者

回复 #1 fromeast 的帖子

ding

使用道具 举报

回复
论坛徽章:
19
授权会员
日期:2007-08-25 20:02:41会员2007贡献徽章
日期:2007-09-26 18:42:10BLOG每日发帖之星
日期:2008-11-13 01:01:05
33#
发表于 2008-9-8 10:40 | 只看该作者
如果是full scan,多块读读情况下,楼主的情况确实会减少大量io。

使用道具 举报

回复
论坛徽章:
8
会员2007贡献徽章
日期:2007-09-26 18:42:10ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44生肖徽章2007版:鸡
日期:2008-01-02 17:35:53生肖徽章2007版:猴
日期:2008-01-02 17:35:53生肖徽章2007版:鼠
日期:2008-01-02 17:35:532008新春纪念徽章
日期:2008-02-13 12:43:032009新春纪念徽章
日期:2009-01-04 14:52:28ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
34#
发表于 2008-9-8 14:46 | 只看该作者
原帖由 fromeast 于 2008-9-8 10:22 发表


按照ROWID的结构,ROWID的顺序即是数据块的顺序,而CURSOR返回的记录的顺序即是更新的顺序,所以更新就会按数据块的物理顺序依次处理,即更新完一个数据块里的所有行,再更新下一个数据块的数据。这样一来,对于每个数据块,就只有第一行会产生物理读,其他的行,因为数据块已经在内存里了,就只都是逻辑读了。

按数据块的顺序更新可能还有另外一个好处,就是磁盘的顺序读写成本更小,因为磁头减少了磁头的寻道动作。对于单个磁盘肯定是这样,但对于做了条带的RAID是不是也有这个好处,就不清楚了。但有一点是肯定的,就是好的存储设备会根据顺序访问的规律做预读,即监测到顺序访问时,会提前把后续的数据块读入存储的缓存。

CURSOR上的HINT只对CURSOR里的SELECT其作用。从SQL TRACE文件看到的大量的db file sequential read事件是UPDATE语句等待的,不是SELECT语句等待的。



楼主分析的十分正确,拿进buffer cache的data block里面的行都更新完了,在更新下一个data block里面的行。
跟你修改cache的参数应该没有关系。

使用道具 举报

回复
论坛徽章:
4
生肖徽章2007版:鼠
日期:2008-01-02 17:35:53数据库板块每日发贴之星
日期:2008-03-19 01:04:392009日食纪念
日期:2009-07-22 09:30:002010新春纪念徽章
日期:2010-03-01 11:20:51
35#
发表于 2008-9-8 15:05 | 只看该作者
LZ的思路很好,学习了

使用道具 举报

回复
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
36#
发表于 2008-9-8 16:08 | 只看该作者
加一个for all, 效果会更好
declare
maxrows number default 1000;
row_id_table dbms_sql.Urowid_Table;
currcount_table dbms_sql.number_Table;
  cursor cur_t2 is
    select /*+ use_hash(T1,T2) parallel(T1,16) parallel_index(IX_T1_id2,16) */
       T2.id2, T2.curr_count, T1.rowid row_id
    from T1, T2
    where T1.id2=T2.id2
    order by T1.rowid;
  v_counter number;
begin
  v_counter := 0;
open cur_t2;
LOOP
EXIT WHEN cur_t2%NOTFOUND;
FETCH cur_t2 bulk collect into row_id_table,currcount_table limit maxrows;
forall i in 1 .. row_id_table.count
    update T1 set curr_count=currcount_table(i)
       where rowid= row_id_table(i);
      commit;
  end loop;
end;
/
参考:
http://space.itpub.net/1249/viewspace-64339

[ 本帖最后由 rollingpig 于 2008-9-8 16:11 编辑 ]

使用道具 举报

回复
论坛徽章:
0
37#
发表于 2008-9-8 16:17 | 只看该作者
支持原创~

使用道具 举报

回复
论坛徽章:
10
ITPUB元老
日期:2005-02-28 12:57:002010广州亚运会纪念徽章:保龄球
日期:2011-01-30 11:57:03祖国60周年纪念徽章
日期:2009-10-09 08:28:00参与2009年中国云计算大会纪念
日期:2009-06-05 10:02:28ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452009新春纪念徽章
日期:2009-01-04 14:52:28生肖徽章2007版:鼠
日期:2008-01-02 17:35:53会员2006贡献徽章
日期:2006-04-17 13:46:34授权会员
日期:2005-10-30 17:05:33ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41
38#
 楼主| 发表于 2008-9-8 22:24 | 只看该作者
原帖由 rollingpig 于 2008-9-8 16:08 发表
加一个for all, 效果会更好
declare
maxrows number default 1000;
row_id_table dbms_sql.Urowid_Table;
currcount_table dbms_sql.number_Table;
  cursor cur_t2 is
    select /*+ use_hash(T1,T2) parallel(T1,16) parallel_index(IX_T1_id2,16) */
       T2.id2, T2.curr_count, T1.rowid row_id
    from T1, T2
    where T1.id2=T2.id2
    order by T1.rowid;
  v_counter number;
begin
  v_counter := 0;
open cur_t2;
LOOP
EXIT WHEN cur_t2%NOTFOUND;
FETCH cur_t2 bulk collect into row_id_table,currcount_table limit maxrows;
forall i in 1 .. row_id_table.count
    update T1 set curr_count=currcount_table(i)
       where rowid= row_id_table(i);
      commit;
  end loop;
end;
/
参考:
http://space.itpub.net/1249/viewspace-64339


谢谢!我想应该会很有效。以前用BULK COLLECT的时候,经常莫名其妙地遇到ORA-21779错误,一直没有解决,那时是9.2.0.4。不知道9.2.0.8会不会遇到这个问题。

使用道具 举报

回复
论坛徽章:
5
祖国60周年纪念徽章
日期:2009-10-09 08:28:002011新春纪念徽章
日期:2011-02-18 11:42:472012新春纪念徽章
日期:2012-01-04 11:54:262014年新春福章
日期:2014-02-18 16:43:09马上有钱
日期:2014-02-18 16:43:09
39#
发表于 2008-9-8 23:08 | 只看该作者
BULK COLLECT 不错

使用道具 举报

回复
论坛徽章:
10
授权会员
日期:2007-07-18 11:34:32ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44生肖徽章2007版:鸡
日期:2008-12-02 12:45:45生肖徽章2007版:龙
日期:2008-12-07 18:27:322009新春纪念徽章
日期:2009-01-04 14:52:28生肖徽章2007版:猪
日期:2009-02-18 12:56:472009日食纪念
日期:2009-07-22 09:30:00
40#
发表于 2008-9-8 23:29 | 只看该作者
应该跟如下的写法差不多, 同时建议不要 1000 commit 一次, 可以考虑 10000 或者 30000 左右来一次,
太频繁也是浪费时间.

CURSOR c1 IS
    SELECT object_name,object_id,status
    FROM up
    ORDER BY object_name
    FOR UPDATE OF status;

BEGIN

FOR acct IN c1 LOOP   -- process each row one at a time   
  IF acct.status='INVALID' THEN
       UPDATE up SET status='TEST'
       WHERE current of c1;
  END IF;
END LOOP;

COMMIT;
END;

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表