??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品不卡视频,亚洲国产成人九九综合,亚洲人成网站在线观看播放青青http://m.tkk7.com/AstroQi/category/37307.htmlI'm Astro Qi. If call me, please send email to closoastroqi@126.comzh-cnTue, 22 Dec 2009 22:51:45 GMTTue, 22 Dec 2009 22:51:45 GMT60Oracle分析函数http://m.tkk7.com/AstroQi/archive/2009/01/20/252022.htmlAstro.QiAstro.QiTue, 20 Jan 2009 03:33:00 GMThttp://m.tkk7.com/AstroQi/archive/2009/01/20/252022.htmlhttp://m.tkk7.com/AstroQi/comments/252022.htmlhttp://m.tkk7.com/AstroQi/archive/2009/01/20/252022.html#Feedback0http://m.tkk7.com/AstroQi/comments/commentRss/252022.htmlhttp://m.tkk7.com/AstroQi/services/trackbacks/252022.html阅读全文

Astro.Qi 2009-01-20 11:33 发表评论
]]>
ORACLE的烦引和U束详解http://m.tkk7.com/AstroQi/archive/2009/01/20/252020.htmlAstro.QiAstro.QiTue, 20 Jan 2009 03:23:00 GMThttp://m.tkk7.com/AstroQi/archive/2009/01/20/252020.htmlhttp://m.tkk7.com/AstroQi/comments/252020.htmlhttp://m.tkk7.com/AstroQi/archive/2009/01/20/252020.html#Feedback0http://m.tkk7.com/AstroQi/comments/commentRss/252020.htmlhttp://m.tkk7.com/AstroQi/services/trackbacks/252020.htmlOracle的约?br />
* 如果某个U束只作用于单独的字D,卛_以在字段U定义约束,也可以在表定义U束Q但如果某个U束作用于多个字D,
必须在表U定义约?br /> * 在定义约束时可以通过CONSTRAINT关键字ؓU束命名Q如果没有指定,ORACLE自动ؓU束建立默认的名U?br />
定义primary keyU束(单个字段Q?br /> create table employees (empno number(5) primary key,...)

指定U束?br /> create table employees (empno number(5) constraint emp_pk primary key,...)

定义primary keyU束(多个字段,在表U定义约束)
create table employees
(empno number(5),
deptno number(3) not null,
constraint emp_pk primary key(empno,deptno)
using index tablespace indx
storage (initial 64K
next 64K
)
)

ORACLE自动会ؓhPRIMARY KEYU束的字D?ȝ字段)建立一个唯一索引和一个NOT NULLU束,定义PRIMARY KEYU束时可以ؓ它的索引
指定存储位置和存储参?br />
alter table employees add primary key (empno)
alter table employees add constraint emp_pk primary key (empno)
alter table employees add constraint emp_pk primary key (empno,deptno)

not nullU束(只能在字D定义NOT NULLU束,在同一个表中可以定义多个NOT NULLU束)
alter table employees modify deptno not null/null

uniqueU束
create table employees
( empno number(5),
ename varchar2(15),
phone varchar2(15),
email varchar2(30) unique,
deptno number(3) not null,
constraint emp_ename_phone_uk unique (ename,phone)
)

alter table employees
add constraint emp_uk unique(ename,phone)
using index tablespace indx

定义了UNIQUEU束的字D中不能包含重复|可以Z个或多个字段定义UNIQUEU束,因此QUNIQUE卛_以在字段U也可以在表U定义,
在UNIQUEDU束的字D上可以包含I?

foreign keyU束

* 定义为FOREIGN KEYU束的字D中只能包含相应的其它表中的引用码字D늚值或者NULL?br /> * 可以Z个或者多个字D늚l合定义FOREIGN KEYU束
* 定义了FOREIGN KEYU束的外部码字段和相应的引用码字D可以存在于同一个表中,q种情况UCؓ"自引?
* 对同一个字D可以同时定义FOREIGN KEYU束和NOT NULLU束

定义了FOREIGN KEYU束的字D늧?外部码字D?,被FORGIEN KEYU束引用的字D늧?引用码字D?,引用码必Lȝ或唯一?包含外部码的表称为子表,
包含引用码的表称为父?

A:
create table employees
(.....,
deptno number(3) NOT NULL,
constraint emp_deptno_fk foreign key (deptno)
references dept (deptno)
)

如果子表中的外部码与主表中的引用码具有相同的名称Q可以写?
B:
create table employees
(.....,
deptno number(3) NOT NULL
constraint emp_deptno_fk references dept
)

注意Q?br /> 上面的例?B)中not null后面没有加逗号,因ؓq一句的contraint是跟在那一列deptno后面的,属于列定义,所以都无需指明列。而A例中的是表定义,需要指明那一列,所以要加逗号Q不能在列后面定义,q可以写成:

create table employees
(empno char(4),
deptno char(2) not null constraint emp_deptno_fk references dept,
ename varchar2(10)
)
表定义contraint的只能写在最后,再看两个例子Q?br />
create table employees
(empno number(5),
ename varchar2(10),
deptno char(2) not null constraint emp_deptno_fk references dept,
constraint emp_pk primary key(empno,ename)
)

create table employees
( empno number(5),
ename varchar2(15),
phone varchar2(15),
email varchar2(30) unique,
deptno number(3) not null,
constraint emp_pk primary key(empno,ename),
constraint emp_phone_uk unique (phone)
)

dforeign keyU束(多字D/表Q?br /> alter table employees
add constraint emp_jobs_fk foreign key (job,deptno)
references jobs (jobid,deptno)
on delete cascade

更改foreign keyU束定义的引用行?delete cascade/delete set null/delete no action),默认是delete on action

引用行ؓ(当主表中一条记录被删除Ӟ定如何处理字表中的外部码字D)Q?br /> delete cascade : 删除子表中所有的相关记录
delete set null : 所有相兌录的外部码字DD|ؓNULL
delete no action: 不做M操作

先删除原来的外键U束,再添加约?br /> ALTER TABLE employees DROP CONSTRAINT emp_deptno_fk;
ALTER TABLE employees ADD CONSTRAINT emp_deptno_fk FOREIGN KEY(deptno) REFERENCES dept(deptno) ON DELETE CASCADE;

checkU束
* 在CHECKU束的表辑ּ中必d用到表中的一个或多个字段Qƈ且表辑ּ的计结果必L一个布?br /> * 可以在表U或字段U定?br /> * 对同一个字D可以定义多个CHECKU束Q同时也可以定义NOT NULLU束

create table employees
(sal number(7,2)
constraint emp_sal_ck1 check (sal > 0)
)

alter table employees
add constraint emp_sal_ck2 check (sal < 20000)

删除U束

alter table dept drop unique (dname,loc) --指定U束的定义内?br /> alter table dept drop constraint dept_dname_loc_uk --指定U束?br />
删除U束Ӟ默认同时删除约束所对应的烦引,如果要保留烦引,用KEEP INDEX关键?br /> alter table employees drop primary key keep index

如果要删除的U束正在被其它约束引用,通过ALTER TABLE..DROP语句中指定CASCADE关键字能够同时删除引用它的约?br />
利用下面的语句在删除DEPT表中的PRIMARY KEYU束Ӟ同时删除其它表中引用这个约束的FOREIGN KEYU束:
alter table dept drop primary key cascade

用/Ȁzȝ?用/Ȁzȝ束会引v删除和重建烦引的操作)
alter table employees disable/enable unique email
alter table employees disable/enable constraint emp_ename_pk
alter tabel employees modify constraint emp_pk disable/enable
alter tabel employees modify constraint emp_ename_phone_uk disable/enable  

如果有FOREIGN KEYU束正在引用UNIQUE或PRIMARY KEYU束Q则无法用q些UNIQUE或PRIMARY KEYU束Q?br /> q时可以先禁用FOREIGN KEYU束Q然后再用UNIQUE或PRIMARY KEYU束Q或者可以在ALTER TABLE...DISABLE
语句中指定CASCADE关键字,q样在用UNIQUE或PRIMARY KEYU束的同时禁用那些引用它们的FOREIGN KEYU束Q如Q?br /> alter table employees disable primary key cascade

