存档

2010年1月 的存档

对于一个高并发的OLTP系统,SQL执行计划的改变往往意味着灾难。很多因素都可能导致执行计划发生不可预期的改变,比如表结构,索引,统计信息等变化,甚至我们发生过一个小小的grant操作,导致执行计划失效,重新解析后生成了一个不正确的执行计,让整个系统Crash的案例。最近,我们对一个分区表增加分区后,导致了执行计划发生改变,故障再次重演。
如何控制SQL的执行计划就成为了一个课题,之前我曾经写过一篇关于调整SQL执行计划的文章,但是内容比较粗略。因为Oracle提供了很多手段去控制执行计划,所以我打算为每个版本都整理一个最佳实践。
我们设想一个场景,一个SQL本来应该走nested loop join,但是由于某种原因,突然变成了hash join,调整统计信息无效,数据库load不断升高,只留给你很少的时间,怎么办?最直接有效的方法是在SQL上加hints,但是需要程序发布,或者程序根本无法修改。
9i为我们提供了Stored outline,大家都非常熟悉,但是对于上面的场景,还是需要点技巧。方法是:生成两个stored outline,一条是错误的,一条是正确的(加hints),两个然后将其执行计划交换。看下面的步骤:
1.创建两个public stroed outline,第一个是目前运行的,第二个是加了hints.
create or replace outline OUTLN1 on select e.ename from emp e, dept d where e.deptno=d.deptno;
create or replace outline OUTLN2 on select /*+ use_nl(e d)*/ e.ename from emp e, dept d
where e.deptno=d.deptno;
拷贝成为private outline
create or replace private outline PRIV_OUTLN1 from OUTLN1;
create or replace private outline PRIV_OUTLN2 from OUTLN2;
交换两个stored outline的执行计划
update ol$ [...]

1 28th, 2010 | Filed under 大话技术

朋友遇到一个问题,当建立一个包含varchar2(4000)的索引时,直接创建没有问题,但是如果加上online子句,则报错:
ORA-00604: error occurred at recursive SQL level 1
ORA-01450: maximum key length (3215) exceeded
这里实际上包含了两个问题:
1.索引的key到底可以有多大?因为索引的key是不可以跨越block的,所以最直接的决定因素是block size,Oracle的文档给出了一个计算公式:
DB_BLOCK_SIZE: Maximum Index Key Length:
============== =========================

2K (2048) [...]

1 26th, 2010 | Filed under 大话技术
标签:

不知不觉,来杭州已经五年了。翻看了以前的blog,里面记录了我这五年的心路历程。
2004年12月27日,《新的征程》
“上帝关上了一扇门,总会打开一扇窗。所以,别担心。”
2005年3月19日,《杭州两个月》
“说说工作吧,刚来的时候,我感觉到很大的压力,毕竟我和周围的同事相比,水平还差很多。但是发现 BITI,RUDOLF,GRASSBELL,FENNG,WANGHAI,CHENYP,CHENJP,都对我非常的好。虽然我的水平很差,但是有什么 问题,都耐心的给我讲,让我很感动,尤其是BITI,能在这样的环境中工作,我感觉很满足。”
2005年7月28日,《一致读的实现》
第一次有点技术含量的文章,现在看起来依然很优雅,短短几句话,就将一致读的原理解释的清清楚楚:)
2007年3月4日,《细节决定成败》
做DBA的第一次犯错。
2007年5月19日,《IBM P570+DMX3》
第一次跟着老大做项目,学到了很多东西,现在仍然受益匪浅。
2008年1月1日,《我的2007》
2007年,终于实现了梦寐以求的目标,正式当上了DBA。比当DBA更重要的是,当上了别人的爹。
2008年3月6日,《我有压力 未解决》
“工作是挣扎滴,前途是渺茫滴
压力是很大滴,解决是没有滴
抱怨是没用滴,开心是重要滴
未来是光明滴,什么都会有滴”
五年时光,很快就过去了,虽然没成就什么大事业,不过也算是小有成就,感谢家人和朋友的支持,真是挺不容易的。
一直一来,我的梦想是成为象BITI那样的技术大牛,也一直为了这个目标而努力,但是今年情况可能发生了变化,我从技术岗位调整为管理岗位,这本不是我的意愿和初衷,但是我也欣然接受。未来我将把更多的心思放在团队身上,努力让每个人都能从团队发展的过程中受益。
我不会放弃自己的梦想,大师说过:只有自己坚信,才会有人同路。我坚信现在的工作是有价值的,我坚信所有的痛都是暂时的,我坚信付出总有一天会有回报的,我坚信……
–EOF–