U束数据字典
all_constraints/dba_constraints/user_constraints U束的基本信息,包括U束的名UͼcdQ状?br /> (U束cdQC(CHECKU束),P(ȝU束),R(外部码约?,U(唯一码约?)
all_cons_columns/dba/user U束对应的字D信?/p>
Oracle的烦?br />     索引和对应的表应该位于不同的表空间中,oracle能够q行d位于不同盘上的数据Q可以避免生I/O冲突
B树烦引:在B树的叶节点中存储索引字段的gROWID?br /> 唯一索引和不唯一索引都只是针对B树烦引而言.
Oracle最多允许包?2个字D늚复合索引

索引创徏{略
1.导入数据后再创徏索引
2.不需要ؓ很小的表创徏索引
3.对于取D围很的字段Q比如性别字段Q应当徏立位囄?br /> 4.限制表中的烦引的数目
5.为烦引设|合适的PCTFREE?br /> 6.存储索引的表I间最好单独设?br />
创徏不唯一索引
create index emp_ename on employees(ename)
tablespace users
storage(......)
pctfree 0;

创徏唯一索引
create unique index emp_email on employees(email)
tablespace users;

创徏位图索引
create bitmap index emp_sex on employees(sex)
tablespace users;

创徏反序索引
create unique index order_reinx on orders(order_num,order_date)
tablespace users
reverse;

创徏函数索引(函数索引卛_以是普通的B树烦引,也可以是位图索引)
create index emp_substr_empno
on employees(substr(empno,1,2))
tablespace users;

修改索引存储参数(与表cMQINITIAL和MINEXTENTS参数在烦引徏立以后不能再改变)
alter index emp_ename storage(pctincrease 50);

׃定义U束时由oracle自动建立的烦引通常是不知道名称的,对这cȝ引的修改l常是利用alter table ..using index语句q行?而不是alter index语句

利用下面的语句将employees表中primary keyU束对应的烦引的PCTFREE参数修改?
alter table employees enable primary key using index pctfree 5;

清理索引片
1.合ƈ索引(只是单的B树叶l点中的存储片合ƈ在一Pq不会改变烦引的物理l织l构Q?br /> alter index emp_pk coalesce;

2.重徏索引(不仅能够消除存储片,q可以改变烦引的全部存储参数讄Qƈ且可以将索引Ud到其它的表空间中,重徏索引
实际上就是再指定的表I间中重新徏立一个新的烦?然后删除原来的烦?
alter index emp_pk rebuild;

删除索引
drop index emp_ename;

如果索引中包含损坏的数据块,或者包含过多的存储片Q需要首先删除这个烦引,然后再重建它.
如果索引是在创徏U束时由oracle自动产生?可以通过用U束或删除约束的Ҏ来删除对应的索引.
在删除一个表?oracle会自动删除所有与该表相关的烦?

索引数据字典
all_indexes/dba_indexes/user_indexes 索引的基本信?br /> all_ind_columns/dba_ind_columns/user_ind_columns 索引对应的字D信?br />


Astro.Qi 2009-01-20 11:23 发表评论
]]>
Oracle热备?/title><link>http://m.tkk7.com/AstroQi/archive/2009/01/20/252019.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Tue, 20 Jan 2009 03:21:00 GMT</pubDate><guid>http://m.tkk7.com/AstroQi/archive/2009/01/20/252019.html</guid><wfw:comment>http://m.tkk7.com/AstroQi/comments/252019.html</wfw:comment><comments>http://m.tkk7.com/AstroQi/archive/2009/01/20/252019.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/AstroQi/comments/commentRss/252019.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/AstroQi/services/trackbacks/252019.html</trackback:ping><description><![CDATA[<a href="javascript:;" onclick="javascript:tagshow(event, 'Oracle');" target="_self"><u><strong>Oracle</strong></u></a> 版本Q?i?0g<br /> 1?nbsp;       q行?a href="javascript:;" onclick="javascript:tagshow(event, '%B1%B8%B7%DD');" target="_self"><u><strong>备䆾</strong></u></a>的要求?<br /> 热备份是一U?a href="javascript:;" onclick="javascript:tagshow(event, '%CA%FD%BE%DD%BF%E2');" target="_self"><u><strong>数据?/strong></u></a>的处于打开时的物理备䆾Q因为数据库在不断发生改变,因此备䆾的文件必然是不一致的Q这p求数据库必须处于归日志模式?br /> <br /> 2?nbsp;       热备份的一般流E?<br /> ?nbsp;       查看数据库是否处于归日志模式,若不是将数据库置为归日志模式?br /> Rem check the archived mode<br /> Archive log list;<br /> Rem if not archivelog mode issue the following statements<br /> Shutdown immediate;<br /> Startup mount;<br /> Alter database archivelog;<br /> Alter database open;<br /> ?nbsp;       查看当前的归档日志情늡认已归<br /> Archive log list;<br /> ?nbsp;       表I间|ؓ热备份模?以users 表空间ؓ?<br /> Alter tablespace users begin backup;<br /> ?nbsp;       物理拯数据文g<br /> Rem for <a href="javascript:;" onclick="javascript:tagshow(event, 'windows');" target="_self"><u><strong>windows</strong></u></a><br /> Sql> host copy c:\oracle\ora92\user01.dbf d:\oracle\hotbackup;<br /> Rem for linux/unix<br /> Sql>host cp  /oracle/ora92/user01.dbf  /oracle/oracle92/user01.dbf<br /> ?nbsp;       l束表空间的热备份模?br /> Alter tablespace users end backup;<br /> ?nbsp;       相同Ҏ备䆾其他表空?read only ?offline 表空间不能置为热备䆾模式)<br /> ?nbsp;       备䆾二进制的控制文g<br /> Alter system backup control file to ‘d:\oracle\hotback\controlfile.ctl’ reuse;<br /> Rem reuse 表示当文件存在时覆盖?br /> <br /> 3?nbsp;       开始热备䆾时发生什么?<br /> ?nbsp;       执行一个checkpoint 所有dirty data 写入文gQ保证热备䆾开始前文g是一致的Q?br /> ?nbsp;       锁定文g头的checkpoint scnQ但是数据库的改变可以正常进行?br /> ?nbsp;       在alert文g中增加一条记?br /> <br /> 4?nbsp;       热备份时相关SCN 如何处理Q?br /> ? 开始进行热备䆾Ӟ数据文g头的checkpoint scn 和控制文件中该文件的scn lock住,但是数据文g的dml操作可以正常q行Q也意味着block 的scn 是正常增加的Q数据文件ƈ没有锁定。ؓ什么要Lock 文g的checkpoint scnQ实际上对应了恢复时的rbaQ?主要是ؓ了标C行恢复操作时需要的redo logQ? q样可以保证数据文件内所有的块都能得到恢复,因ؓ在进行数据文件拷贝时无法保证数据文g头是最先拷贝完成的。如果先拯的是数据文g的其他部分然后才 L贝的数据文g_q时候很有可能数据文件头的checkpoint scn已经改变了而恢复时应用redo log的范围是由数据文件头的rba军_的?br /> 当热备䆾l束Ӟ在备份结束的时候,oracle会把数据文g头和control文g中关于这个数据文件的QIEQ号更新为数据库的SQN受?br /> <br /> 5?nbsp;       Z么热备䆾时生的redo大量增加Q?br /> ? 先说下造成大量增加的直接原因吧Q因为数据文件在q行热备份时Q该数据文g中的处于data buffer中数据块在首ơ发生改变时oracle会把整块的block  image 写入redo log。注意该处首ơ改变是对处于buffer中的数据块而言的,而不是文件中的blockQ例如对于datafile1 的第20个块Q?br /> File ---data buffer 从文件中ddb buffer<br /> Data buffer-----change  产生block image to redo log<br /> Data buffer ------change  不生blcok image 而是正常的change vector<br /> Data buffer ----file  从db buffer 写入文g<br /> File ----data buffer  又从文g中读入db buffer<br /> Data buffer-----change   再次产生block image to redo log<br /> Data buffer ------change  不生blcok image 而是正常的change vector<br /> <br /> ? 所以要存储block image主要是ؓ了处理由于oracle 的block size 和操作系l的block size 不一致而可能造成的split blockQ指数据块不一_。热备䆾中我们用的是操作pȝ命ocopy or cp 来拷贝数据文Ӟq些命o操作的块大小都是由操作系l决定的而操作系l块和数据库块大一般不相同。如果当数据库块在改变的同时在进行拷贝,很有可能? 成拷贝的数据块不一_其中一部䆾改变前拷贝的一部分是改变后拯的)。Oracle 在恢复时split block 当成是currption blockQ这时就需要redo log中的block image覆盖现有块来q行恢复<br /> <br /> 6?nbsp;       Rman备䆾Z么不用锁文g头scnQ不增加redoQ?br /> 锁文件头scn只是Z可以正确标示恢复时的rbaQ热备䆾方式中这个rba需要从备䆾的数据文件本w获取,而rman方式其写入了controlfile 或catalog,所以不用锁文g头?br /> Rman 在备份时需要用两个缓冲区一个输入缓冲区Q一个输出缓冲区。数据块在从输入~冲Z送到输出~冲区时会进行一致性校验,不一致时会重新读取直C致。所以rman备䆾的文件数据块U都是一致的Q不需要block image?br /> Q两个缓冲区默认在pga中如果设|了io_slave 会在larger pool 中。)<br /> <br /> 7?nbsp;       热备份过E中发生crash如何恢复Q?以users 表空?user01.dbf  file# 9 Z)<br /> 如果在热备䆾的过E中发生crash在startup时会报:ORA-01113文g9需要恢复?br /> 有两U方式可以解册个问题:<br /> 1?nbsp;       alter tablespace users end backup;<br /> 2?nbsp;       recover datafile 9;<br /> 因ؓq时报的错误和restore了一个文件后需要恢复时一LQ所以在定是没有end backup时用W一U方法否则应该用W二U?br /> <br /> 8?nbsp;       热备份恢复相兌图?<br /> v$recover_file:需要恢复的文g<br /> v$recover_logQ需要应用的归档日志<br /> x$kcvfh Q可以查看各个文件的rba<br /> <br /> 9?nbsp;       热备份相兌本?Q备份脚本)<br /> set linesize 800 verify off pagesize 0 feedback off<br /> define dir='c:\oracle\admin\hotback\2008-10-26'<br /> define log='c:\oracle\admin\hotback\2008-10-26\bklog.txt'<br /> define fil='c:\oracle\admin\sqlsheet\bkdatafile.sql'<br /> set serveroutput on<br /> spool &fil<br /> prompt spool &log<br /> prompt archive log list;;<br /> prompt alter system switch logfile;;<br /> declare<br /> cursor c_tbs is select tablespace_name tbsname from dba_tablespaces where status='ONLINE';<br /> cursor c_datafile(tn varchar2) is select file_name from dba_data_files where tablespace_name=tn;<br /> begin<br /> for row_tbs in c_tbs loop<br /> dbms_output.put_line('alter tablespace '||row_tbs.tbsname||' begin backup;');<br /> for row_file in c_datafile(row_tbs.tbsname) loop<br />    dbms_output.put_line('host copy '||row_file.file_name||' &dir;');<br /> end loop;<br /> dbms_output.put_line('alter tablespace '||row_tbs.tbsname||' end backup;');<br /> end loop;<br /> end;<br /> /<br /> prompt alter system switch logfile;;<br /> prompt alter database backup controlfile to '&dir\controfile.ctl';;<br /> prompt archive log list;;<br /> prompt spool off;;<br /> spool off;<br /> @&fil<br /> <br /> 10?nbsp;       当归日志文件不在默认位|时如何处理Q?br /> 我们在进行热备䆾恢复旉要的归日志文g很有可能从默认的归位置U走了,在恢复时要一个一个指定归档日志位|很ȝQ可以用以下方式解冟?br /> ?nbsp;       Recover from ‘new_dir’ datafile 9;  -- 该方法我试了下不行,好像已被oracle废除<br /> ?nbsp;       Set logsource  ‘new_dir’   --注意没有“=”<br /> Recover datafile 9;<br /> <br /> <img src ="http://m.tkk7.com/AstroQi/aggbug/252019.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/AstroQi/" target="_blank">Astro.Qi</a> 2009-01-20 11:21 <a href="http://m.tkk7.com/AstroQi/archive/2009/01/20/252019.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>满L几个条g的查询方?/title><link>http://m.tkk7.com/AstroQi/archive/2009/01/19/251887.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Mon, 19 Jan 2009 05:47:00 GMT</pubDate><guid>http://m.tkk7.com/AstroQi/archive/2009/01/19/251887.html</guid><wfw:comment>http://m.tkk7.com/AstroQi/comments/251887.html</wfw:comment><comments>http://m.tkk7.com/AstroQi/archive/2009/01/19/251887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/AstroQi/comments/commentRss/251887.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/AstroQi/services/trackbacks/251887.html</trackback:ping><description><![CDATA[<p><span style="color: rgb(0,0,255)">满5个条件中L四个条g都可以的实现Ҏ?/span></p> <p><span style="color: rgb(0,0,255)">一、用case when实现</span></p> <p><span style="color: rgb(0,0,255)">select</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(128,128,128)">*</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">from</span><span style="color: rgb(0,0,0)"> 表名 <br /> </span><span style="color: rgb(0,0,255)">where</span><span style="color: rgb(0,0,0)"> (</span><span style="color: rgb(255,0,255)">case</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">when</span><span style="color: rgb(0,0,0)"> 条g1 </span><span style="color: rgb(0,0,255)">then</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">1</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">0</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">end </span><span style="color: rgb(128,128,128)">+</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(255,0,255)">case</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">when</span><span style="color: rgb(0,0,0)"> 条g2 </span><span style="color: rgb(0,0,255)">then</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">1</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">0</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">end </span><span style="color: rgb(128,128,128)">+</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(255,0,255)">case</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">when</span><span style="color: rgb(0,0,0)"> 条g3 </span><span style="color: rgb(0,0,255)">then</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">1</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">0</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">end </span><span style="color: rgb(128,128,128)">+</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(255,0,255)">case</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">when</span><span style="color: rgb(0,0,0)"> 条g4 </span><span style="color: rgb(0,0,255)">then</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">1</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">0</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">end </span><span style="color: rgb(128,128,128)">+</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(255,0,255)">case</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">when</span><span style="color: rgb(0,0,0)"> 条g5 </span><span style="color: rgb(0,0,255)">then</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">1</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">else</span><span style="color: rgb(0,0,0)"> </span><span style="font-weight: bold; color: rgb(128,0,0)">0</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">end</span><span style="color: rgb(0,0,0)">) </span><span style="color: rgb(128,128,128)">>= 10;</span></p> <img src ="http://m.tkk7.com/AstroQi/aggbug/251887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/AstroQi/" target="_blank">Astro.Qi</a> 2009-01-19 13:47 <a href="http://m.tkk7.com/AstroQi/archive/2009/01/19/251887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle的执行计?/title><link>http://m.tkk7.com/AstroQi/archive/2009/01/19/251884.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Mon, 19 Jan 2009 05:40:00 GMT</pubDate><guid>http://m.tkk7.com/AstroQi/archive/2009/01/19/251884.html</guid><wfw:comment>http://m.tkk7.com/AstroQi/comments/251884.html</wfw:comment><comments>http://m.tkk7.com/AstroQi/archive/2009/01/19/251884.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/AstroQi/comments/commentRss/251884.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/AstroQi/services/trackbacks/251884.html</trackback:ping><description><![CDATA[     摘要: 一、什么是执行计划 An explain plan is a representation of the access path that is taken when a query is executed within Oracle. 二、如何访问数?At the physical level Oracle reads blocks of data. The smallest ...  <a href='http://m.tkk7.com/AstroQi/archive/2009/01/19/251884.html'>阅读全文</a><img src ="http://m.tkk7.com/AstroQi/aggbug/251884.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/AstroQi/" target="_blank">Astro.Qi</a> 2009-01-19 13:40 <a href="http://m.tkk7.com/AstroQi/archive/2009/01/19/251884.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle树结构的专用Ҏhttp://m.tkk7.com/AstroQi/archive/2009/01/19/251881.htmlAstro.QiAstro.QiMon, 19 Jan 2009 05:26:00 GMThttp://m.tkk7.com/AstroQi/archive/2009/01/19/251881.htmlhttp://m.tkk7.com/AstroQi/comments/251881.htmlhttp://m.tkk7.com/AstroQi/archive/2009/01/19/251881.html#Feedback0http://m.tkk7.com/AstroQi/comments/commentRss/251881.htmlhttp://m.tkk7.com/AstroQi/services/trackbacks/251881.html树结构和它的专用函数SYS_CONNECT_BY_PATH
单的树型l构
关于树的普通应?br /> 学习了下q个函数, 用ORGINDUSTRIES的表做了个测?
正常的树型结?br /> select lpad(' ',6*(level-1))||industry,indlevel,indid,pindid
from ORGINDUSTRIES
start with indid=1
connect by pindid=prior indid
l果昄如下
                 Indlevel     indid          pindid
          服装与服?nbsp;       1             1               0
               服装           2             2               1
                  奌        3             3               2

倒型?br /> 下面q个例子是个”倒数”—倒过来的树型l构
select lpad(' ',6*(level-1))||industry,indlevel,indid,pindid
from ORGINDUSTRIES
start with indid=20
connect by indid=prior pindid;
q是标准l果:
                             Indlevel indid    pindid
二手服装                      3        20       2
      服装                         2        2        1
            服装与服?nbsp;       1        1        0
l论
无论正树q是倒树, 关键在于connect by的条?
正树:  必须?nbsp; ‘?#8217;= prior ‘?#8217;
倒树:  必须?nbsp; ‘?#8217;= prior ‘?#8217;

树型l构的条件过?br /> 采用树型l构的话, 如果我们惛_树上的一个分支砍?  分支后面的l构都抛弃掉, q个可以实现麽?当然可以?但是不是用whereQ?where条g只能去除单一的条件?br /> 所以, q种树型的过滤条件就需要加在connect by上面?br />
试如下Q由于用真实环境比较贴近实际Q所以提前用下SYS_CONNECT_BY_PATH函数来显CZ环境

不加M条g的环境:
select areaname,sys_connect_by_path(areaname,',')
from areas bb
start with areaname='中国大陆'
connect by parentareaid=prior areaid  

l果Q?br /> 1        中国大陆,中国大陆
2        北京        ,中国大陆,北京
3        北京        ,中国大陆,北京,北京
4        东城?nbsp;       ,中国大陆,北京,东城?br /> 5        西城?nbsp;       ,中国大陆,北京,西城?br /> 22        q东        ,中国大陆,q东
23        q州        ,中国大陆,q东,q州
24        汕尾        ,中国大陆,q东,汕尾
25        潮阳        ,中国大陆,q东,潮阳
46        上v        ,中国大陆,上v
47        上v        ,中国大陆,上v,上v
48        黄?nbsp;       ,中国大陆,上v,黄?br /> 49        闸北?nbsp;       ,中国大陆,上v,闸北?br />
加了whereqo条g的SQL:
select areaname,sys_connect_by_path(areaname,',')
from areas bb
where bb.areaid>861000
start with areaname='中国大陆'
connect by parentareaid=prior areaid

l果为:
2        北京        ,中国大陆,北京
3        北京        ,中国大陆,北京,北京
4        东城?nbsp;       ,中国大陆,北京,东城?br /> 5        西城?nbsp;       ,中国大陆,北京,西城?br /> 22        q东        ,中国大陆,q东
23        q州        ,中国大陆,q东,q州
24        汕尾        ,中国大陆,q东,汕尾
25        潮阳        ,中国大陆,q东,潮阳
46        上v        ,中国大陆,上v
47        上v        ,中国大陆,上v,上v
48        黄?nbsp;       ,中国大陆,上v,黄?br /> 49        闸北?nbsp;       ,中国大陆,上v,闸北?br />
l论Q去掉了“1        中国大陆,中国大陆”数据

加了connect by的过滤条Ӟ
select areaname,sys_connect_by_path(areaname,',')
from areas bb
where bb.areaid>861000
start with areaname='中国大陆'
connect by parentareaid=prior areaid  and areaname<>'q东'

l果为:
2        北京        ,中国大陆,北京
3        北京        ,中国大陆,北京,北京
4        东城?nbsp;       ,中国大陆,北京,东城?br /> 5        西城?nbsp;       ,中国大陆,北京,西城?br /> 46        上v        ,中国大陆,上v
47        上v        ,中国大陆,上v,上v
48        黄?nbsp;       ,中国大陆,上v,黄?br /> 49        闸北?nbsp;       ,中国大陆,上v,闸北?br />
l论Q去掉了整个q东的分支,  在结果集中只有北京和上v


SYS_CONNECT_BY_PATH函数
采用SYS_CONNECT_BY_PATH函数?

select industry,sys_connect_by_path(industry,'/')
from ORGINDUSTRIES
start with indid=3
connect by indid=prior pindid;

l果?
奌               /奌
服装                    /奌/服装
服装与服?nbsp;           /奌/服装/服装与服?br />
q样的话, 可以实? 树结构的l果集的单行拼接:

我们只需要取最大的字段OK?br />
试如下Q?br />
select max(sys_connect_by_path(industry,'/'))
from ORGINDUSTRIES
start with indid=3
connect by indid=prior pindid;

l果为:
/奌/服装/服装与服?br />
复杂的树型结构――多列变单列
树型l构也分单树和多?我的U呼,实际上就是指单支和多?
对于下面的这U情况, 我们必须要构造的树就属于单支树?br /> 原始环境
环境如下Q?br /> select * from testQ?br />
l果为:
1        n1
1        n2
1        n3
1        n4
1        n5
3        t1
3        t2
3        t3
3        t4
3        t5
3        t6
2        m1

造树
脚本如下Q?br /> select no,q,
       no+row_number() over( order by no) rn,
       row_number() over(partition by no order by no) rn1
from test

l果如下Q?br /> No  Q  RN RN1
1        n1        2        1
1        n2        3        2
1        n3        4        3
1        n4        5        4
1        n5        6        5
2        m1        8        1
3        t1        10        1
3        t2        11        2
3        t3        12        3
3        t4        13        4
3        t5        14        5
3        t6        15        6

每列的目的是Q?br /> RN1列主要的目的是分l, 按照value?#8216;1’Q我们可以start with使用它?br />
RN列主要用来做connect by使用?实际上它是我们要的树?br /> W一个支Q?2Q?Q?Q?Q?
W二个支Q?8
W三个支Q?10Q?1Q?2Q?3Q?4Q?5

中间Z么要断掉Q?,9  目的是Z区别每个分支?到后面看具体的SQLQ就明白q里的说法了?br />
杀手锏
既然我们有了树, 可以用树型函数SYS_CONNECT_BY_PATH和connect by啦,来拼接我们所需要的多列倹{?br />
脚本如下Q?br /> select no,sys_connect_by_path(q,',')
from (
select no,q,
       no+row_number() over( order by no) rn,
       row_number() over(partition by no order by no) rn1
from test
)
start with rn1=1
connect by rn-1=prior rn

l果为:
1        ,n1
1        ,n1,n2
1        ,n1,n2,n3
1        ,n1,n2,n3,n4
1        ,n1,n2,n3,n4,n5
2        ,m1
3        ,t1
3        ,t1,t2
3        ,t1,t2,t3
3        ,t1,t2,t3,t4
3        ,t1,t2,t3,t4,t5
3        ,t1,t2,t3,t4,t5,t6

l极武器
最l我们要的|是单列| 其实xQ?也就是最长的一行咯?那么好办了?我们直接GROUP BY Q然后取MAX倹{?br /> 脚本如下Q?br /> select no,max(sys_connect_by_path(q,','))
from (
select no,q,
       no+row_number() over( order by no) rn,
       row_number() over(partition by no order by no) rn1
from test
)
start with rn1=1
connect by rn-1=prior rn
group by no

l果为:
1        ,n1,n2,n3,n4,n5
2        ,m1
3        ,t1,t2,t3,t4,t5,t6

如果觉得前面?#8216;Q?#8217;不好看,可以使用ltrimL?或者用substr也可以?br /> 如下Q?br /> ltrim(max(sys_connect_by_path(q,',')),',')
或?br /> substr(max(sys_connect_by_path(q,',')),2)


Astro.Qi 2009-01-19 13:26 发表评论
]]>
ORACLE SQL 索引http://m.tkk7.com/AstroQi/archive/2009/01/19/251880.htmlAstro.QiAstro.QiMon, 19 Jan 2009 05:16:00 GMThttp://m.tkk7.com/AstroQi/archive/2009/01/19/251880.htmlhttp://m.tkk7.com/AstroQi/comments/251880.htmlhttp://m.tkk7.com/AstroQi/archive/2009/01/19/251880.html#Feedback0http://m.tkk7.com/AstroQi/comments/commentRss/251880.htmlhttp://m.tkk7.com/AstroQi/services/trackbacks/251880.html
ORACLE SQL TUNING
一Q优化器模式
   ORACLE的优化器共有3U?
   a.  RULE (Z规则)   b. COST (Z成本)  c. CHOOSE (选择?
   Z使用Z成本的优化器(CBO, Cost-Based Optimizer) , 你必d期更新统计信息,以保证数据库中的对象l计信息(object statistics)的准?
   如果数据库的优化器模式设|ؓ选择?CHOOSE),那么实际的优化器模式和是否q行qanalyze命o有关. 如果table已经被analyzeq? 优化器模式将自动成ؓCBO , 反之,数据库将采用RULE形式的优化器?/div>

二.讉KTable的方?br /> ORACLE 采用两种讉K表中记录的方?
a.  全表扫描
      全表扫描是序地访问表中每条记? ORACLE采用一ơ读入多个数 据块(database block)的方式优化全表扫描?br />    
b.  索引扫描
   你可以采用基于ROWID的访问方式情?提高讉K表的效率, ROWID包含了表中记录的物理位置信息.ORACLE采用索引(INDEX)实现了数据和存放数据的物理位|?ROWID)之间的联p? 通常索引提供了快速访问ROWID的方?因此那些Z索引列的查询可以得到性能上的提高.

其中ORACLE对烦引又有两U访问模?
a)索引唯一扫描 ( INDEX UNIQUE SCAN)
大多数情况下, 优化器通过WHERE子句讉KINDEX.
例如:
表LOADING有两个烦?: 建立在LOADING列上的唯一性烦引LOADING_PK和徏立在MANAGER列上的非唯一性烦引IDX_MANAGER.
SELECT loading 
FROM LOADING
WHERE LOADING = ‘ROSE HILL’;
   在内?, 上述SQL被分成两步执行, 首先 , LOADING_PK 索引通过索引唯一扫描的方式被讉K , 获得相对应的ROWID, 通过ROWID讉K表的方式执行下一步检?
   如果被检索返回的列包括在INDEX列中,ORACLE不执行W二步的处理(通过ROWID讉K?. 因ؓ索数据保存在索引? 单单讉K索引可以完全满x询结?
   下面SQL只需要INDEX UNIQUE SCAN 操作.
       SELECT LOADING
       FROM  LOADING
WHERE LOADING = ‘ROSE HILL’;
 
  b)索引范围查询(INDEX RANGE SCAN)
     适用于两U情?
1. Z一个范围的?br /> 2. Z非唯一性烦引的?br />  ?:
      SELECT LOADING
      FROM  LOADING
WHERE LOADING LIKE ‘M%’;
 
WHERE子句条g包括一pd? ORACLE通过索引范围查询的方式查询LODGING_PK . ׃索引范围查询返回一l? 它的效率p比烦引唯一扫描
低一? 
?:
      SELECT LOADING
      FROM  LOADING
WHERE MANAGER = ‘BILL GATES’;
 q个SQL的执行分两步, IDX_MANAGER的烦引范围查?得到所有符合条件记录的ROWID) 和下一步同qROWID讉K表得到LOADING列的? ׃IDX_MANAGER是一个非唯一性的索引,数据库不能对它执行烦引唯一扫描.
 
  ׃SQLq回LOADING?而它q不存在于IDX_MANAGER索引? 所以在索引范围查询后会执行一个通过ROWID讉K表的操作.
  WHERE子句? 如果索引列所对应的值的W一个字W由通配W?WILDCARD)开? 索引不被采?
SELECT LOADING
      FROM  LOADING
WHERE MANAGER LIKE ‘QHANMAN’;
在这U情况下QORACLE用全表扫?


三.SQL调优的本质就是调整执行计划?br />  在好多情况下Qoracle自动选择的执行计划ƈ不是最优的Q这旉要我们h工去q预?什么是执行计划?)
 

对SQL调优基本步骤Q?br /> a) 捕获SQL语句
b) 产生SQL语句的执行计划;
c) 验证l计信息(SQL语句涉及到的表格是否做过分析)Q表g?l果集的记录敎ͼ索引)Q字D上面数据分布特?br /> d) 通过手工攉到的信息QŞ成自q想的执行计划?br /> e) 如果做过分析Q则重新分析相关表格或者做q囑ֈ析?br /> f) 如果没有做过分析Q则通过试不同的HintQ从而获得合适的执行计划?br /> g) 当我们正常无法调优到位时Q可以打开10053事g打开优化器的跟踪Q看看Oracle如何选择?
alter session set events='10053 trace name context forever,level 2';
 
四.如何捕获SQL语句
 捕获SQL语句的方法有如下几种Q?br />   1QSQL TRACE?0046跟踪某个模块?br />   2QPERFSTAT性能l计包,使用Ҏ见附录二?br />   3QV$SQLQV$SESSION_WAITQV$SQL_TEXT
五.如何查看执行计划
 查看SQL语句的执行计划有以下几种Q?br />  1QSet autotrace on(set autotrace traceonly exp)
 2QExplain plan for …..
  @?/rdbms/admin/utlxpls.sql
 3QV$SQL_PLAN视图
  column operation format a16
column "Query Plan" format a60
column options format a15
column object_name  format a20
column id  format 99

select id,lpad(' ',2*(level-1))||operation||' '||options||' '||object_name||' '
       ||decode(id,0,'Cost = '||position) "Query Plan"
from (select *
from v$sql_plan 
where address='&a') sql_plan
start with id = 0
connect by prior id = parent_id
/

 4Q第三方工具Q如pl/sql developer,TOAD
 
六.SQL语句主要的连接方?/p>

a) Nested-loop join
适合于小?几千条,几万条记?与大表做联接
在联接列上有索引?/p>

 分内表和外表(驱动?Q靠qfrom子句的是内表。从效率上讲Q小表应该作外表Q大表应该作内表Q即大表查询时走索引?/p>

COST= Access cost of A(驱动? + (access cost of B * number of rows from A)

成本计算ҎQ?br />  讑ְ?00行,大表100000行?/p>

 两表均有索引Q?br />  如果表在内Q大表在?驱动?的话Q则扫描ơ数为:
  100000+100000*2 (其中2表示IOơ数Q一ơ烦引,一ơ数?
 如果大表在内Q小表在?驱动?的话Q则扫描ơ数为:
  100+100*2.

 两表均无索引Q?br />  如果表在内Q大表在外的话,则扫描次CؓQ?br />   100000+100*100000
 如果大表在内Q小表在外的话,则扫描次CؓQ?br />   100+100000*100

注意Q如果一个表有烦引,一个表没有索引QORACLE会将没有索引的表作驱动表。如果两个表都有索引Q则外表作驱动表。如果两个都没烦引的话,则也是外表作驱动表?/p>

 基本的执行计划如下所C:
  NESTED LOOPS
           TABLE ACCESS (BY ROWID)  OF  our_outer_table
                   INDEX (..SCAN) OF outer_table_index(….)
           TABLE ACCESS (BY ROWID)  OF  our_inner_table
             INDEX (..SCAN) OF inner_table_index(….)

b) Hash join

适合于大表与大表Q小?几十万,几百?与大表之间的联连?br /> 联接列上不需要烦引?/p>

基本执行计划如下Q?br />  HASH JOIN
              TABLE ACCESS (….)  OF  tableA
              TABLE ACCESS (….)  OF  tableB

cost= (access cost of A * number of hash partitions of B) + access cost of B

可以看出主要成本在于A表是否可以被Cache。Hash_area_size的大将军_Hash Join的主要成本。可以看出Hash Join的成本和q回集合q没有直接的关系Q所以当q回l果集比较大的时候一般具有较好的性能?/p>

Z加快hash join的速度Q可以调大hash_area_size和pga_aggregate_targetQ默认ؓ25MQ的倹{?/p>


c) Sort Merge join

每一个Row Source在Join列上均排序?br />  然后两个排序后的Row Source合ƈ后,作一个结果集q回?br />  Sort/Merge Join仅仅对equal Join有效?/p>

基本执行计划
 MERGE (JOIN)
        SORT (JOIN)
                 TABLE ACCESS (….)  OF  tableA
        SORT (JOIN)
                 TABLE ACCESS (….)  OF  tableB

cost= access cost of A + access cost of B +(sort cost of A + sort cost of B)

可以看出Sort的成本是Merge Join的主要构成部分。这样sort_area_size的大将很大E度军_Merge Join的大。同样如果A表或者B表已l经q排序的Q那么Merge Join往往h很好的性能。其不会走烦引?/p>

没有驱动表的概念Q即时响应能力较差?/p>

 

七.一般情况下最常见?U问?/p>

1. Statement not written for indexes 25%
2. Indexes are missing or inappropriate 16%
3. Use of single-column index merge 15%
4. Misuse of nested loop, sort merge, or hash join 12%
5. Misuse of IN, EXISTS, NOT IN, NOT EXISTS, or table joins 8%
 
 不过在我们这里,最常见的问题是在第2条,W?条,W?条?/p>

1Q?nbsp;Statement not written for indexes
cM于这LQ?br /> SELECT account_name, trans_date, amount
FROM transaction
WHERE SUBSTR(account_name,1,7) = ' CAPITAL';

WHERE account_name LIKE 'CAPITAL%';

Account_date 日期

To_char(Account_date,’YYYY-MM-DD:HH24:MI:SS’)=’200508XXX’;

Account_date=to_date(‘200508….’,’yyyy-mm-dd);


2QIndexes are missing or inappropriate
 
 例如REP_C021中有q样一句:
select SUBSIDIARYID,260,'    300电话?,
    sum(decode(feetype, 1, ceil(duration / 60))) +
         sum(decode(feetype, 0, ceil(duration / 60))),
         sum(decode(feetype, 1, ceil(duration / 60))),
         sum(decode(feetype, 0, ceil(duration / 60))),0
    from cardsusage200508 a, service b
   where a.caller = b.servicecode and
         (b.property = i_property or i_property is null) and
         a.cdrtype = 102
   group by SUBSIDIARYID, 260, '    300电话?;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=RULE
   1    0   SORT (GROUP BY)
   2    1     NESTED LOOPS
   3    2       TABLE ACCESS (FULL) OF 'CARDSUSAGE200508'
   4    2       TABLE ACCESS (BY INDEX ROWID) OF 'SERVICE'
   5    4         INDEX (UNIQUE SCAN) OF 'SERVICE_CODE'
 
我们取其中的select语句q行调优。在调整之前Q原select语句需?分钟左右?/p>

12:19:20 SQL> select cdrtype,count(*) from cardsusage200508
12:20:12   2  group by cdrtype;

CDRT   COUNT(*)
---- ----------
102         637
106     1973757
107     2390097
112       46016
113          20

针对cardsuage200508表格的特性,我们在CDRTYPE字段上徏立一个位囄引CARDSUSAGE_CDRTYPE_BTIDX?br /> SQL语句加上以下HintQ?br />   select /*+  INDEX(A, CARDSUSAGE_CDRTYPE_BTIDX)*/
         SUBSIDIARYID,260,'    300电话?,
         sum(decode(feetype, 1, ceil(duration / 60))) +
         sum(decode(feetype, 0, ceil(duration / 60))),
         sum(decode(feetype, 1, ceil(duration / 60))),
         sum(decode(feetype, 0, ceil(duration / 60))),0
    from cardsusage200508  a, service b
   where a.caller = b.servicecode and
         (b.property = i_property or i_property is null) and
         a.cdrtype = 102
   group by SUBSIDIARYID, 260, '    300电话?;
 q样调整后,只需要几U钟卛_出来?/p>

3.  Use of single-column index merge
 复合索引有的时候比单列索引效率更高。根据where子句中的具体情况Q有 时可以徏立复合烦引。例如:
 select a.AccountNum,a.ChargeID,a.Total,b.ItemID,
      b.Amount,c.billingcycle
  from charge_bill a, chargedetail_bill b, Account c
 where a.AccountNum > 1 and a.AccountNum <= 1969618 and
       a.status = '0' and a.InvoiceID is null and c.paymentmethod != '7' and
       a.Total > 0 and a.AccountNum = c.AccountNum and
       a.ChargeID = b.ChargeID
 order by a.AccountNum, a.ChargeID, b.ItemID;
q样的SQL语句执行需??7U?/p>

我们做了以下优化Q?br /> 在charge_bill表格的accountnum,status,total,invoiceid列上建立一个复合烦引。这样上qSQL语句需?0U左叟?/p>

 Resume Serviceq程中有q么一句:
 SELECT NVL(SUM(A.FEE),0)  
FROM ACCOUNTBALANCE A,INVOICE B 
WHERE A.OBJECTID = B.INVOICEID  AND A.ACCOUNTNUM = :b1
AND B.BILLINGBEGINDATE < TO_DATE(:b2,'yyyymmdd');
该语句需要执行大?2000ơ。整个过E执行大概需?00分钟左右?/p>

?b1以具体的g替,q条SQL语句执行很快Q大?.1U左叟?/p>

我们做了以下优化Q?br /> 在invoiceid,billingbegindate列上创徏了一个烦引idx_invoice_hc?br /> 上qSQL语句ҎQ?br /> select /*+ use_nl(a,b) index(b,IDX_INVOICE_HC)*/  nvl(sum(a.fee),0)
from accountbalance a,invoice b
where a.objectid=b.invoiceid  and a.accountnum=m_accountnum
and b.billingbegindate

q样一来,该过E的执行旉快的时候大概在10分钟左右Q慢的时?IO异常紧张的时)大概?0分钟左右?/p>


4. Misuse of nested loop, sort merge, or hash join
 表格之间的连接方式和q接序都将极大的媄响SQL语句的性能。这U问  题在qx最常见。ORACLE在处?张或5张以上的表格的连接时候,很容 易出问题。一般情况下Q}记前面表g间的q接原则Q即可以处理此类?nbsp;题?br />  
   例如Q?br />   select b.SUBSIDIARYID,
       c.paymentmethod || ':' || nvl(subscribertype, '9999999'),
       'gsm',count(*),sum(decode(untelLOCALCHARGE,
                  0,decode(duration,0,1,
                         decode(sign(duration - 1800),
                                1, 2 + trunc((duration - 1201) / 600),
                                2)), trunc((duration + 599) / 600))),
       sum(nvl(GSMCHARGE, 0)),nvl(property, '0'),
       SUM(trunc((duration + 599) / 600))
  from  rt_untelecomusage a ,service b, account c
 where a.starttime >
       to_date(to_char(add_months(to_date('200508 ', 'YYYYMM'), -1),
                       'YYYYMM') || '20235959',
               'YYYYMMDDHH24MISS') and
       a.starttime < to_date('200508 ' || '21', 'YYYYMMdd') and
       gsmcharge > 0 and a.serviceid = b.serviceid and
       b.accountnum = c.accountnum
 group by b.SUBSIDIARYID,
          c.paymentmethod || ':' || nvl(subscribertype, '9999999'),
          'gsm',nvl(property, '0');
 该语句原先需?Q?个小时左叟?/p>

优化Q?br /> alter session set hash_area_size=300000000;

select /*+ use_hash(b,c) ordered NO_EXPAND full(a) use_hash(a)*/  b.SUBSIDIARYID,c.paymentmethod || ':' || nvl(subscribertype, '9999999'),
     'gsm',count(*), sum(decode(untelLOCALCHARGE,0,decode(duration,0, 1,
        decode(sign(duration - 1800), 1,2 + trunc((duration - 1201) / 600), 2)),
     trunc((duration + 599) / 600))),sum(nvl(GSMCHARGE, 0)),
       nvl(property, '0'),SUM(trunc((duration + 599) / 600))
  from service b, account c,untelecomusage_200508  a
 where a.starttime >
       to_date(to_char(add_months(to_date('200508', 'YYYYMM'), -1),
                       'YYYYMM') || '20235959',
               'YYYYMMDDHH24MISS') and
       a.starttime < to_date('200508' || '21', 'YYYYMMdd') and
       gsmcharge > 0 and a.serviceid = b.serviceid and
       b.accountnum = c.accountnum
 group by b.SUBSIDIARYID,c.paymentmethod || ':' || nvl(subscribertype, '9999999'),'gsm',nvl(property, '0'); 

 q样优化后,只需?0分钟左右卛_?/p>

八.案例
1Q?nbsp;循环Update操作
 
  以下q程太慢了, 半个时q?000条记录都未处理,?共有7万多条?br /> declare
    cursor c1 is
    select caller
    from zxx_sms_step where chargemonth=200504 and fee is null;
    icnt number;
begin
 icnt:=0;
 for m_c1 in c1 loop
  update zxx_sms_step a set fee=
   (select nvl(sum(pascharge),0) from ipasimport_200504 where caller=m_c1.caller and pastag in (1243,1251))
   where caller=m_c1.caller and chargemonth=200504;
  icnt:=icnt+1;
  if icnt=500 then
   exit;   
  end if;
 end loop;
end;

   q样的SQL语句Q徏议先update中的子查询生成一张中间表Q然后再update?br /> alter session set hash_area_size=400000000 ;

select /*+use_hash(a,b)*/ b.caller,nvl(sum(a.pascharge),0) from ipasimport_200504 a,zxx_sms_step b
where b.chargemonth=200504 and b.fee is null
and a.caller=b.caller and a.pastag in (1243,1251)
group by b.caller;
 q样10分钟不到可产生中间表,然后再update只需几分钟即可?/p>


2Q?nbsp;部分表格未做l计信息分析
 
 |通OApȝ自从oracle服务器从pc服务器上q到型Z后,其CPU利用率经常冲到很高。而其中每一个进E在某个瞬间占?0%左右的CPU。这些进E都是通过jdbc thin client q过来的?/p>

通过抓取其sql_textQ发C下两条SQL语句不正常?br /> 1.
 SQL>  select D.flow_inid,D.step_inco,D.deal_man,D.agen_men,D.time_set,D.peri_man,
  2   S2.fsub_set,S2.fsub_id,F.mtbl_stru,F.doc_name,F.svr_name
  3   from deal_info D,step_inst S1,step_def S2,flow_inst F
  4   where D.step_inco=S1.step_inco and S1.flow_id=S2.flow_id
  5   and S1.step_code=S2.step_code and S1.flow_inid=F.flow_inid and D.step_type=5
  6   and D.fsub_flag is not null and D.fsub_flag=1 and rownum<=1;

其执行计划和l计信息如下Q?/p>

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=22 Card=1 Bytes=1077)
   1    0   COUNT (STOPKEY)
   2    1     NESTED LOOPS (Cost=22 Card=1 Bytes=1077)
   3    2       NESTED LOOPS (Cost=21 Card=1 Bytes=360)
   4    3         NESTED LOOPS (Cost=20 Card=1 Bytes=150)
   5    4           TABLE ACCESS (FULL) OF 'STEP_INST' (Cost=2 Card=9  Bytes=153)
   6    4           TABLE ACCESS (BY INDEX ROWID) OF 'DEAL_INFO' (Cost=2 Card=1 Bytes=133)
   7    6             INDEX (RANGE SCAN) OF 'DEAL_INFO_STEP_INCO' (NON-UNIQUE) (Cost=2
   8    3         TABLE ACCESS (BY INDEX ROWID) OF 'FLOW_INST' (Cost=1 Card=1 Bytes=210)
   9    8           INDEX (UNIQUE SCAN) OF 'PK_FLOW_INST' (UNIQUE)
  10    2       TABLE ACCESS (BY INDEX ROWID) OF 'STEP_DEF' (Cost=1 Card=1 Bytes=717)
  11   10         INDEX (UNIQUE SCAN) OF 'STEP_DEF_PK11119358638593' (UNIQUE)

Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
     270626  consistent gets
        273  physical reads
          0  redo size
       1079  bytes sent via SQL*Net to client
        655  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

q条SQL语句执行的时间也不长Q就几秒钟,但是我们看到consistent gets很高?7万多Q这个操作就是消耗CPU的祸首。从执行计划来看Q其执行计划昄不可理,问题出在表格的连接顺序上面,应该是deal_info表格做ؓ驱动表先讉K?/p>

查这些表格的l计分析Q发现step_def表格未做分析Q对该表格做l计信息分析Qƈ对deal_info表做q囑ֈ析后Q?br /> analyze table deal_info compute statistics for all indexed columns;

其执行计划正是我们所惌的,同时consistent gets也只?00左右Q该操作所消耗的CPU也下降到?%?/p>

2.表格的柱状图信息没有分析Q?br /> SELECT SO.SO_NBR, so_type.name,STATUS.STS_WORDS, SO.REMARKS, SO.CHECK_TYPE,CTRL_ASGN.DISPATCHED_DATE,
CTRL_ASGN.PRE_ALARM_DATE, CTRL_ASGN.ALARM_DATE
from SO,SO_HANDLE, CTRL_ASGN,so_type,status
WHERE SO_HANDLE.SO_NBR=SO.SO_NBR AND SO.SO_NBR=CTRL_ASGN.SO_NBR
AND SO_HANDLE.HANDLE_TYPE_ID=1017
and so.so_type_id=so_type.so_type_id and so.PRIORITY=status.sts_id and status.table_name='SO'
 AND STATUS.column_name ='PRIORITY' AND SO_HANDLE.WORK_AREA_ID= 300101
AND SO.STATE= 'B' AND SO.HALT ='N'
AND CTRL_ASGN.STATE = 'B'
AND CTRL_ASGN.STS = 'D';

该SQL语句执行旉?分钟左右?br /> 执行计划如下Q?br /> Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: RULE
   1    0   NESTED LOOPS
   2    1     NESTED LOOPS
   3    2       NESTED LOOPS
   4    3         NESTED LOOPS
   5    4           TABLE ACCESS (BY INDEX ROWID) OF 'STATUS'
   6    5             INDEX (RANGE SCAN) OF 'PK_STATUS' (UNIQUE)
   7    4           TABLE ACCESS (BY INDEX ROWID) OF 'CTRL_ASGN'
   8    7             INDEX (RANGE SCAN) OF 'CTRL_ASGN_0002'
   9    3         TABLE ACCESS (BY INDEX ROWID) OF 'SO'
  10    9           INDEX (UNIQUE SCAN) OF 'PK_SO' (UNIQUE)
  11    2       TABLE ACCESS (BY INDEX ROWID) OF 'SO_TYPE'
  12   11         INDEX (UNIQUE SCAN) OF 'PK_SO_TYPE' (UNIQUE)
  13    1     TABLE ACCESS (BY INDEX ROWID) OF 'SO_HANDLE'
  14   13       INDEX (RANGE SCAN) OF 'PK_SO_HANDLE' (UNIQUE)

我们攉表格信息和结果集的信?
SQL> select count(*) from CTRL_ASGN;
  COUNT(*)
----------
   1832469
SQL> select count(*) from status;
  COUNT(*)
----------
      1718

SQL> select count(*) from so;
  COUNT(*)
----------
    300296

SQL> select count(*) from so_type;
  COUNT(*)
----------
       265

SQL> select count(*) from so_handle;
  COUNT(*)
----------
   1296263  

select count(*) from ctrl_asgn where  CTRL_ASGN.STATE = 'B' AND CTRL_ASGN.STS = 'D';
  COUNT(*)
----------
    331490
      
select count(*) from so where SO.STATE= 'B' AND SO.HALT ='N';
  COUNT(*)
----------
       361
      
select count(*) from so_handle where SO_HANDLE.HANDLE_TYPE_ID=1017 and SO_HANDLE.WORK_AREA_ID= 300101;
  COUNT(*)
----------
     30086

通过对上面这些信息进行分析,我们可以发现q个问题也可以归lؓ表格之间的连接顺序上面。通过SO表做q囑ֈ析后Q该SQL语句只需1U钟卛_出来?br /> Analyze table so compute statistics for all indexed columns;

执行计划变成如下Q?br /> Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=273 Card=32 Bytes=3936)
   1    0   NESTED LOOPS (Cost=273 Card=32 Bytes=3936)
   2    1     NESTED LOOPS (Cost=153 Card=30 Bytes=2730)
   3    2       HASH JOIN (Cost=33 Card=30 Bytes=2130)
   4    3         NESTED LOOPS (Cost=31 Card=30 Bytes=1620)
   5    4           TABLE ACCESS (FULL) OF 'STATUS' (Cost=2 Card=1 Bytes=25)
   6    4           TABLE ACCESS (BY INDEX ROWID) OF 'SO' (Cost=29 Card=59 Bytes=1711)
   7    6             INDEX (RANGE SCAN) OF 'SO_0003' (NON-UNIQUE) (Cost=2 Card=59)
   8    3         TABLE ACCESS (FULL) OF 'SO_TYPE' (Cost=1 Card=128 Bytes=2176)
   9    2       TABLE ACCESS (BY INDEX ROWID) OF 'SO_HANDLE' (Cost=4 Card=280 Bytes=5600)
  10    9         INDEX (RANGE SCAN) OF 'PK_SO_HANDLE' (UNIQUE) (Cost=3 Card=280)
  11    1     TABLE ACCESS (BY INDEX ROWID) OF 'CTRL_ASGN' (Cost=4 Card=13620 Bytes=435840)
  12   11       INDEX (RANGE SCAN) OF 'CTRL_ASGN_0003' (NON-UNIQUE) (Cost=2 Card=13620)

 

3Q?nbsp;Not exists的?br /> --停机保号用户?除欠?
select 'XJ'||1||'180','停机保号用户?,count(distinct serviceid),1,'200509',groupid from cbq_lch_usage0
where subsidiaryid=1 and subid<>'02'  and subid<>'06' and status='7' and
serviceid not in (select serviceorderid from cbq_qf_usage1  where status<>'3' and status <> '8')
group by 'XJ'||1||'180','停机保号用户?,1,'200509',groupid ;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=RULE
   1    0   SORT (GROUP BY)
   2    1     FILTER
   3    2       TABLE ACCESS (FULL) OF 'CBQ_LCH_USAGE0'
   4    2       TABLE ACCESS (FULL) OF 'CBQ_QF_USAGE1'

Elapsed: 13:48:26.85

调整Q?br /> not in Ҏnot exists
create index idx_serviceorderid on cbq_qf_usage1(serviceorderid) nologging;

select 'XJ'||1||'180','停机保号用户?,count(distinct serviceid),1,'200509',a.groupid
from cbq_lch_usage0 a
where a.subsidiaryid=1 and a.subid<>'02'  and a.subid<>'06' and a.status='7'
and not exists(select 1 from cbq_qf_usage1 b where status<>'3' and status<>'8' and a.serviceid=b.serviceorderid)
group by 'XJ'||1||'180','停机保号用户?,1,'200509',a.groupid;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=RULE
   1    0   SORT (GROUP BY)
   2    1     FILTER
   3    2       TABLE ACCESS (FULL) OF 'CBQ_LCH_USAGE0'
   4    2       TABLE ACCESS (BY INDEX) OF 'CBQ_QF_USAGE1'
   5    4         INDEX (RANGE SCAN) OF 'IDX_SERVICEORDERID'

Elapsed: 00:00:01.36


九.其他
1QSELECT子句中避免?‘ * ‘
当你惛_SELECT子句中列出所有的COLUMN?使用动?SQL列引?‘*’ 是一个方便的Ҏ.不幸的是,q是一个非怽效的Ҏ. 实际?ORACLE在解析的q程? 会将’*’ 依次转换成所有的列名, q个工作是通过查询数据字典完成? q意味着耗费更多的时?
2Q用TRUNCATE替代DELETE
3Q用表的别?Alias)
当在SQL语句中连接多个表? 请用表的别名ƈ把别名前~于每个Column?q样一?可以减解析的旉q减那些由Column歧义引v的语法错?


4.索引的等U?br />  一般情늃引等U如下:
 a) {式比较比范围比较要高?br />  b) 唯一性烦引比非唯一性烦引要高?br />  c) 一般情况下单列索引{要比复合索引高,但如果where子句中包含所  有复合烦引的字段Q则复合索引{高?br />  例如Q?br /> SELECT col1, ...
FROM emp
WHERE emp_name = 'GURRY'
AND emp_no = 127
AND dept_no = 12

Index1 (emp_name)
Index2 (emp_no, dept_no, emp_name)
ORACLE用烦引Index2?/p>

5.l计信息分析
在现实当中,有关analyze分析有以下两U误区:

a) 只要对主要的或者关键的表格做分析即可。其实正的应该是需要对所有涉及到的表格都做过分析?/p>

b) 做一ơ分析后卛_高枕无忧。事实上Q一旦做q分析后Q就应该定期更新q些l计信息Q以保证l计信息的正性?/p>

6QExistsLIn?br />  有许多h认ؓ用ExistsL用In要快,q也是一个误区。有时用in反而比用Exists快?br /> 他们之间的区别如下:
  IN subqueryQ首先执行subqueryQ由subquery来驱动父查询。而Exists子查询则q查询来驱动子查询。这是两者之间的区别?br />  所以如果子查询的话,则可以采用in会快一些,如果子查询大的话Q则采用exists会快一些?/p>

7Q?gt;?gt;=
 大于或小于操作符一般情况下是不用调整的Q因为它有烦引就会采用烦引查找,但有的情况下可以对它q行优化Q如一个表?00万记录,一个数值型字段AQ?br /> 30万记录的A=0Q?0万记录的A=1Q?9万记录的A=2Q?万记录的A=3?br />  那么执行A>2与A>=3的效果就有很大的区别了,因ؓA>2时ORACLE会先扑և
?的记录烦引再q行比较Q而A>=3时ORACLE则直接找?3的记录烦引?/p>

8. 使用索引来避免排?br />   索引是排好序的,在某些情况下可以使用索引来避免排序?br />   SELECT acc_name, acc_surname
  FROM account acct
  ORDER BY 1;

  SELECT /*+ INDEX_ASC(acct acc_ndx1) */ acc_name,acc_surname
  FROM account acct;


9.大对象操?br />  
a)Big Insert
(1)direct insert(serial and parallel)
insert /*+append*/into tab1 select * from tab2;
       Insert /*+append parallel(emp,8)*/ into emp  select * from emp_bak;
(2)nologging
         insert into tab1 nologging select * from tab2;
    (3)Large extent size
     更大的extent可以获得更好的insert性能?br />  (5)Large rollback segment

b)Large Index Create
  大的索引extent size?br />     大的Sort_area_size?br />   采用nologging
  采用parallel
  大的临时表空?/p>

alter session sort_area_size=100000000;
create index xxx on aa(ab) nologging parallel 2;

 c)Large Delete
分几ơdelete?/p>

 

 


附录一
Hint全集
174. /*+ALL_ROWS*/

  表明对语句块选择Z开销的优化方?q获得最佛_吐量,使资源消耗最化.例如:
SELECT /*+ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP';

  175. /*+FIRST_ROWS*/

  表明对语句块选择Z开销的优化方?q获得最佛_应时?使资源消耗最化.例如:
SELECT /*+FIRST_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP';

  176. /*+CHOOSE*/

  表明如果数据字典中有讉K表的l计信息,基于开销的优化方?q获得最佳的吞吐?表明如果数据字典中没有访问表的统计信?基于规则开销的优化方?例如:
SELECT /*+CHOOSE*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP';

  177. /*+ RULE*/

  表明对语句块选择Z规则的优化方?例如:
SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP'; 

  178. /*+ FULL(TABLE)*/

  表明对表选择全局扫描的方?例如:
SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='CCBZZP';

  179. /*+ROWID(TABLE)*/

  提示明确表明Ҏ定表ҎROWIDq行讉K.例如:
SELECT /*+ROWID(BSEMPMS)*/ * FROM BSEMPMS WHERE ROWID>='AAAAAAAAAAAAAA'
AND EMP_NO='CCBZZP';

  180. /*+CLUSTER(TABLE)*/
 
  提示明确表明Ҏ定表选择扫描的讉KҎ,它只对簇对象有效.例如:
SELECT /*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS
WHERE DPT_NO='TEC304' AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

181. /*+ INDEX(TABLE   INDEX_NAME)*/
/*+index(table ind_name) index(table ind_name)*/
表明对表选择索引的扫描方?例如:
SELECT /*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX='M';

  182. /*+INDEX_ASC(TABLE INDEX_NAME)*/

  表明对表选择索引升序的扫描方?例如:
SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='CCBZZP';

  183. /*+INDEX_COMBINE*/

  为指定表选择位图讉K路经,如果INDEX_COMBINE中没有提供作为参数的索引,选择Z囄引的布尔l合方式.例如:
SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/ * FROM BSEMPMS
WHERE SAL<5000000 AND HIREDATE

  184. /*+INDEX_JOIN(TABLE INDEX_NAME)*/

  提示明确命o优化器用烦引作问\?例如:
SELECT /*+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)*/ SAL,HIREDATE
FROM BSEMPMS WHERE SAL<60000;

  185. /*+INDEX_DESC(TABLE INDEX_NAME)*/

  表明对表选择索引降序的扫描方?例如:
SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='CCBZZP';

  186. /*+INDEX_FFS(TABLE INDEX_NAME)*/

  Ҏ定的表执行快速全索引扫描,而不是全表扫描的办法.例如:
SELECT /*+INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305';

  187. /*+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,...*/

  提示明确q行执行规划的选择,几个单列烦引的扫描合v?例如:
SELECT /*+INDEX_FFS(BSEMPMS IN_DPTNO,IN_EMPNO,IN_SEX)*/ * FROM BSEMPMS WHERE EMP_NO='CCBZZP' AND DPT_NO='TDC306';

  188. /*+USE_CONCAT*/

  Ҏ询中的WHERE后面的OR条gq行转换为UNION ALL的组合查?例如:
SELECT /*+USE_CONCAT*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';

  189. /*+NO_EXPAND*/

  对于WHERE后面的OR 或者IN-LIST的查询语?NO_EXPAND阻止其Z优化器对其进行扩?例如:
SELECT /*+NO_EXPAND*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';

  190. /*+NOWRITE*/

  止Ҏ询块的查询重写操?

191. /*+REWRITE*/

  可以视图作为参?

  192. /*+MERGE(TABLE)*/

  能够对视囄各个查询q行相应的合q?例如:
SELECT /*+MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO
,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) Va WHERE A.DPT_NO=V.DPT_NO
AND A.SAL>V.AVG_SAL;

  193. /*+NO_MERGE(TABLE)*/

  对于有可合ƈ的视图不再合q?例如:
SELECT /*+NO_MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO
,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO
AND A.SAL>V.AVG_SAL;

  194. /*+ORDERED*/

  Ҏ表出现在FROM中的序,ORDERED使ORACLE依此序对其q接.例如:
SELECT /*+ORDERED*/ A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C
WHERE A.COL1=B.COL1 AND B.COL1=C.COL1;

  195. /*+USE_NL(TABLE)*/

  指定表与嵌套的q接的行源进行连?q把指定表作为内部表.例如:
SELECT /*+ORDERED USE_NL(BSEMPMS)*/ BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

  196. /*+USE_MERGE(TABLE)*/

  指定的表与其他行源通过合ƈ排序q接方式q接h.例如:
SELECT /*+USE_MERGE(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE
BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

  197. /*+USE_HASH(TABLE)*/

  指定的表与其他行源通过哈希q接方式q接h.例如:
SELECT /*+USE_HASH(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE
BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

  198. /*+DRIVING_SITE(TABLE)*/

  强制与ORACLE所选择的位|不同的表进行查询执?例如:
SELECT /*+DRIVING_SITE(DEPT)*/ * FROM BSEMPMS,DEPT@BSDPTMS WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;

  199. /*+LEADING(TABLE)*/

  指定的表作接次序中的首?

200. /*+CACHE(TABLE)*/

  当进行全表扫描时,CACHE提示能够表的检索块攄在缓冲区~存中最q最列表LRU的最q用端例如:
SELECT /*+FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;

  201. /*+NOCACHE(TABLE)*/

  当进行全表扫描时,CACHE提示能够表的检索块攄在缓冲区~存中最q最列表LRU的最q用端Q例?
SELECT /*+FULL(BSEMPMS) NOCAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;

  202. /*+APPEND*/

  直接插入到表的最?可以提高速度.
insert /*+append*/ into test1 select * from test4 ;

  203. /*+NOAPPEND*/

  通过在插入语句生存期内停止ƈ行模式来启动常规插入.
insert /*+noappend*/ into test1 select * from test4;

附录?br /> STATSPACK包的使用指南
1.oracle8.1.6开始引qstatspackQstatspack是诊断oracle性能的强有力的工兗?br /> 2.安装前准?br />  A.首先是系l参数的认Q?br /> job_query_processesQؓ了徏立自动Q务,执行数据攉Q该参数要大?
time_statisticsQؓ了收集操作系l计时信息等Q需要将其设|ؓTRUE

B.最好是单独的ؓperfstat用户Q即安装statspack要徏的用P单独建立数据表空间和临时表空_数据表空间至要?00M的空闲空_否则创徏statspack对象会失败,如果打算长期使用statspackQ可以考虑建稍大些的数据表I间?br /> 3.安装
A.安装脚本
安装的脚本所在目录是$ORACLE_HOME/rdbms/adminQ在oracle8.1.6版本安装脚本是statscre.sqlQ之?8.1.7版本开始就是spcreate.sqlQ安装所需用户?i之前的需要internal或者拥有sysdba权限的用P9i需要的用户?sysQ?i已经不存在internal用户了)
执行安装脚本如下Q?br /> SQL> @$ORACLE_HOME/rdbms/admin/spcreate
 
B. 在安装过E中Q需要填写perfstat用户的密码,q且选择perfstat用户的数据表I间和时表I间Q安装完成之后,察看相应?lis文g查安装是否正无误,有问题可以通过spdrop.sql完成statspack的卸载,重新q行spcreate.sql完成statspack的安装?/p>

4.  试
最单的statspack报告生成Q运行两ơstatspack.snapQ然后运行spreport.sql生成一个基于两个时间点的报告。如果是8.1.7.3之前版本的OracleQ需要修改spcpkg.sqlQ要substr修改为substrbQ如下位|:
       select l_snap_id
            , p_dbid
            , p_instance_number
            , substr(sql_text,1,31) ? substrb(sql_text,1,31)
 
建立单的statspack报告q程如下Q?br /> SQL> execute statspack.snap (i_snap_level=>10)
PL/SQL procedure successfully completed.
SQL> execute statspack.snap
PL/SQL procedure successfully completed.
SQL> @$ORACLE_HOME/rdbms/admin/spreport
 
Spreport的执行过E中会列出需要选择的快照,你需要填写该报告描述的开始和l束的快照序Pq填写报告的文g名,当然可以不填Q用默认的报告文g名,默认的会生成在目?ORACLE_HOME/rdbms/admin?br /> q样可以验证statspack已经正确的安装完成了
 
自动攉statspack快照
正常在真正的环境下,我们是需要连l的采样一D|_q样生成的statspack才能更好的反映系l的现状Q我们是可以通过spauto.sql来自动收集数据的?br />  
主要可能会设计到修改如下部分的内?br /> variable jobno number;
variable instno number;
begin
  select instance_number into :instno from v$instance;
  dbms_job.submit(:jobno, 'statspack.snap;', trunc(sysdate+1/24,'HH'), 'trunc(SYSDATE+1/24,''HH'')', TRUE, :instno);
  commit;
end;
/
主要是修?/24q个|目前是一个小时自动收集一ơ数据,如果要改动ؓ半个时攉一ơ数据就修改?/48,同理Q进行或大或的修改?br />  
执行后,可以在spauto.lis文g中看到当前自动收集数据的jobL信息。当惌生成statspack报告的时候,只要选择M两个不跨停机时间的快照序号可以了。注意,statspack是不能跨停机的?/p>



Astro.Qi 2009-01-19 13:16 发表评论
]]>
Oracle中表的连接及其调?/title><link>http://m.tkk7.com/AstroQi/archive/2009/01/19/251875.html</link><dc:creator>Astro.Qi</dc:creator><author>Astro.Qi</author><pubDate>Mon, 19 Jan 2009 04:58:00 GMT</pubDate><guid>http://m.tkk7.com/AstroQi/archive/2009/01/19/251875.html</guid><wfw:comment>http://m.tkk7.com/AstroQi/comments/251875.html</wfw:comment><comments>http://m.tkk7.com/AstroQi/archive/2009/01/19/251875.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/AstroQi/comments/commentRss/251875.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/AstroQi/services/trackbacks/251875.html</trackback:ping><description><![CDATA[<div id="nphntlr" class="art_txt"> <div> <div> <p><font style="font-size: 14px">只有对这些问题有了清晰的理解后,我们才能针对特定的查询需求选择合适的q接方式Q开发出健壮的数据库应用E序。选择合适的表连接方法对SQL语句q行的性能有着臛_重要的媄响。下面我们就Oracle常用的一些连接方法及适用情景做一个简单的介绍?/font></p> <p><font style="font-size: 14px"><font style="font-size: 16px"><strong>一、嵌套@环连接(Nested LoopQ?/strong> </font></font></p> <p>嵌套循环q接的工作方式是q样的: </p> <p>1、Oracle首先选择一张表作ؓq接的驱动表Q这张表也称为外部表QOuter TableQ。由驱动表进行驱动连接的表或数据源称为内部表QInner TableQ?</p> <p>2、提取驱动表中符合条件的记录Q与被驱动表的连接列q行兌查询W合条g的记录。在q个q程中,Oracle首先提取驱动表中W合条g的第一条记录,再与内部表的q接列进行关联查询相应的记录行。在兌查询的过E中QOracle会持l提取驱动表中其他符合条件的记录与内部表兌查询。这两个q程是ƈ行进行的Q因此嵌套@环连接返回前几条记录的速度是非常快的。在q里需要说明的是,׃Oracle最的IO单位为单个数据块Q因此在q个q程?Oracle会首先提取驱动表中符合条件的单个数据块中的所有行Q再与内部表q行兌q接查询的,然后提取下一个数据块中的记录持箋地@环连接下厅R当Ӟ如果单行记录跨越多个数据块的话,是一ơ单条记录进行关联查询的?</p> <p>3、嵌套@环连接的q程如下所C:</p> <table style="width: 566px; height: 121px" cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="566" align="center" bordercolorlight="#000000" border="1"> <tbody> <tr> <td class="code" bgcolor="#e6e6e6"> <pre> <p>NESTED LOOP <Outer Loop> <Inner Loop> </p> </pre> </td> </tr> </tbody> </table> <p>我们可以看出q里面存在着两个循环Q一个是外部循环Q提取驱动表中符合条件的每条记录。另外一个是内部循环Q根据外循环中提取的每条记录对内部表q行q接查询相应的记录。由于这两个循环是嵌套进行的Q故此种q接ҎUCؓ嵌套循环q接?</p> <p>嵌套循环q接适用于查询的选择性强、约束性高q且仅返回小部分记录的结果集。通常要求驱动表的记录Q符合条件的记录Q通常通过高效的烦引访问)较少Q且被驱动表q接列有唯一索引或者选择性强的非唯一索引Ӟ嵌套循环q接的效率是比较高的。比如下面这个查询是选用嵌套循环q接的典型例子:</p> <table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"> <tbody> <tr> <td class="code" bgcolor="#e6e6e6"> <pre> <p>SQL> select e.empno,e.ename,e.job,d.dname 2 from emp e,dept d 3 where e.deptno=d.deptno 4 and e.empno=7900;</p> <p>EMPNO ENAME JOB DNAME ---------- ---------- --------- -------------- 7900 JAMES CLERK SALES</p> <p>Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 NESTED LOOPS 2 1 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' 3 2 INDEX (UNIQUE SCAN) OF 'PK_EMP' (UNIQUE) 4 1 TABLE ACCESS (BY INDEX ROWID) OF 'DEPT' 5 4 INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE) </p> </pre> </td> </tr> </tbody> </table> <p>在这个查询中Q优化器选择emp作ؓ驱动表,Ҏ唯一性烦引PK_EMP快速返回符合条件empno?900的记录,然后再与被驱动表dept?deptno兌查询相应的dnameq最l返回结果集。由于dept表上面的deptno有唯一索引PK_DEPTQ故查询能够快速地定位deptno 对应dname为SALES的记录ƈq回?</p> <p>嵌套循环q接驱动表的选择也是q接中需要着重注意的一点,有一个常见的误区是驱动表要选择表Q其实这是不对的。假如有两张表A、B兌查询QA表有1000000条记录,B表有10000条记录,但是A表过滤出来的记录只有10条,q时候显然用A表当做驱动表是比较合适的。因此驱动表是由qo条g限制q回记录最的那张表,而不是根据表的大来选择的?</p> <p>在外q接查询中,如果走嵌套@环连接的话,那么驱动表必然是没有W合条g兌的那张表Q也是后面不加(+)的那张表。这是由于外q接需要提取可能另一张表没符合条件的记录Q因此驱动表需要是那张我们要返回所有符合条件记录的表。比如下面这个查询,是选择了emp表做为驱动表q行q接Q?/p> <table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"> <tbody> <tr> <td class="code" bgcolor="#e6e6e6"> <pre> <p><a href="mailto:Roby@XUE">Roby@XUE</a>> select emp.ename,dept.dname 2 from emp,dept 3 where emp.deptno=dept.deptno(+); ENAME DNAME ---------- -------------- SMITH ALLEN WARD SALES JONES RESEARCH MARTIN SALES BLAKE SALES CLARK ACCOUNTING SCOTT RESEARCH KING ACCOUNTING TURNER SALES ADAMS RESEARCH JAMES SALES FORD RESEARCH MILLER ACCOUNTING 14 rows selected. Execution Plan ----------------------------------------------------------</p> <p> | 0 | SELECT STATEMENT | | 14 | 308 | 15 | 1 | NESTED LOOPS OUTER | | 14 | 308 | 15 | 2 | TABLE ACCESS FULL | EMP | 14 | 126 | 3 | 3 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 13 | 1 |* 4 | INDEX UNIQUE SCAN | DEPT_PK | 1 | | 0</p> </pre> </td> </tr> </tbody> </table> <p>嵌套循环q接q回前几行的记录是非常快的,q是因ؓ使用了嵌套@环后Q不需要等到全部@环结束再q回l果集,而是不断地将查询出来的结果集q回。在q种情况下,l端用户会快速地得到q回的首批记录,且同时等待Oracle内部处理其他记录q返回。如果查询的驱动表的记录数非常多Q或者被驱动表的q接列上无烦引或索引不是高度可选的情况Q嵌套@环连接的效率是非怽的?/p> </div> </div> </div> <p><font style="font-size: 14px"><strong>二、排序合q连?Sort Merge)</strong> </font></p> <p><font style="font-size: 14px">排序合ƈq接的方法非常简单。在排序合ƈq接中是没有驱动表的概念的,两个互相q接的表按连接列的值先排序Q排序完后Ş成的l果集再互相q行合ƈq接提取W合条g的记录。相比嵌套@环连接,排序合ƈq接比较适用于返回大数据量的l果。以下ؓ排序合ƈq接的例子:</font></p> <table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"> <tbody> <tr> <td class="code" bgcolor="#e6e6e6"> <pre> <p><a href="mailto:Roby@XUE"><font style="font-size: 14px">Roby@XUE</font></a><font style="font-size: 14px">> select emp.ename,dept.dname 2 from emp,dept 3 where emp.deptno=dept.deptno 4 /</font></p> <p><font style="font-size: 14px">ENAME DNAME ---------- -------------- CLARK ACCOUNTING KING ACCOUNTING MILLER ACCOUNTING JONES RESEARCH SCOTT RESEARCH FORD RESEARCH ADAMS RESEARCH TURNER SALES JAMES SALES WARD SALES MARTIN SALES BLAKE SALES</font></p> <p><font style="font-size: 14px">12 rows selected.</font></p> <p><font style="font-size: 14px">Execution Plan</font></p> <p><font style="font-size: 14px">--------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 12 | 264 | 8 (25)| 00:00:01 | | 1 | MERGE JOIN | | 12 | 264 | 8 (25)| 00:00:01 | | 2 | SORT JOIN | | 4 | 52 | 4 (25)| 00:00:01 | | 3 | TABLE ACCESS FULL| DEPT | 4 | 52 | 3 (0) | 00:00:01 | |* 4| SORT JOIN | | 12 | 108 | 4 (25)| 00:00:01 | |* 5| TABLE ACCESS FULL| EMP | 12 | 108 | 3 (0) | 00:00:01 |</font></p> </pre> </td> </tr> </tbody> </table> <p><font style="font-size: 14px">可以看得出来上述查询首先按dept、emp两张表的deptno先排序,然后排序好的l果集再q行合ƈq接q回最l的记录?</font></p> <p><font style="font-size: 14px">排序合ƈq接在数据表预先排序好的情况下效率是非常高的Q也比较适用于非{D接的情况Q比?gt;?gt;=?lt;={情况下的连接(哈希q接只适用于等D接)。由于Oracle中排序操作的开销是非常消耗资源的Q当l果集很大时排序合ƈq接的性能很差Q于是Oracle?.3之后推出了新的连接方式——哈希连接?/font></p> <p><font style="font-size: 14px"><strong>三、哈希连接(Hash joinQ?/strong> </font></p> <p><font style="font-size: 14px">哈希q接分ؓ两个阶段Q如下?</font></p> <p><font style="font-size: 14px">1、构建阶D:优化器首先选择一张小表做为驱动表Q运用哈希函数对q接列进行计生一张哈希表。通常q个步骤是在内存Qhash_area_sizeQ里面进行的Q因此运很快?</font></p> <p><font style="font-size: 14px">2、探阶D:优化器对被驱动表的连接列q用同样的哈希函数计得到的l果与前面Ş成的哈希表进行探返回符合条件的记录。这个阶D中如果被驱动表的连接列的值没有与驱动表连接列的值相{的话,那么q些记录会被丢弃而不q行探测。关于哈希连接更深层ơ的原理可以参考Itpub上网友logzgh发表?#8220;hash join法原理”帖子Q?/font><a ><font style="font-size: 14px">http://www.itpub.net/showthread.php?threadid=315494</font></a><font style="font-size: 14px">Q?</font></p> <p><font style="font-size: 14px">以下为哈希连接的一个例子:</font></p> <table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"> <tbody> <tr> <td class="code" bgcolor="#e6e6e6"> <pre> <p><a href="mailto:Roby@XUE"><font style="font-size: 14px">Roby@XUE</font></a><font style="font-size: 14px">> select /**//*+ use_hash(emp,dept) */ emp.ename,dept.dname 2 from emp,dept 3 where emp.deptno=dept.deptno;</font></p> <p><font style="font-size: 14px">ENAME DNAME ---------- -------------- WARD SALES JONES RESEARCH MARTIN SALES BLAKE SALES CLARK ACCOUNTING SCOTT RESEARCH KING ACCOUNTING TURNER SALES ADAMS RESEARCH JAMES SALES FORD RESEARCH MILLER ACCOUNTING</font></p> <p><font style="font-size: 14px">12 rows selected.</font></p> <p><font style="font-size: 14px">Execution Plan --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 12 | 264 | 7 (15)| 00:00:01 | |* 1 | HASH JOIN | | 12 | 264 | 7 (15)| 00:00:01 | | 2 | TABLE ACCESS FULL| DEPT | 4 | 52 | 3 (0)| 00:00:01 | |* 3 | TABLE ACCESS FULL| EMP | 12 | 108 | 3 (0)| 00:00:01 |</font></p> </pre> </td> </tr> </tbody> </table> <p><font style="font-size: 14px">在这个查询中优化器首先选择deptq张表ؓ驱动表,对列deptnoq算哈希函数构徏一张哈希表Q然后再对被驱动表emp的deptno列运同L哈希函数计算得到的结果进行探,最l连接得出符合条件的记录?</font></p> <p><font style="font-size: 14px">同嵌套@环外q接一P哈希循环外连接的驱动表同h没有W合条g兌的那张表。如下述例子Q?/font></p> <table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"> <tbody> <tr> <td class="code" bgcolor="#e6e6e6"> <pre> <p><a href="mailto:Roby@XUE"><font style="font-size: 14px">Roby@XUE</font></a><font style="font-size: 14px">> select /**//*+ use_hash(emp,dept) */ emp.ename,dept.dname 2 from emp,dept 3 where emp.deptno=dept.deptno(+); ENAME DNAME ---------- -------------- MILLER ACCOUNTING KING ACCOUNTING CLARK ACCOUNTING FORD RESEARCH ADAMS RESEARCH SCOTT RESEARCH JONES RESEARCH JAMES SALES TURNER SALES BLAKE SALES MARTIN SALES WARD SALES ALLEN SMITH<br /> </p> <font style="font-size: 14px"><font style="font-size: 14px"> <p><font style="font-size: 14px">12 rows selected.</font></p> <p><font style="font-size: 14px">Execution Plan<br /> </font></p> </font></font> <p> -------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------- | 0 | SELECT STATEMENT | | 14 | 308 | 7 (15)| 00:00:01 | |* 1| HASH JOIN OUTER | | 14 | 308 | 7 (15)| 00:00:01 | | 2 | TABLE ACCESS FULL| EMP | 14 | 126 | 3 (0) | 00:00:01 | | 3 | TABLE ACCESS FULL| DEPT | 4 | 52 | 3 (0) | 00:00:01 | --------------------------------------------------------------</font></p> </pre> </td> </tr> </tbody> </table> <p><font style="font-size: 14px">哈希q接比较适用于返回大数据量结果集的连接。用哈希连接必L在CBO模式下,参数hash_join_enabled讄为trueQ且只适用于等D接。从Oracle9i开始,哈希q接׃其良好的性能渐渐取代了原来的排序合ƈq接?/font></p> <p><font style="font-size: 14px"><strong>四、跟表连接有关的几个HINT</strong> </font></p> <p><font style="font-size: 14px">Q?Quse_nlQt1,t2Q:表示对表t1、t2兌旉用嵌套@环连接?Q?Quse_mergeQt1,t2Q:表示对表t1、t2兌旉用排序合q连接?Q?Quse_hashQt1,t2Q:表示对表t1、t2兌旉用哈希连接?Q?Qleading(t)Q表C在q行表连接时Q选择t为驱动表?Q?QordredQ要求优化器按from列出的表序q行q接?</font></p> <p><font style="font-size: 14px">需要注意的是在Oracle使用hint?如果SQL语句中表用别名的?那么hint中必M用表的别?否则hint不会生效?/font></p> <img src ="http://m.tkk7.com/AstroQi/aggbug/251875.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/AstroQi/" target="_blank">Astro.Qi</a> 2009-01-19 12:58 <a href="http://m.tkk7.com/AstroQi/archive/2009/01/19/251875.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC ORACLE CLOB (用分|想解决兆以上的字W流操作问题)http://m.tkk7.com/AstroQi/archive/2008/07/10/214025.htmlAstro.QiAstro.QiThu, 10 Jul 2008 09:05:00 GMThttp://m.tkk7.com/AstroQi/archive/2008/07/10/214025.htmlhttp://m.tkk7.com/AstroQi/comments/214025.htmlhttp://m.tkk7.com/AstroQi/archive/2008/07/10/214025.html#Feedback1http://m.tkk7.com/AstroQi/comments/commentRss/214025.htmlhttp://m.tkk7.com/AstroQi/services/trackbacks/214025.html import java.io.*;
import java.util.*;
import java.sql.*;
 