1 26th, 2010 | Filed under 一地鸡毛

一个数据库的同步系统,可以分为三部分:抓取变化,传输和加载。抓取数据库变化,最通常的做法是用trigger记录到表中,或者通过解析Oracle redo log中的信息来抓取。传输是将数据库变化记录到特定格式的文件中,通过网络推送到目标数据库上。加载则是指在目标数据库上应用这些变化(SQL),这里主要是讨论并行加载的实现思路。
我们通过trigger或者redo log得到了数据库变化的事务流,这个流是按照事务的提交顺序排列的,最简单的方法是在目标端按照这个事务流顺序执行,就是串行执行。这么做的最大优点是可以完全保证事务的一致性,但是缺点是性能很差。如果采用并行加载,就需要考虑事务相关性的问题,所谓事务相关性,是指两个或多个事务更新了同一条或者多条记录,他们之前存在时间上的依赖关系。如果将具有相关性的事务分在不同的并发进程上加载,可能出现后面的事务被前面的事务覆盖掉的情况,最终导致事务混乱。
我们设计一个并行加载的方法,目标是尽可能快的加载数据,保证不会产生数据混乱的情况,但是不能保证事务完全的一致性。这句话如何理解,假设两个事务不相关,A事务只更新A表,B事务只更新B表,如果在源库A事务先于B事务完成,那么在目标库可以让B事务先于A事务执行,或者两个事务并行执行,虽然事务的顺序与主库并不一致,但是数据是正确的,因为两个事务不相关。
我们如果按照事务去分拆并行的话,设计比较困难,因为涉及到事务的相关性分析。换个思路,我们可以按照数据来拆分并行,也就是把同一个事务拆分到不同的并发进程中,保证表的同一行记录的所有更改都由一个并发进程处理。按照这个思路,我们首先把事务流加载到一个队列或者一个内存结构中去,为了理解方便,我们可以认为放在了一张内存表中,这个表有以下几个字段,事务ID,表名,PK,SQL,时间序列号。首先按照不同的表分组,将不同的表的操作分配给不同的进程处理,每个并发进程按照事务提交的时间顺序来执行。比如:A事务更新A,B,C三张表的A1,B1,C1记录,B事务更新A,B,C三张表的A2,B2,C2记录,C事务更新A,B,C三张表的A3,B3,C3记录。三个事务的提交顺序是A,B,C,这时我们可以启动三个并发进程,分别处理A表,B表和C表的操作,顺序是A1,A2,A3……这样就实现了最简单的并行,虽然目标库的事务与主库并不一致,但是数据是完整和正确的。
按照表来做并行可能还不足够,如果某张表的更改量特别大,这时我们还可以进一步分组,针对同一张表中的操作再按照行(PK)分组,保证同一行的不同操作分配到同一个的并发进程处理。这里有一些小的技巧,在很多情况下,我们可以只关注某行的最后一个操作就可以了,比如某行的最后一个操作是delete,那么我们只需要执行delete,之前的操作就可以直接丢弃,如果是insert,那么我们可以在目标库先执行delete,然后再insert,针对我们自己的系统,有些表的update是全部字段更新,所以我们直接采用了merge操作,相当于对同一行的不同操作,我们做了合并处理。因为系统是自己开发的,所以可以针对我们自己的特性定制了功能。
有人说这个思路有些土,Oracle logical standby,Goldengate或者Shareplex这些商业软件是怎么做的?我之前也写过一篇文章探讨这个问题:Oracle Logical Standby SQL Apply Architecture,这些商业软件都声称自己分析了事务的相关性,可以做到并行加载,但是同样也存在事务不一致的问题,但是分析事务的相关性肯定要按照表或者行来分析,所以思路应该不会差太远,无非是他们包装得更好。
PS:这个方法并不是我想出来的,是团队的智慧。现在看起来思路挺简单,但是其实困扰了我们很长的时间。当然如果你有更好的方法,欢迎和我讨论。
–EOF–