public class ClobTest {
 
    private static final String DRIVER = "oracle.jdbc.driver.OracleDriver";
    private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:ora10g";
    private static final String USER = "sc";
    private static final String PASSWORD = "sc";
    private static Connection conn = null;
    private static Statement stmt = null;

 
    /**
     * 往数据库中插入一个新的CLOB对象
     */
    public static void save(BO obj) throws Exception {
        /* 一定要讑֮不自动提交,否则抛出ORA-01002: dq反序 */
        boolean defaultCommit = conn.getAutoCommit();
        conn.setAutoCommit(false);
 
        try {
            stmt = conn.createStatement();
            /* 插入一个空的CLOB对象 */
            stmt.executeUpdate("INSERT INTO TEST_CLOB VALUES ('1000', EMPTY_CLOB())");//一定要使用Oracle中的EMPTY_CLOB()函数
           
            stmt.close();//记得x我哦 :-)
            stmt= null;

            /* 查询此CLOB对象q?*/
            //stmt = conn.prepareStatement();//如果是PrepareStatement接口,一定要重新创徏该对?否则抛出ORA-01006: 赋值变量不?/span>?/span>
           
            ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");//一定要for update锁定该记录,否则抛出ORA-22920: 未锁定含?LOB 值的?/span>
            while (rs.next()) {
                /* 取出此CLOB对象 */
                oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");

                /* 向CLOB对象中写入数?*/
                Writer out = clob.getCharacterOutputStream();
                //out.write(new String(obj.getEmail()));//obj.getEmail()q回byte[]cd,但是当obj.getEmail()l对大时,执行new String(byte[])?JVM会抛?span style="color: red;">内存
溢出异常

                byte[] emails = obj.getEmail();
                ClobStreamHandler csh = new ClobStreamHandler(emails);
                String[] arrx = csh.pagedClobStream();//要解军_存溢出异常,必须把绝对大的byte[]q行分页
                if (arrx != null){
                    for (int i = 0; i < arrx.length; i++) {
                        out.write(arrx[i]);
                        out.flush();//要解军_存溢出异?必须一一?/span>的flush()到数据库
                    }
                }
                else out.write("");
                out.close();
            }
            /* 正式提交 */
            conn.commit();

            /* 恢复原提交状?*/
            conn.setAutoCommit(defaultCommit);
        } catch (Exception ex) {
            /* 出错回滚 */
            conn.rollback();
            throw ex;
        } finally {相关关闭操作}
 
      
    }
 
    /**
     * 修改CLOB对象Q是在原CLOB对象基础上进行覆盖式的修改)
     *
     * @param obj - 数据对象
     * @throws java.lang.Exception
     * @roseuid 3EDA04B60367
     */
    public static void modify(BO obj) throws Exception {
        /* 讑֮不自动提?*/
        boolean defaultCommit = conn.getAutoCommit();
        conn.setAutoCommit(false);
 
        try {
            /* 查询CLOB对象q?*/
            ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");
            while (rs.next()) {
                /* 获取此CLOB对象 */
                oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");  
                
                /* q行覆盖式修?*/
                Writer out = clob.getCharacterOutputStream();
                byte[] emails = obj.getEmail();
                ClobStreamHandler csh = new ClobStreamHandler(emails);
                String[] arrx = csh.pagedClobStream();//要解军_存溢出异常,必须把绝对大的byte[]q行分页
                if (arrx != null){
                    for (int i = 0; i < arrx.length; i++) {
                        out.write(arrx[i]);
                        out.flush();//要解军_存溢出异?必须一一?/span>的flush()到数据库
                    }
                }
                else out.write("");
                out.close();
            }
            /* 正式提交 */
            conn.commit();

            /* 恢复原提交状?*/
            conn.setAutoCommit(defaultCommit);
        } catch (Exception ex) {
            /* 出错回滚 */
            conn.rollback();
            throw ex;
        } finally {相关关闭操作}
 
        /* 恢复原提交状?*/
        conn.setAutoCommit(defaultCommit);
    }
 
    /**
     * 替换CLOB对象Q将原CLOB对象清除Q换成一个全新的CLOB对象Q?br />      *
     * @param obj - 数据对象
     * @throws java.lang.Exception
     * @roseuid 3EDA04BF01E1
     */
    public static void replace(BO obj) throws Exception {
        /* 讑֮不自动提?*/
        boolean defaultCommit = conn.getAutoCommit();
        conn.setAutoCommit(false);
 
        try {
            /* 清空原CLOB对象 */
            stmt.executeUpdate("UPDATE TEST_CLOB SET CLOBCOL=EMPTY_CLOB() WHERE ID='1000'");
            
            /* 查询CLOB对象q?*/
            ResultSet rs = stmt.executeQuery("SELECT CLOBCOL FROM TEST_CLOB WHERE ID='1000' FOR UPDATE");
            
            while (rs.next()) {
                /* 获取此CLOB对象 */
                oracle.sql.CLOB clob = (oracle.sql.CLOB)rs.getClob("CLOBCOL");
                /* 更新数据 */
                Writer out = clob.getCharacterOutputStream();
                byte[] emails = item.getEmail();
                ClobStreamHandler csh = new ClobStreamHandler(emails);
                String[] arrx = csh.pagedClobStream();//要解军_存溢出异常,必须把绝对大的byte[]q行分页
                if (arrx != null){
                    for (int i = 0; i < arrx.length; i++) {
                        out.write(arrx[i]);
                        out.flush();//要解军_存溢出异?必须一一?/span>的flush()到数据库
                    }
                }
                else out.write("");
                out.close();
            }
            /* 正式提交 */
            conn.commit();

            /* 恢复原提交状?*/
            conn.setAutoCommit(defaultCommit);
        } catch (Exception ex) {
            /* 出错回滚 */
            conn.rollback();
            throw ex;
        } finally {相关关闭操作}
 
       
    }
 
    /**
     * dCLOB对象
     */
    public static byte[] read() throws Exception {
        /* 讑֮不自动提?*/
        boolean defaultCommit = conn.getAutoCommit();
        conn.setAutoCommit(false);
 
        try {
            /* 查询CLOB对象 */
            ResultSet rs = stmt.executeQuery("SELECT * FROM TEST_CLOB WHERE ID='1000'");
            while (rs.next()) {
                /* 获取CLOB对象 */
                oracle.sql.CLOB c= (oracle.sql.CLOB)rs.getClob("CLOBCOL");
               
                if (c != null){
                     try {
                          oracle.jdbc.driver.OracleClobInputStream is = (OracleClobInputStream) c.getAsciiStream();
                          java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
                   
                          byte[] by = new byte[1024 * 200];
                          while(is.read(by, 0, by.length) != -1){
                              baos.write(by, 0, by.length);
                              baos.flush();//把数据写入内?/span>
                          }
                   
                          baos.close();
                          is.close();
                          return baos.toByteArray();//不会内存溢出?/span>,呵呵. 原因是把数据写入了内?而不是JVM的内存管理区?br />                      } catch (SQLException e) {
                           //e.printStackTrace();
                     }
                }
                else return new byte[0];
                break;
            }
        } catch (Exception ex) {
            conn.rollback();
            throw ex;
        } finally {相关关闭操作}
 
        /* 恢复原提交状?*/
        conn.setAutoCommit(defaultCommit);
    }
 
    /**
     * 建立试用表?br />      * @throws Exception
     */
    public static void createTables() throws Exception {
        try {
            stmt.executeUpdate("CREATE TABLE TEST_CLOB (ID VARCHAR2(4), CLOBCOL CLOB)");
            stmt.executeUpdate("CREATE TABLE TEST_BLOB (ID VARCHAR2(4), BLOBCOL BLOB)");
        } catch (Exception ex) {
 
        }
    }
 
    public static void main(String[] args) throws Exception {
        /* 装蝲驱动,建立数据库连?*/
        Class.forName(DRIVER);
        conn = DriverManager.getConnection(URL, USER, PASSWORD);
        stmt = conn.createStatement();
 
        /* 建立试表格 */
        createTables();
    }
}


    对Clob字符进行分늚法Q?br />    
 1 package privy.astroqi.oracle.db.handler;
 2 
 3 /**
 4  * 
 5  * @author Astro Qi
 6  * @since  2008-07-23 00:05
 7  *
 8  */
 9 public class ClobStreamHandler {
10 
11     private static int PAGE_SIZE = 1024 * 200 * 1;
12     
13     private byte[] dataes;
14     
15     private int length;
16     
17     private int pageCount;
18     
19     public ClobStreamHandler(byte[] data){
20         if (data == null){
21             throw new java.lang.IllegalArgumentException("参数byte[]不能为空,否则无法处理接下来的操作.");
22         }
23         
24         dataes = data;
25         length = dataes.length;
26         pageCount = (length % PAGE_SIZE == 0? (length / PAGE_SIZE) : (length / PAGE_SIZE) + 1;
27         
28     }
29     
30     public String[] pagedClobStream(){
31         
32         String[] arr = new String[pageCount];
33         
34         for (int i = 1; i <= pageCount; i++) {
35             int sheYuByte = length - (PAGE_SIZE * (i - 1));
36             byte[] b = null;
37             if (sheYuByte > PAGE_SIZE){
38                 b = new byte[PAGE_SIZE];
39             } 
40             else {
41                 b = new byte[sheYuByte];
42             }
43             for (int j = 0; j < b.length; j++){
44                 b[j] = dataes[(i - 1* PAGE_SIZE + j];
45             }
46             arr[i - 1= new String(b);
47         }
48         
49         return arr;
50     }
51 }


Astro.Qi 2008-07-10 17:05 发表评论
]]>
վ֩ģ壺 ɫ˿ѹۿվ| ƵƷѹۿ99| AV˾Ʒ| ձվƵ| ޹ŷպƷһ| ޾Ʒ鶹av| 182tvѹۿƵ| ŮƵվ| þþƷ96Ʒ| 鶹VAѾƷ | ŮƵվ| ޳ߵӰ| avƬ߲| þþþþþ99Ʒ| ձ޸߹ۿ| AVһҳƷ| 99reþþƷƷ| þþƷӰѶ| Ƶxxxx| þþþþAVר| Ʒպһ| ߹ۿѴվ| ձ߿Ƭ˳Ƶ1000| Ʒ| ޳ۺӰԺԺ| ޺ݺݰۺӰԺ| ĻѸ| 㻨߹ۿѹۿͼƬ| պƷAV| ۺһƷ| Ļ˿Ʒһ| ëƬѹۿƵ| 97ƵѲ| Ļ߿Ӱȫ| ޸Ʒһ| ۺС˵ͼƬͼ| 91޾ƷƵ| AVרAV԰| þþþù˾Ʒҹ| ѹԺ߹ۿ| Ѹ߹ۿ|