1 7th, 2010 | Filed under 大话技术
标签:

打算每年都给自己和家人拍几张照片,以此来纪念每一年的变化。本来是想照几张严肃点的,但是室内的效果实在不怎么样。元旦天气不错,带家人去了趟玉皇山,就作为《我的2009》的定妆照吧。

在玉皇山顶,因为可以看到西湖,又可以看到钱塘江,所以叫“一统江湖”,希望2010年我也可以达成自己的目标,在自己的江湖世界里,一统江湖!
–EOF–

1 5th, 2010 | Filed under 一地鸡毛, 边走边拍

又到了一年一度总结的时候了,其实挺害怕总结这事的,因为每次回头看过去的一年,总是感觉有些失落。
2009年最大的事就是搬进了自己的家,不管装修的过程多么曲折,但是结局是圆满的。同事们戏称我是“品质”男,殊不知追求品质是要付出代价的。
工作上逐步脱离了一线环境,带了一个小团队,负责了一个项目,为了这个团队和项目,付出了很多心血。谋事在人,成事在天,不管结果怎样,我问心无愧。
这一年我一直在寻找自己的方向,如何在远离一线环境后,继续提高技术水平。“多读,多写,多教”是我摸索出来的方法:从问题出发,在找寻答案的过程中,不断思考,最终提炼为简单的道理。“教是最好的学”,所以我会尽可能的讲给别人,或者与别人讨论,从中发现漏洞并完善。
这一年,同事们都说我越来越能“忽悠”了,我觉得这句话是在夸我,因为我大部分忽悠的是技术问题,尤其是当我弄明白了某件事情之后,就有强烈的欲望与别人分享。最近尤其喜欢和别人切磋技术,很多东西不辨不明。遇到志同道合的人讨论技术,很快乐,很鸡冻。
Blog还在写,大道至简是我的风格,期望用最简单的语言把技术问题讲明白,不会有任何操作手册类的文章,虽然篇幅不多,但是每一篇都经过了思考和提炼。Twitter每天都在写,大部分是工作和生活中的感悟,有时候也会写点小抱怨,这个东西,真得挺好。
2009年另外一个技术上的提升是,熟练掌握了翻墙的技能,并在各种场合教别人如何翻墙,就算我们不关心政治,翻墙去寻找一些技术上的资料,也是一个技术人员必备的技能。
我这个岁数的老男人,已经进入了一个舒适区,每天上班下班回家抱孩子,不希望有什么改变。明年要打破这个舒适区,给自己更高的期望,寻求突破。
2009年就这样了,虽然没啥大成就,但是也没虚度光阴。路在前方,还得继续走,看看2010年的几个事:
家庭和谐是最高目标,为老爸当好IT支持,为老婆当好司机,为儿子当好爸爸,为老妈当好儿子。
工作上继续为那个小团队和那个项目努力,兄弟们跟着我,我总得走在前面吧。
多读,多写,多教,技术上提高,突破自我,影响团队,努力向大牛们靠拢。
旅游什么就不指望了,等儿子长大了,财务自由了,全部补回来。
苦练内功,我为自己定了一个目标,三年内要……不成功就转行娱乐圈了。
–EOF–
“他强任他强 清风拂山岗 他横任他横 明月照大江”—给所有为了生活苦苦奋斗的70后老男人。

1 1st, 2010 | Filed under 一地鸡毛
标签: