﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Titan专栏-文章分类-Oracle</title><link>http://www.blogjava.net/Titan/category/6104.html</link><description>用文字来整理生命</description><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 03:21:15 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 03:21:15 GMT</pubDate><ttl>60</ttl><item><title>Oracle散记</title><link>http://www.blogjava.net/Titan/articles/24431.html</link><dc:creator>Titan</dc:creator><author>Titan</author><pubDate>Sat, 17 Dec 2005 16:01:00 GMT</pubDate><guid>http://www.blogjava.net/Titan/articles/24431.html</guid><wfw:comment>http://www.blogjava.net/Titan/comments/24431.html</wfw:comment><comments>http://www.blogjava.net/Titan/articles/24431.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Titan/comments/commentRss/24431.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Titan/services/trackbacks/24431.html</trackback:ping><description><![CDATA[<P>一．优化器模式<BR>&nbsp;&nbsp;&nbsp;ORACLE的优化器共有3种:<BR>&nbsp;&nbsp;&nbsp;a.&nbsp;&nbsp;RULE&nbsp;(基于规则)&nbsp;&nbsp;&nbsp;b.&nbsp;COST&nbsp;(基于成本)&nbsp;&nbsp;c.&nbsp;CHOOSE&nbsp;(选择性)<BR>&nbsp;&nbsp;&nbsp;为了使用基于成本的优化器(CBO,&nbsp;Cost-Based&nbsp;Optimizer)&nbsp;,&nbsp;你必须定期更新统计信息，以保证数据库中的对象统计信息(object&nbsp;statistics)的准确性.<BR>&nbsp;&nbsp;&nbsp;如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关.&nbsp;如果table已经被analyze过,&nbsp;优化器模式将自动成为CBO&nbsp;,&nbsp;反之,数据库将采用RULE形式的优化器。<BR><BR>二．访问Table的方式<BR>ORACLE&nbsp;采用两种访问表中记录的方式:<BR>a.&nbsp;&nbsp;全表扫描&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;全表扫描就是顺序地访问表中每条记录.&nbsp;ORACLE采用一次读入多个数 据块(database&nbsp;block)的方式优化全表扫描。<BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>b.&nbsp;&nbsp;索引扫描<BR>&nbsp;&nbsp;&nbsp;你可以采用基于ROWID的访问方式情况,提高访问表的效率,&nbsp;ROWID包含了表中记录的物理位置信息.ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系.&nbsp;通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高.<BR><BR>其中ORACLE对索引又有两种访问模式.<BR>a)索引唯一扫描&nbsp;(&nbsp;INDEX&nbsp;UNIQUE&nbsp;SCAN)<BR>大多数情况下,&nbsp;优化器通过WHERE子句访问INDEX.<BR>例如:<BR>表LOADING有两个索引&nbsp;:&nbsp;建立在LOADING列上的唯一性索引LOADING_PK和建立在MANAGER列上的非唯一性索引IDX_MANAGER.&nbsp;<BR>SELECT&nbsp;loading&nbsp;&nbsp;<BR>FROM&nbsp;LOADING<BR>WHERE&nbsp;LOADING&nbsp;=&nbsp;‘ROSE&nbsp;HILL’;<BR>&nbsp;&nbsp;&nbsp;在内部&nbsp;,&nbsp;上述SQL将被分成两步执行,&nbsp;首先&nbsp;,&nbsp;LOADING_PK&nbsp;索引将通过索引唯一扫描的方式被访问&nbsp;,&nbsp;获得相对应的ROWID,&nbsp;通过ROWID访问表的方式执行下一步检索.<BR>&nbsp;&nbsp;&nbsp;如果被检索返回的列包括在INDEX列中,ORACLE将不执行第二步的处理(通过ROWID访问表).&nbsp;因为检索数据保存在索引中,&nbsp;单单访问索引就可以完全满足查询结果.&nbsp;<BR>&nbsp;&nbsp;&nbsp;下面SQL只需要INDEX&nbsp;UNIQUE&nbsp;SCAN&nbsp;操作.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;LOADING<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM&nbsp;&nbsp;LOADING<BR>WHERE&nbsp;LOADING&nbsp;=&nbsp;‘ROSE&nbsp;HILL’;<BR>&nbsp;<BR>&nbsp;&nbsp;b)索引范围查询(INDEX&nbsp;RANGE&nbsp;SCAN)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;适用于两种情况:<BR>1.&nbsp;基于一个范围的检索<BR>2.&nbsp;基于非唯一性索引的检索<BR>&nbsp;例1:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;LOADING<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM&nbsp;&nbsp;LOADING<BR>WHERE&nbsp;LOADING&nbsp;LIKE&nbsp;‘M%’;<BR>&nbsp;<BR>WHERE子句条件包括一系列值,&nbsp;ORACLE将通过索引范围查询的方式查询LODGING_PK&nbsp;.&nbsp;由于索引范围查询将返回一组值,&nbsp;它的效率就要比索引唯一扫描<BR>低一些.&nbsp;&nbsp;<BR>例2:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;LOADING<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM&nbsp;&nbsp;LOADING<BR>WHERE&nbsp;MANAGER&nbsp;=&nbsp;‘BILL&nbsp;GATES’;<BR>这个SQL的执行分两步,&nbsp;IDX_MANAGER的索引范围查询(得到所有符合条件记录的ROWID)&nbsp;和下一步同过ROWID访问表得到LOADING列的值.&nbsp;由于IDX_MANAGER是一个非唯一性的索引,数据库不能对它执行索引唯一扫描.&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;由于SQL返回LOADING列,而它并不存在于IDX_MANAGER索引中,&nbsp;所以在索引范围查询后会执行一个通过ROWID访问表的操作.&nbsp;<BR>&nbsp;&nbsp;WHERE子句中,&nbsp;如果索引列所对应的值的第一个字符由通配符(WILDCARD)开始,&nbsp;索引将不被采用.<BR>SELECT&nbsp;LOADING<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM&nbsp;&nbsp;LOADING<BR>WHERE&nbsp;MANAGER&nbsp;LIKE&nbsp;‘％HANMAN’;<BR>在这种情况下，ORACLE将使用全表扫描.<BR><BR><BR>三．SQL调优的本质就是调整执行计划。<BR>在好多情况下，oracle自动选择的执行计划并不是最优的，这时需要我们人工去干预。(什么是执行计划?)<BR><BR><BR>对SQL调优基本步骤：<BR>a) 捕获SQL语句<BR>b) 产生SQL语句的执行计划；<BR>c) 验证统计信息(SQL语句涉及到的表格是否做过分析)，表格信息(结果集的记录数，索引)，字段上面数据分布特点<BR>d) 通过手工收集到的信息，形成自己理想的执行计划。<BR>e) 如果做过分析，则重新分析相关表格或者做柱状图分析。<BR>f) 如果没有做过分析，则通过尝试不同的Hint，从而获得合适的执行计划。<BR>g) 当我们正常无法调优到位时，可以打开10053事件打开优化器的跟踪，看看Oracle如何选择的.<BR>alter&nbsp;session&nbsp;set&nbsp;events='10053&nbsp;trace&nbsp;name&nbsp;context&nbsp;forever,level&nbsp;2';<BR><BR>四．如何捕获SQL语句<BR>捕获SQL语句的方法有如下几种：<BR>1．SQL&nbsp;TRACE或10046跟踪某个模块。<BR>2．PERFSTAT性能统计包，使用方法见附录二。<BR>3．V＄SQL，V＄SESSION_WAIT，V＄SQL_TEXT<BR>五．如何查看执行计划<BR>查看SQL语句的执行计划有以下几种：<BR>1．Set&nbsp;autotrace&nbsp;on(set&nbsp;autotrace&nbsp;traceonly&nbsp;exp)<BR>2．Explain&nbsp;plan&nbsp;for&nbsp;…..<BR>@?/rdbms/admin/utlxpls.sql<BR>3．V＄SQL_PLAN视图<BR>column&nbsp;operation&nbsp;format&nbsp;a16&nbsp;<BR>column&nbsp;"Query&nbsp;Plan"&nbsp;format&nbsp;a60&nbsp;<BR>column&nbsp;options&nbsp;format&nbsp;a15&nbsp;<BR>column&nbsp;object_name&nbsp;&nbsp;format&nbsp;a20&nbsp;<BR>column&nbsp;id&nbsp;&nbsp;format&nbsp;99&nbsp;<BR><BR>select&nbsp;id,lpad('&nbsp;',2*(level-1))||operation||'&nbsp;'||options||'&nbsp;'||object_name||'&nbsp;'&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;||decode(id,0,'Cost&nbsp;=&nbsp;'||position)&nbsp;"Query&nbsp;Plan"&nbsp;<BR>from&nbsp;(select&nbsp;*&nbsp;<BR>from&nbsp;v＄sql_plan&nbsp;&nbsp;<BR>where&nbsp;address='&amp;a')&nbsp;sql_plan&nbsp;<BR>start&nbsp;with&nbsp;id&nbsp;=&nbsp;0&nbsp;<BR>connect&nbsp;by&nbsp;prior&nbsp;id&nbsp;=&nbsp;parent_id<BR>/<BR><BR>4．第三方工具，如pl/sql&nbsp;developer,TOAD<BR><BR>六．SQL语句主要的连接方法<BR><BR>a) Nested-loop&nbsp;join<BR>适合于小表(几千条，几万条记录)与大表做联接<BR>在联接列上有索引。<BR><BR>分内表和外表(驱动表)，靠近from子句的是内表。从效率上讲，小表应该作外表，大表应该作内表，即大表查询时走索引。<BR><BR>COST=&nbsp;Access&nbsp;cost&nbsp;of&nbsp;A(驱动表)&nbsp;+&nbsp;(access&nbsp;cost&nbsp;of&nbsp;B&nbsp;*&nbsp;number&nbsp;of&nbsp;rows&nbsp;from&nbsp;A)<BR><BR>成本计算方法：<BR>设小表100行，大表100000行。<BR><BR>两表均有索引：<BR>如果小表在内，大表在外(驱动表)的话，则扫描次数为：<BR>100000+100000*2&nbsp;(其中2表示IO次数，一次索引，一次数据)<BR>如果大表在内，小表在外(驱动表)的话，则扫描次数为：<BR>100+100*2.<BR><BR>两表均无索引：<BR>如果小表在内，大表在外的话，则扫描次数为：<BR>100000+100*100000<BR>如果大表在内，小表在外的话，则扫描次数为：<BR>100+100000*100<BR><BR>注意：如果一个表有索引，一个表没有索引，ORACLE会将没有索引的表作驱动表。如果两个表都有索引，则外表作驱动表。如果两个都没索引的话，则也是外表作驱动表。<BR><BR>基本的执行计划如下所示：<BR>NESTED&nbsp;LOOPS<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;ROWID)&nbsp;&nbsp;OF&nbsp;&nbsp;our_outer_table<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(..SCAN)&nbsp;OF&nbsp;outer_table_index(….)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;ROWID)&nbsp;&nbsp;OF&nbsp;&nbsp;our_inner_table<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(..SCAN)&nbsp;OF&nbsp;inner_table_index(….)<BR><BR>b) Hash&nbsp;join&nbsp;<BR><BR>适合于大表与大表，小表(几十万，几百万)与大表之间的联连。<BR>联接列上不需要索引。<BR><BR>基本执行计划如下：<BR>HASH&nbsp;JOIN<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(….)&nbsp;&nbsp;OF&nbsp;&nbsp;tableA<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(….)&nbsp;&nbsp;OF&nbsp;&nbsp;tableB<BR><BR>cost=&nbsp;(access&nbsp;cost&nbsp;of&nbsp;A&nbsp;*&nbsp;number&nbsp;of&nbsp;hash&nbsp;partitions&nbsp;of&nbsp;B)&nbsp;+&nbsp;access&nbsp;cost&nbsp;of&nbsp;B<BR><BR>可以看出主要成本在于A表是否可以被Cache。Hash_area_size的大小将决定Hash&nbsp;Join的主要成本。可以看出Hash&nbsp;Join的成本和返回集合并没有直接的关系，所以当返回结果集比较大的时候一般具有较好的性能。<BR><BR>为了加快hash&nbsp;join的速度，可以调大hash_area_size和pga_aggregate_target（默认为25M）的值。<BR><BR><BR>c) Sort&nbsp;Merge&nbsp;join<BR><BR>每一个Row&nbsp;Source在Join列上均排序。<BR>然后两个排序后的Row&nbsp;Source合并后，作一个结果集返回。<BR>Sort/Merge&nbsp;Join仅仅对equal&nbsp;Join有效。<BR><BR>基本执行计划<BR>MERGE&nbsp;(JOIN)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SORT&nbsp;(JOIN)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(….)&nbsp;&nbsp;OF&nbsp;&nbsp;tableA<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SORT&nbsp;(JOIN)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(….)&nbsp;&nbsp;OF&nbsp;&nbsp;tableB<BR><BR>cost=&nbsp;access&nbsp;cost&nbsp;of&nbsp;A&nbsp;+&nbsp;access&nbsp;cost&nbsp;of&nbsp;B&nbsp;+(sort&nbsp;cost&nbsp;of&nbsp;A&nbsp;+&nbsp;sort&nbsp;cost&nbsp;of&nbsp;B)<BR><BR>可以看出Sort的成本是Merge&nbsp;Join的主要构成部分。这样sort_area_size的大小将很大程度决定Merge&nbsp;Join的大小。同样如果A表或者B表已经经过排序的，那么Merge&nbsp;Join往往具有很好的性能。其不会走索引。<BR><BR>没有驱动表的概念，即时响应能力较差。<BR><BR><BR><BR>七．一般情况下最常见的5种问题<BR><BR>1.&nbsp;Statement&nbsp;not&nbsp;written&nbsp;for&nbsp;indexes 25%<BR>2.&nbsp;Indexes&nbsp;are&nbsp;missing&nbsp;or&nbsp;inappropriate 16%<BR>3.&nbsp;Use&nbsp;of&nbsp;single-column&nbsp;index&nbsp;merge 15%<BR>4.&nbsp;Misuse&nbsp;of&nbsp;nested&nbsp;loop,&nbsp;sort&nbsp;merge,&nbsp;or&nbsp;hash&nbsp;join 12%<BR>5.&nbsp;Misuse&nbsp;of&nbsp;IN,&nbsp;EXISTS,&nbsp;NOT&nbsp;IN,&nbsp;NOT&nbsp;EXISTS,&nbsp;or&nbsp;table&nbsp;joins 8%<BR><BR>不过在我们这里，最常见的问题是在第2条，第3条，第4条。<BR><BR>1． Statement&nbsp;not&nbsp;written&nbsp;for&nbsp;indexes<BR>类似于这样的：<BR>SELECT&nbsp;account_name,&nbsp;trans_date,&nbsp;amount&nbsp;<BR>FROM&nbsp;transaction&nbsp;<BR>WHERE&nbsp;SUBSTR(account_name,1,7)&nbsp;=&nbsp;'&nbsp;CAPITAL';&nbsp;<BR><BR>WHERE&nbsp;account_name&nbsp;LIKE&nbsp;'CAPITAL%';&nbsp;<BR><BR>Account_date&nbsp;日期<BR><BR>To_char(Account_date,’YYYY-MM-DD:HH24:MI:SS’)=’200508XXX’;<BR><BR>Account_date=to_date(‘200508….’,’yyyy-mm-dd);<BR><BR><BR>2．Indexes&nbsp;are&nbsp;missing&nbsp;or&nbsp;inappropriate<BR><BR>例如REP_C021中有这样一句：<BR>select&nbsp;SUBSIDIARYID,260,'&nbsp;&nbsp;&nbsp;&nbsp;300电话卡',<BR>&nbsp; &nbsp;sum(decode(feetype,&nbsp;1,&nbsp;ceil(duration&nbsp;/&nbsp;60)))&nbsp;+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(decode(feetype,&nbsp;0,&nbsp;ceil(duration&nbsp;/&nbsp;60))),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(decode(feetype,&nbsp;1,&nbsp;ceil(duration&nbsp;/&nbsp;60))),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(decode(feetype,&nbsp;0,&nbsp;ceil(duration&nbsp;/&nbsp;60))),0<BR>&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;cardsusage200508&nbsp;a,&nbsp;service&nbsp;b<BR>&nbsp;&nbsp;&nbsp;where&nbsp;a.caller&nbsp;=&nbsp;b.servicecode&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(b.property&nbsp;=&nbsp;i_property&nbsp;or&nbsp;i_property&nbsp;is&nbsp;null)&nbsp;and&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.cdrtype&nbsp;=&nbsp;102<BR>&nbsp;&nbsp;&nbsp;group&nbsp;by&nbsp;SUBSIDIARYID,&nbsp;260,&nbsp;'&nbsp;&nbsp;&nbsp;&nbsp;300电话卡';<BR><BR>Execution&nbsp;Plan<BR>----------------------------------------------------------<BR>&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;STATEMENT&nbsp;Optimizer=RULE<BR>&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;SORT&nbsp;(GROUP&nbsp;BY)<BR>&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS<BR>&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(FULL)&nbsp;OF&nbsp;'CARDSUSAGE200508'<BR>&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'SERVICE'<BR>&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(UNIQUE&nbsp;SCAN)&nbsp;OF&nbsp;'SERVICE_CODE'<BR><BR>我们取其中的select语句进行调优。在调整之前，原select语句需要6分钟左右。<BR><BR>12:19:20&nbsp;SQL&gt;&nbsp;select&nbsp;cdrtype,count(*)&nbsp;from&nbsp;cardsusage200508<BR>12:20:12&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;group&nbsp;by&nbsp;cdrtype;<BR><BR>CDRT&nbsp;&nbsp;&nbsp;COUNT(*)<BR>----&nbsp;----------<BR>102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;637<BR>106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1973757<BR>107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2390097<BR>112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;46016<BR>113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;20<BR><BR>针对cardsuage200508表格的特性，我们在CDRTYPE字段上建立一个位图索引CARDSUSAGE_CDRTYPE_BTIDX。<BR>将SQL语句加上以下Hint：<BR>&nbsp;&nbsp;select&nbsp;/*+&nbsp;&nbsp;INDEX(A,&nbsp;CARDSUSAGE_CDRTYPE_BTIDX)*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBSIDIARYID,260,'&nbsp;&nbsp;&nbsp;&nbsp;300电话卡',<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(decode(feetype,&nbsp;1,&nbsp;ceil(duration&nbsp;/&nbsp;60)))&nbsp;+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(decode(feetype,&nbsp;0,&nbsp;ceil(duration&nbsp;/&nbsp;60))),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(decode(feetype,&nbsp;1,&nbsp;ceil(duration&nbsp;/&nbsp;60))),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(decode(feetype,&nbsp;0,&nbsp;ceil(duration&nbsp;/&nbsp;60))),0<BR>&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;cardsusage200508&nbsp;&nbsp;a,&nbsp;service&nbsp;b<BR>&nbsp;&nbsp;&nbsp;where&nbsp;a.caller&nbsp;=&nbsp;b.servicecode&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(b.property&nbsp;=&nbsp;i_property&nbsp;or&nbsp;i_property&nbsp;is&nbsp;null)&nbsp;and&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.cdrtype&nbsp;=&nbsp;102<BR>&nbsp;&nbsp;&nbsp;group&nbsp;by&nbsp;SUBSIDIARYID,&nbsp;260,&nbsp;'&nbsp;&nbsp;&nbsp;&nbsp;300电话卡';<BR>这样调整后，只需要几秒钟即可出来。<BR><BR>3.&nbsp;&nbsp;Use&nbsp;of&nbsp;single-column&nbsp;index&nbsp;merge<BR>复合索引有的时候比单列索引效率更高。根据where子句中的具体情况，有 时可以建立复合索引。例如：<BR>&nbsp;select&nbsp;a.AccountNum,a.ChargeID,a.Total,b.ItemID,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.Amount,c.billingcycle<BR>&nbsp;&nbsp;from&nbsp;charge_bill&nbsp;a,&nbsp;chargedetail_bill&nbsp;b,&nbsp;Account&nbsp;c<BR>&nbsp;where&nbsp;a.AccountNum&nbsp;&gt;&nbsp;1&nbsp;and&nbsp;a.AccountNum&nbsp;&lt;=&nbsp;1969618&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.status&nbsp;=&nbsp;'0'&nbsp;and&nbsp;a.InvoiceID&nbsp;is&nbsp;null&nbsp;and&nbsp;c.paymentmethod&nbsp;!=&nbsp;'7'&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.Total&nbsp;&gt;&nbsp;0&nbsp;and&nbsp;a.AccountNum&nbsp;=&nbsp;c.AccountNum&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.ChargeID&nbsp;=&nbsp;b.ChargeID<BR>&nbsp;order&nbsp;by&nbsp;a.AccountNum,&nbsp;a.ChargeID,&nbsp;b.ItemID;<BR>这样的SQL语句执行需要3分27秒。<BR><BR>我们做了以下优化：<BR>在charge_bill表格的accountnum,status,total,invoiceid列上建立一个复合索引。这样上述SQL语句需要40秒左右。<BR><BR>Resume&nbsp;Service过程中有这么一句：<BR>SELECT&nbsp;NVL(SUM(A.FEE),0)&nbsp;&nbsp;&nbsp;<BR>FROM&nbsp;ACCOUNTBALANCE&nbsp;A,INVOICE&nbsp;B&nbsp;&nbsp;<BR>WHERE&nbsp;A.OBJECTID&nbsp;=&nbsp;B.INVOICEID&nbsp;&nbsp;AND&nbsp;A.ACCOUNTNUM&nbsp;=&nbsp;:b1&nbsp;<BR>AND&nbsp;B.BILLINGBEGINDATE&nbsp;&lt;&nbsp;TO_DATE(:b2,'yyyymmdd');<BR>该语句需要执行大概72000次。整个过程执行大概需要100分钟左右。<BR><BR>将:b1以具体的值代替，这条SQL语句执行很快，大概0.1秒左右。<BR><BR>我们做了以下优化：<BR>在invoiceid,billingbegindate列上创建了一个索引idx_invoice_hc。<BR>将上述SQL语句改成：<BR>select&nbsp;/*+&nbsp;use_nl(a,b)&nbsp;index(b,IDX_INVOICE_HC)*/&nbsp;&nbsp;nvl(sum(a.fee),0)<BR>from&nbsp;accountbalance&nbsp;a,invoice&nbsp;b<BR>where&nbsp;a.objectid=b.invoiceid&nbsp;&nbsp;and&nbsp;a.accountnum=m_accountnum<BR>and&nbsp;b.billingbegindate&lt;to_date(m_date,'yyyymmdd');<BR><BR>这样一来，该过程的执行时间快的时候大概在10分钟左右，慢的时候(IO异常紧张的时)大概在30分钟左右。<BR><BR><BR>4. Misuse&nbsp;of&nbsp;nested&nbsp;loop,&nbsp;sort&nbsp;merge,&nbsp;or&nbsp;hash&nbsp;join<BR>表格之间的连接方式和连接顺序都将极大的影响SQL语句的性能。这种问 题在平时最常见。ORACLE在处理5张或5张以上的表格的连接时候，很容 易出问题。一般情况下，谨记前面表格之间的连接原则，即可以处理此类问 题。<BR><BR>&nbsp;&nbsp;&nbsp;例如：<BR>select&nbsp;b.SUBSIDIARYID,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c.paymentmethod&nbsp;||&nbsp;':'&nbsp;||&nbsp;nvl(subscribertype,&nbsp;'9999999'),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'gsm',count(*),sum(decode(untelLOCALCHARGE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0,decode(duration,0,1,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decode(sign(duration&nbsp;-&nbsp;1800),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1,&nbsp;2&nbsp;+&nbsp;trunc((duration&nbsp;-&nbsp;1201)&nbsp;/&nbsp;600),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)),&nbsp;trunc((duration&nbsp;+&nbsp;599)&nbsp;/&nbsp;600))),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum(nvl(GSMCHARGE,&nbsp;0)),nvl(property,&nbsp;'0'),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUM(trunc((duration&nbsp;+&nbsp;599)&nbsp;/&nbsp;600))<BR>&nbsp;&nbsp;from&nbsp;&nbsp;rt_untelecomusage&nbsp;a&nbsp;,service&nbsp;b,&nbsp;account&nbsp;c&nbsp;<BR>&nbsp;where&nbsp;a.starttime&nbsp;&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to_date(to_char(add_months(to_date('200508&nbsp;',&nbsp;'YYYYMM'),&nbsp;-1),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'YYYYMM')&nbsp;||&nbsp;'20235959',<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'YYYYMMDDHH24MISS')&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.starttime&nbsp;&lt;&nbsp;to_date('200508&nbsp;'&nbsp;||&nbsp;'21',&nbsp;'YYYYMMdd')&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gsmcharge&nbsp;&gt;&nbsp;0&nbsp;and&nbsp;a.serviceid&nbsp;=&nbsp;b.serviceid&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.accountnum&nbsp;=&nbsp;c.accountnum<BR>&nbsp;group&nbsp;by&nbsp;b.SUBSIDIARYID,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c.paymentmethod&nbsp;||&nbsp;':'&nbsp;||&nbsp;nvl(subscribertype,&nbsp;'9999999'),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'gsm',nvl(property,&nbsp;'0');&nbsp;<BR>该语句原先需要4，5个小时左右。<BR><BR>优化：<BR>alter&nbsp;session&nbsp;set&nbsp;hash_area_size=300000000;<BR><BR>select&nbsp;/*+&nbsp;use_hash(b,c)&nbsp;ordered&nbsp;NO_EXPAND&nbsp;full(a)&nbsp;use_hash(a)*/&nbsp;&nbsp;b.SUBSIDIARYID,c.paymentmethod&nbsp;||&nbsp;':'&nbsp;||&nbsp;nvl(subscribertype,&nbsp;'9999999'),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'gsm',count(*),&nbsp;sum(decode(untelLOCALCHARGE,0,decode(duration,0,&nbsp;1,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;decode(sign(duration&nbsp;-&nbsp;1800),&nbsp;1,2&nbsp;+&nbsp;trunc((duration&nbsp;-&nbsp;1201)&nbsp;/&nbsp;600),&nbsp;2)),<BR>&nbsp;&nbsp;&nbsp;&nbsp; trunc((duration&nbsp;+&nbsp;599)&nbsp;/&nbsp;600))),sum(nvl(GSMCHARGE,&nbsp;0)),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nvl(property,&nbsp;'0'),SUM(trunc((duration&nbsp;+&nbsp;599)&nbsp;/&nbsp;600))<BR>&nbsp;&nbsp;from&nbsp;service&nbsp;b,&nbsp;account&nbsp;c,untelecomusage_200508&nbsp;&nbsp;a&nbsp;<BR>&nbsp;where&nbsp;a.starttime&nbsp;&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to_date(to_char(add_months(to_date('200508',&nbsp;'YYYYMM'),&nbsp;-1),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'YYYYMM')&nbsp;||&nbsp;'20235959',<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'YYYYMMDDHH24MISS')&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.starttime&nbsp;&lt;&nbsp;to_date('200508'&nbsp;||&nbsp;'21',&nbsp;'YYYYMMdd')&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gsmcharge&nbsp;&gt;&nbsp;0&nbsp;and&nbsp;a.serviceid&nbsp;=&nbsp;b.serviceid&nbsp;and<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.accountnum&nbsp;=&nbsp;c.accountnum<BR>&nbsp;group&nbsp;by&nbsp;b.SUBSIDIARYID,c.paymentmethod&nbsp;||&nbsp;':'&nbsp;||&nbsp;nvl(subscribertype,&nbsp;'9999999'),'gsm',nvl(property,&nbsp;'0');&nbsp;&nbsp;<BR><BR>这样优化后，只需要40分钟左右即可。<BR><BR>八．案例<BR>1． 循环Update操作<BR><BR>&nbsp;&nbsp;以下过程太慢了，&nbsp;半个小时连5000条记录都未处理，总&nbsp;共有7万多条。<BR>declare<BR>&nbsp;&nbsp;&nbsp;&nbsp;cursor&nbsp;c1&nbsp;is&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;select&nbsp;caller&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;zxx_sms_step&nbsp;where&nbsp;chargemonth=200504&nbsp;and&nbsp;fee&nbsp;is&nbsp;null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;icnt&nbsp;number;<BR>begin<BR>icnt:=0;<BR>for&nbsp;m_c1&nbsp;in&nbsp;c1&nbsp;loop<BR>update&nbsp;zxx_sms_step&nbsp;a&nbsp;set&nbsp;fee=<BR>(select&nbsp;nvl(sum(pascharge),0)&nbsp;from&nbsp;ipasimport_200504&nbsp;where&nbsp;caller=m_c1.caller&nbsp;and&nbsp;pastag&nbsp;in&nbsp;(1243,1251))<BR>where&nbsp;caller=m_c1.caller&nbsp;and&nbsp;chargemonth=200504;<BR>icnt:=icnt+1;<BR>if&nbsp;icnt=500&nbsp;then<BR>exit; <BR>end&nbsp;if;<BR>end&nbsp;loop;<BR>end;<BR><BR>&nbsp;&nbsp;&nbsp;这样的SQL语句，建议先将update中的子查询生成一张中间表，然后再update。<BR>alter&nbsp;session&nbsp;set&nbsp;hash_area_size=400000000&nbsp;;<BR><BR>select&nbsp;/*+use_hash(a,b)*/&nbsp;b.caller,nvl(sum(a.pascharge),0)&nbsp;from&nbsp;ipasimport_200504&nbsp;a,zxx_sms_step&nbsp;b&nbsp;<BR>where&nbsp;b.chargemonth=200504&nbsp;and&nbsp;b.fee&nbsp;is&nbsp;null&nbsp;<BR>and&nbsp;a.caller=b.caller&nbsp;and&nbsp;a.pastag&nbsp;in&nbsp;(1243,1251)&nbsp;<BR>group&nbsp;by&nbsp;b.caller;<BR>&nbsp;这样10分钟不到就可产生中间表，然后再update只需几分钟即可。<BR><BR><BR>2． 部分表格未做统计信息分析<BR><BR>网通OA系统自从oracle服务器从pc服务器上迁到小型机上后，其CPU利用率经常冲到很高。而其中每一个进程在某个瞬间将占用40%左右的CPU。这些进程都是通过jdbc&nbsp;thin&nbsp;client&nbsp;连过来的。<BR><BR>通过抓取其sql_text，发现以下两条SQL语句不正常。<BR>1.<BR>&nbsp;SQL&gt;&nbsp;&nbsp;select&nbsp;D.flow_inid,D.step_inco,D.deal_man,D.agen_men,D.time_set,D.peri_man,<BR>&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;S2.fsub_set,S2.fsub_id,F.mtbl_stru,F.doc_name,F.svr_name&nbsp;<BR>&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;from&nbsp;deal_info&nbsp;D,step_inst&nbsp;S1,step_def&nbsp;S2,flow_inst&nbsp;F&nbsp;<BR>&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;where&nbsp;D.step_inco=S1.step_inco&nbsp;and&nbsp;S1.flow_id=S2.flow_id&nbsp;<BR>&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;and&nbsp;S1.step_code=S2.step_code&nbsp;and&nbsp;S1.flow_inid=F.flow_inid&nbsp;and&nbsp;D.step_type=5<BR>&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;and&nbsp;D.fsub_flag&nbsp;is&nbsp;not&nbsp;null&nbsp;and&nbsp;D.fsub_flag=1&nbsp;and&nbsp;rownum&lt;=1;<BR><BR>其执行计划和统计信息如下：<BR><BR>Execution&nbsp;Plan<BR>----------------------------------------------------------<BR>&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;STATEMENT&nbsp;Optimizer=CHOOSE&nbsp;(Cost=22&nbsp;Card=1&nbsp;Bytes=1077)<BR>&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;COUNT&nbsp;(STOPKEY)<BR>&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS&nbsp;(Cost=22&nbsp;Card=1&nbsp;Bytes=1077)<BR>&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS&nbsp;(Cost=21&nbsp;Card=1&nbsp;Bytes=360)<BR>&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS&nbsp;(Cost=20&nbsp;Card=1&nbsp;Bytes=150)<BR>&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(FULL)&nbsp;OF&nbsp;'STEP_INST'&nbsp;(Cost=2&nbsp;Card=9&nbsp;&nbsp;Bytes=153)<BR>&nbsp;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'DEAL_INFO'&nbsp;(Cost=2&nbsp;Card=1&nbsp;Bytes=133)<BR>&nbsp;&nbsp;&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(RANGE&nbsp;SCAN)&nbsp;OF&nbsp;'DEAL_INFO_STEP_INCO'&nbsp;(NON-UNIQUE)&nbsp;(Cost=2&nbsp;<BR>&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'FLOW_INST'&nbsp;(Cost=1&nbsp;Card=1&nbsp;Bytes=210)<BR>&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(UNIQUE&nbsp;SCAN)&nbsp;OF&nbsp;'PK_FLOW_INST'&nbsp;(UNIQUE)<BR>&nbsp;&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'STEP_DEF'&nbsp;(Cost=1&nbsp;Card=1&nbsp;Bytes=717)<BR>&nbsp;&nbsp;11&nbsp;&nbsp;&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(UNIQUE&nbsp;SCAN)&nbsp;OF&nbsp;'STEP_DEF_PK11119358638593'&nbsp;(UNIQUE)<BR><BR>Statistics<BR>----------------------------------------------------------<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;recursive&nbsp;calls<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;db&nbsp;block&nbsp;gets<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;270626&nbsp;&nbsp;consistent&nbsp;gets<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;273&nbsp;&nbsp;physical&nbsp;reads<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;redo&nbsp;size<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1079&nbsp;&nbsp;bytes&nbsp;sent&nbsp;via&nbsp;SQL*Net&nbsp;to&nbsp;client<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;655&nbsp;&nbsp;bytes&nbsp;received&nbsp;via&nbsp;SQL*Net&nbsp;from&nbsp;client<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;SQL*Net&nbsp;roundtrips&nbsp;to/from&nbsp;client<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;sorts&nbsp;(memory)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;sorts&nbsp;(disk)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;rows&nbsp;processed<BR><BR>这条SQL语句执行的时间也不长，就几秒钟，但是我们看到consistent&nbsp;gets很高有27万多，这个操作就是消耗CPU的祸首。从执行计划来看，其执行计划显然不可理，问题出在表格的连接顺序上面，应该是deal_info表格做为驱动表先访问。<BR><BR>检查这些表格的统计分析，发现step_def表格未做分析，对该表格做统计信息分析，并对deal_info表做柱状图分析后：<BR>analyze&nbsp;table&nbsp;deal_info&nbsp;compute&nbsp;statistics&nbsp;for&nbsp;all&nbsp;indexed&nbsp;columns;<BR><BR>其执行计划正是我们所想要的，同时consistent&nbsp;gets也只有200左右，该操作所消耗的CPU也下降到了1%。<BR><BR>2.表格的柱状图信息没有分析：<BR>SELECT&nbsp;SO.SO_NBR,&nbsp;so_type.name,STATUS.STS_WORDS,&nbsp;SO.REMARKS,&nbsp;SO.CHECK_TYPE,CTRL_ASGN.DISPATCHED_DATE,&nbsp;<BR>CTRL_ASGN.PRE_ALARM_DATE,&nbsp;CTRL_ASGN.ALARM_DATE<BR>from&nbsp;SO,SO_HANDLE,&nbsp;CTRL_ASGN,so_type,status&nbsp;<BR>WHERE SO_HANDLE.SO_NBR=SO.SO_NBR&nbsp;AND&nbsp;SO.SO_NBR=CTRL_ASGN.SO_NBR&nbsp;<BR>AND&nbsp;SO_HANDLE.HANDLE_TYPE_ID=1017<BR>and&nbsp;so.so_type_id=so_type.so_type_id&nbsp;and&nbsp;so.PRIORITY=status.sts_id&nbsp;and&nbsp;status.table_name='SO'<BR>&nbsp;AND&nbsp;STATUS.column_name&nbsp;='PRIORITY'&nbsp;AND&nbsp;SO_HANDLE.WORK_AREA_ID=&nbsp;300101<BR>AND&nbsp;SO.STATE=&nbsp;'B'&nbsp;AND&nbsp;SO.HALT&nbsp;='N'<BR>AND&nbsp;CTRL_ASGN.STATE&nbsp;=&nbsp;'B'<BR>AND&nbsp;CTRL_ASGN.STS&nbsp;=&nbsp;'D';<BR><BR>该SQL语句执行时间要2分钟左右。<BR>执行计划如下：<BR>Execution&nbsp;Plan<BR>----------------------------------------------------------<BR>&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;STATEMENT&nbsp;Optimizer=HINT:&nbsp;RULE<BR>&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS<BR>&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS<BR>&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS<BR>&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS<BR>&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'STATUS'<BR>&nbsp;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(RANGE&nbsp;SCAN)&nbsp;OF&nbsp;'PK_STATUS'&nbsp;(UNIQUE)<BR>&nbsp;&nbsp;&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'CTRL_ASGN'<BR>&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(RANGE&nbsp;SCAN)&nbsp;OF&nbsp;'CTRL_ASGN_0002'<BR>&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'SO'<BR>&nbsp;&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(UNIQUE&nbsp;SCAN)&nbsp;OF&nbsp;'PK_SO'&nbsp;(UNIQUE)<BR>&nbsp;&nbsp;11&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'SO_TYPE'<BR>&nbsp;&nbsp;12&nbsp;&nbsp;&nbsp;11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(UNIQUE&nbsp;SCAN)&nbsp;OF&nbsp;'PK_SO_TYPE'&nbsp;(UNIQUE)<BR>&nbsp;&nbsp;13&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'SO_HANDLE'<BR>&nbsp;&nbsp;14&nbsp;&nbsp;&nbsp;13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(RANGE&nbsp;SCAN)&nbsp;OF&nbsp;'PK_SO_HANDLE'&nbsp;(UNIQUE)<BR><BR>我们收集表格信息和结果集的信息:<BR>SQL&gt;&nbsp;select&nbsp;count(*)&nbsp;from&nbsp;CTRL_ASGN;<BR>&nbsp;&nbsp;COUNT(*)<BR>----------<BR>&nbsp;&nbsp;&nbsp;1832469<BR>SQL&gt;&nbsp;select&nbsp;count(*)&nbsp;from&nbsp;status;<BR>&nbsp;&nbsp;COUNT(*)<BR>----------<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1718<BR><BR>SQL&gt;&nbsp;select&nbsp;count(*)&nbsp;from&nbsp;so;<BR>&nbsp;&nbsp;COUNT(*)<BR>----------<BR>&nbsp;&nbsp;&nbsp;&nbsp;300296<BR><BR>SQL&gt;&nbsp;select&nbsp;count(*)&nbsp;from&nbsp;so_type;<BR>&nbsp;&nbsp;COUNT(*)<BR>----------<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;265<BR><BR>SQL&gt;&nbsp;select&nbsp;count(*)&nbsp;from&nbsp;so_handle;<BR>&nbsp;&nbsp;COUNT(*)<BR>----------<BR>&nbsp;&nbsp;&nbsp;1296263&nbsp;&nbsp;&nbsp;<BR><BR>select&nbsp;count(*)&nbsp;from&nbsp;ctrl_asgn&nbsp;where&nbsp;&nbsp;CTRL_ASGN.STATE&nbsp;=&nbsp;'B'&nbsp;AND&nbsp;CTRL_ASGN.STS&nbsp;=&nbsp;'D';<BR>&nbsp;&nbsp;COUNT(*)<BR>----------<BR>&nbsp;&nbsp;&nbsp;&nbsp;331490<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>select&nbsp;count(*)&nbsp;from&nbsp;so&nbsp;where&nbsp;SO.STATE=&nbsp;'B'&nbsp;AND&nbsp;SO.HALT&nbsp;='N';<BR>&nbsp;&nbsp;COUNT(*)<BR>----------<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;361<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>select&nbsp;count(*)&nbsp;from&nbsp;so_handle&nbsp;where&nbsp;SO_HANDLE.HANDLE_TYPE_ID=1017&nbsp;and&nbsp;SO_HANDLE.WORK_AREA_ID=&nbsp;300101;<BR>&nbsp;&nbsp;COUNT(*)<BR>----------<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;30086<BR><BR>通过对上面这些信息进行分析，我们可以发现这个问题也可以归结为表格之间的连接顺序上面。通过将SO表做柱状图分析后，该SQL语句只需1秒钟即可出来。<BR>Analyze&nbsp;table&nbsp;so&nbsp;compute&nbsp;statistics&nbsp;for&nbsp;all&nbsp;indexed&nbsp;columns;<BR><BR>执行计划变成如下：<BR>Execution&nbsp;Plan<BR>----------------------------------------------------------<BR>&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;STATEMENT&nbsp;Optimizer=CHOOSE&nbsp;(Cost=273&nbsp;Card=32&nbsp;Bytes=3936)<BR>&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS&nbsp;(Cost=273&nbsp;Card=32&nbsp;Bytes=3936)<BR>&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS&nbsp;(Cost=153&nbsp;Card=30&nbsp;Bytes=2730)<BR>&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HASH&nbsp;JOIN&nbsp;(Cost=33&nbsp;Card=30&nbsp;Bytes=2130)<BR>&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NESTED&nbsp;LOOPS&nbsp;(Cost=31&nbsp;Card=30&nbsp;Bytes=1620)<BR>&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(FULL)&nbsp;OF&nbsp;'STATUS'&nbsp;(Cost=2&nbsp;Card=1&nbsp;Bytes=25)<BR>&nbsp;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'SO'&nbsp;(Cost=29&nbsp;Card=59&nbsp;Bytes=1711)<BR>&nbsp;&nbsp;&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(RANGE&nbsp;SCAN)&nbsp;OF&nbsp;'SO_0003'&nbsp;(NON-UNIQUE)&nbsp;(Cost=2&nbsp;Card=59)<BR>&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(FULL)&nbsp;OF&nbsp;'SO_TYPE'&nbsp;(Cost=1&nbsp;Card=128&nbsp;Bytes=2176)<BR>&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'SO_HANDLE'&nbsp;(Cost=4&nbsp;Card=280&nbsp;Bytes=5600)<BR>&nbsp;&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(RANGE&nbsp;SCAN)&nbsp;OF&nbsp;'PK_SO_HANDLE'&nbsp;(UNIQUE)&nbsp;(Cost=3&nbsp;Card=280)<BR>&nbsp;&nbsp;11&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX&nbsp;ROWID)&nbsp;OF&nbsp;'CTRL_ASGN'&nbsp;(Cost=4&nbsp;Card=13620&nbsp;Bytes=435840)<BR>&nbsp;&nbsp;12&nbsp;&nbsp;&nbsp;11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(RANGE&nbsp;SCAN)&nbsp;OF&nbsp;'CTRL_ASGN_0003'&nbsp;(NON-UNIQUE)&nbsp;(Cost=2&nbsp;Card=13620)<BR><BR><BR><BR>3． Not&nbsp;exists的使用<BR>--停机保号用户数(除欠费)<BR>select&nbsp;'XJ'||1||'180','停机保号用户数',count(distinct&nbsp;serviceid),1,'200509',groupid&nbsp;from&nbsp;cbq_lch_usage0&nbsp;<BR>where&nbsp;subsidiaryid=1&nbsp;and&nbsp;subid&lt;&gt;'02'&nbsp;&nbsp;and&nbsp;subid&lt;&gt;'06'&nbsp;and&nbsp;status='7'&nbsp;and&nbsp;<BR>serviceid&nbsp;not&nbsp;in&nbsp;(select&nbsp;serviceorderid&nbsp;from&nbsp;cbq_qf_usage1&nbsp;&nbsp;where&nbsp;status&lt;&gt;'3'&nbsp;and&nbsp;status&nbsp;&lt;&gt;&nbsp;'8')&nbsp;<BR>group&nbsp;by&nbsp;'XJ'||1||'180','停机保号用户数',1,'200509',groupid&nbsp;;<BR><BR>Execution&nbsp;Plan<BR>----------------------------------------------------------<BR>&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;STATEMENT&nbsp;Optimizer=RULE<BR>&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;SORT&nbsp;(GROUP&nbsp;BY)<BR>&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILTER<BR>&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(FULL)&nbsp;OF&nbsp;'CBQ_LCH_USAGE0'<BR>&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(FULL)&nbsp;OF&nbsp;'CBQ_QF_USAGE1'<BR><BR>Elapsed:&nbsp;13:48:26.85<BR><BR>调整：<BR>not&nbsp;in&nbsp;改成not&nbsp;exists<BR>create&nbsp;index&nbsp;idx_serviceorderid&nbsp;on&nbsp;cbq_qf_usage1(serviceorderid)&nbsp;nologging;<BR><BR>select&nbsp;'XJ'||1||'180','停机保号用户数',count(distinct&nbsp;serviceid),1,'200509',a.groupid&nbsp;<BR>from&nbsp;cbq_lch_usage0&nbsp;a<BR>where&nbsp;a.subsidiaryid=1&nbsp;and&nbsp;a.subid&lt;&gt;'02'&nbsp;&nbsp;and&nbsp;a.subid&lt;&gt;'06'&nbsp;and&nbsp;a.status='7'&nbsp;<BR>and&nbsp;not&nbsp;exists(select&nbsp;1&nbsp;from&nbsp;cbq_qf_usage1&nbsp;b&nbsp;where&nbsp;status&lt;&gt;'3'&nbsp;and&nbsp;status&lt;&gt;'8'&nbsp;and&nbsp;a.serviceid=b.serviceorderid)<BR>group&nbsp;by&nbsp;'XJ'||1||'180','停机保号用户数',1,'200509',a.groupid;<BR><BR>Execution&nbsp;Plan<BR>----------------------------------------------------------<BR>&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT&nbsp;STATEMENT&nbsp;Optimizer=RULE<BR>&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;SORT&nbsp;(GROUP&nbsp;BY)<BR>&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILTER<BR>&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(FULL)&nbsp;OF&nbsp;'CBQ_LCH_USAGE0'<BR>&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TABLE&nbsp;ACCESS&nbsp;(BY&nbsp;INDEX)&nbsp;OF&nbsp;'CBQ_QF_USAGE1'<BR>&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INDEX&nbsp;(RANGE&nbsp;SCAN)&nbsp;OF&nbsp;'IDX_SERVICEORDERID'&nbsp;<BR><BR>Elapsed:&nbsp;00:00:01.36<BR><BR><BR>九．其他<BR>1．SELECT子句中避免使用&nbsp;‘&nbsp;*&nbsp;‘<BR>当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用&nbsp;‘*’&nbsp;是一个方便的方法.不幸的是,这是一个非常低效的方法.&nbsp;实际上,ORACLE在解析的过程中,&nbsp;会将’*’&nbsp;依次转换成所有的列名,&nbsp;这个工作是通过查询数据字典完成的,&nbsp;这意味着将耗费更多的时间.&nbsp;<BR>2．用TRUNCATE替代DELETE<BR>3．使用表的别名(Alias)<BR>当在SQL语句中连接多个表时,&nbsp;请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.<BR><BR><BR>4.索引的等级<BR>一般情况索引等级如下：<BR>a)&nbsp;等式比较比范围比较要高。<BR>b)&nbsp;唯一性索引比非唯一性索引要高。<BR>c)&nbsp;一般情况下单列索引等级要比复合索引高，但如果where子句中包含所 有复合索引的字段，则复合索引等级高。<BR>例如：<BR>SELECT&nbsp;col1,&nbsp;...&nbsp;<BR>FROM&nbsp;emp&nbsp;<BR>WHERE&nbsp;emp_name&nbsp;=&nbsp;'GURRY'&nbsp;<BR>AND&nbsp;emp_no&nbsp;=&nbsp;127&nbsp;<BR>AND&nbsp;dept_no&nbsp;=&nbsp;12&nbsp;<BR><BR>Index1&nbsp;(emp_name)&nbsp;<BR>Index2&nbsp;(emp_no,&nbsp;dept_no,&nbsp;emp_name)&nbsp;<BR>ORACLE将使用索引Index2。<BR><BR>5.统计信息分析<BR>在现实当中，有关analyze分析有以下两种误区：<BR><BR>a)&nbsp;只要对主要的或者关键的表格做分析即可。其实正确的应该是需要对所有涉及到的表格都做过分析。<BR><BR>b)&nbsp;做一次分析后即可高枕无忧。事实上，一旦做过分析后，就应该定期更新这些统计信息，以保证统计信息的正确性。<BR><BR>6．Exists总比In快<BR>有许多人认为用Exists总比用In要快,这也是一个误区。有时用in反而比用Exists快。<BR>他们之间的区别如下：<BR>IN&nbsp;subquery，首先执行subquery，由subquery来驱动父查询。而Exists子查询则由父查询来驱动子查询。这就是两者之间的区别。<BR>所以如果子查询小的话，则可以采用in会快一些，如果子查询大的话，则采用exists会快一些。<BR><BR>7．&gt;与&gt;=<BR>大于或小于操作符一般情况下是不用调整的，因为它有索引就会采用索引查找，但有的情况下可以对它进行优化，如一个表有100万记录，一个数值型字段A，<BR>30万记录的A=0，30万记录的A=1，39万记录的A=2，1万记录的A=3。<BR>那么执行A&gt;2与A&gt;=3的效果就有很大的区别了，因为A&gt;2时ORACLE会先找出<BR>为2的记录索引再进行比较，而A&gt;=3时ORACLE则直接找到=3的记录索引。<BR><BR>8.&nbsp;使用索引来避免排序<BR>&nbsp;&nbsp;索引是排好序的，在某些情况下可以使用索引来避免排序。<BR>&nbsp;&nbsp;SELECT&nbsp;acc_name, acc_surname<BR>&nbsp;&nbsp;FROM&nbsp;account&nbsp;acct<BR>&nbsp;&nbsp;ORDER&nbsp;BY&nbsp;1;<BR><BR>&nbsp;&nbsp;SELECT&nbsp;/*+&nbsp;INDEX_ASC(acct&nbsp;acc_ndx1)&nbsp;*/&nbsp;acc_name,acc_surname<BR>&nbsp;&nbsp;FROM&nbsp;account&nbsp;acct;<BR><BR><BR>9.大对象操作<BR><BR>a)Big&nbsp;Insert<BR>(1)direct&nbsp;insert(serial&nbsp;and&nbsp;parallel)&nbsp;<BR>insert&nbsp;/*+append*/into&nbsp;tab1&nbsp;select&nbsp;*&nbsp;from&nbsp;tab2;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Insert&nbsp;/*+append&nbsp;parallel(emp,8)*/&nbsp;into&nbsp;emp&nbsp;&nbsp;select&nbsp;*&nbsp;from&nbsp;emp_bak;<BR>(2)nologging<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insert&nbsp;into&nbsp;tab1&nbsp;nologging&nbsp;select&nbsp;*&nbsp;from&nbsp;tab2;<BR>&nbsp;&nbsp;&nbsp;&nbsp;(3)Large&nbsp;extent&nbsp;size<BR>&nbsp;&nbsp;&nbsp; 更大的extent可以获得更好的insert性能。<BR>&nbsp;(5)Large&nbsp;rollback&nbsp;segment<BR><BR>b)Large&nbsp;Index&nbsp;Create<BR>&nbsp;&nbsp;大的索引extent&nbsp;size值<BR>&nbsp; &nbsp;&nbsp;大的Sort_area_size值<BR>&nbsp;&nbsp;采用nologging<BR>&nbsp;&nbsp;采用parallel&nbsp;<BR>&nbsp;&nbsp;大的临时表空间<BR><BR>alter&nbsp;session&nbsp;sort_area_size=100000000;<BR>create&nbsp;index&nbsp;xxx&nbsp;on&nbsp;aa(ab)&nbsp;nologging&nbsp;parallel&nbsp;2;<BR><BR>&nbsp;c)Large&nbsp;Delete<BR>分几次delete。<BR><BR><BR><BR><BR><BR><BR>附录一<BR>Hint全集<BR>174.&nbsp;/*+ALL_ROWS*/<BR><BR>　　表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化.例如:<BR>SELECT&nbsp;/*+ALL+_ROWS*/&nbsp;EMP_NO,EMP_NAM,DAT_IN&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;EMP_NO='CCBZZP';<BR><BR>　　175.&nbsp;/*+FIRST_ROWS*/<BR><BR>　　表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化.例如:<BR>SELECT&nbsp;/*+FIRST_ROWS*/&nbsp;EMP_NO,EMP_NAM,DAT_IN&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;EMP_NO='CCBZZP';<BR><BR>　　176.&nbsp;/*+CHOOSE*/<BR><BR>　　表明如果数据字典中有访问表的统计信息,将基于开销的优化方法,并获得最佳的吞吐量;表明如果数据字典中没有访问表的统计信息,将基于规则开销的优化方法;例如:<BR>SELECT&nbsp;/*+CHOOSE*/&nbsp;EMP_NO,EMP_NAM,DAT_IN&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;EMP_NO='CCBZZP';<BR><BR>　　177.&nbsp;/*+&nbsp;RULE*/<BR><BR>　　表明对语句块选择基于规则的优化方法.例如:<BR>SELECT&nbsp;/*+&nbsp;RULE&nbsp;*/&nbsp;EMP_NO,EMP_NAM,DAT_IN&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;EMP_NO='CCBZZP';&nbsp;&nbsp;<BR><BR>　　178.&nbsp;/*+&nbsp;FULL(TABLE)*/<BR><BR>　　表明对表选择全局扫描的方法.例如:<BR>SELECT&nbsp;/*+FULL(A)*/&nbsp;EMP_NO,EMP_NAM&nbsp;FROM&nbsp;BSEMPMS&nbsp;A&nbsp;WHERE&nbsp;EMP_NO='CCBZZP';<BR><BR>　　179.&nbsp;/*+ROWID(TABLE)*/<BR><BR>　　提示明确表明对指定表根据ROWID进行访问.例如:<BR>SELECT&nbsp;/*+ROWID(BSEMPMS)*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;ROWID&gt;='AAAAAAAAAAAAAA'<BR>AND&nbsp;EMP_NO='CCBZZP';<BR><BR>　　180.&nbsp;/*+CLUSTER(TABLE)*/&nbsp;<BR>　<BR>　　提示明确表明对指定表选择簇扫描的访问方法,它只对簇对象有效.例如:<BR>SELECT&nbsp;/*+CLUSTER&nbsp;*/&nbsp;BSEMPMS.EMP_NO,DPT_NO&nbsp;FROM&nbsp;BSEMPMS,BSDPTMS<BR>WHERE&nbsp;DPT_NO='TEC304'&nbsp;AND&nbsp;BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;<BR><BR>181.&nbsp;/*+&nbsp;INDEX(TABLE&nbsp;&nbsp;&nbsp;INDEX_NAME)*/<BR>/*+index(table&nbsp;ind_name)&nbsp;index(table&nbsp;ind_name)*/<BR>表明对表选择索引的扫描方法.例如:<BR>SELECT&nbsp;/*+INDEX(BSEMPMS&nbsp;SEX_INDEX)&nbsp;USE&nbsp;SEX_INDEX&nbsp;BECAUSE&nbsp;THERE&nbsp;ARE&nbsp;FEWMALE&nbsp;BSEMPMS&nbsp;*/&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;SEX='M';<BR><BR>　　182.&nbsp;/*+INDEX_ASC(TABLE&nbsp;INDEX_NAME)*/<BR><BR>　　表明对表选择索引升序的扫描方法.例如:<BR>SELECT&nbsp;/*+INDEX_ASC(BSEMPMS&nbsp;PK_BSEMPMS)&nbsp;*/&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;DPT_NO='CCBZZP';<BR><BR>　　183.&nbsp;/*+INDEX_COMBINE*/<BR><BR>　　为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合方式.例如:<BR>SELECT&nbsp;/*+INDEX_COMBINE(BSEMPMS&nbsp;SAL_BMI&nbsp;HIREDATE_BMI)*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS<BR>WHERE&nbsp;SAL&lt;5000000&nbsp;AND&nbsp;HIREDATE&lt;SYSDATE;<BR><BR>　　184.&nbsp;/*+INDEX_JOIN(TABLE&nbsp;INDEX_NAME)*/<BR><BR>　　提示明确命令优化器使用索引作为访问路径.例如:<BR>SELECT&nbsp;/*+INDEX_JOIN(BSEMPMS&nbsp;SAL_HMI&nbsp;HIREDATE_BMI)*/&nbsp;SAL,HIREDATE<BR>FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;SAL&lt;60000;<BR><BR>　　185.&nbsp;/*+INDEX_DESC(TABLE&nbsp;INDEX_NAME)*/<BR><BR>　　表明对表选择索引降序的扫描方法.例如:<BR>SELECT&nbsp;/*+INDEX_DESC(BSEMPMS&nbsp;PK_BSEMPMS)&nbsp;*/&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;DPT_NO='CCBZZP';<BR><BR>　　186.&nbsp;/*+INDEX_FFS(TABLE&nbsp;INDEX_NAME)*/<BR><BR>　　对指定的表执行快速全索引扫描,而不是全表扫描的办法.例如:<BR>SELECT&nbsp;/*+INDEX_FFS(BSEMPMS&nbsp;IN_EMPNAM)*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;DPT_NO='TEC305';<BR><BR>　　187.&nbsp;/*+ADD_EQUAL&nbsp;TABLE&nbsp;INDEX_NAM1,INDEX_NAM2,...*/<BR><BR>　　提示明确进行执行规划的选择,将几个单列索引的扫描合起来.例如:<BR>SELECT&nbsp;/*+INDEX_FFS(BSEMPMS&nbsp;IN_DPTNO,IN_EMPNO,IN_SEX)*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;EMP_NO='CCBZZP'&nbsp;AND&nbsp;DPT_NO='TDC306';<BR><BR>　　188.&nbsp;/*+USE_CONCAT*/<BR><BR>　　对查询中的WHERE后面的OR条件进行转换为UNION&nbsp;ALL的组合查询.例如:<BR>SELECT&nbsp;/*+USE_CONCAT*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;DPT_NO='TDC506'&nbsp;AND&nbsp;SEX='M';<BR><BR>　　189.&nbsp;/*+NO_EXPAND*/<BR><BR>　　对于WHERE后面的OR&nbsp;或者IN-LIST的查询语句,NO_EXPAND将阻止其基于优化器对其进行扩展.例如:<BR>SELECT&nbsp;/*+NO_EXPAND*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS&nbsp;WHERE&nbsp;DPT_NO='TDC506'&nbsp;AND&nbsp;SEX='M';<BR><BR>　　190.&nbsp;/*+NOWRITE*/<BR><BR>　　禁止对查询块的查询重写操作.<BR><BR>191.&nbsp;/*+REWRITE*/<BR><BR>　　可以将视图作为参数.<BR><BR>　　192.&nbsp;/*+MERGE(TABLE)*/<BR><BR>　　能够对视图的各个查询进行相应的合并.例如:<BR>SELECT&nbsp;/*+MERGE(V)&nbsp;*/&nbsp;A.EMP_NO,A.EMP_NAM,B.DPT_NO&nbsp;FROM&nbsp;BSEMPMS&nbsp;A&nbsp;(SELET&nbsp;DPT_NO<BR>,AVG(SAL)&nbsp;AS&nbsp;AVG_SAL&nbsp;FROM&nbsp;BSEMPMS&nbsp;B&nbsp;GROUP&nbsp;BY&nbsp;DPT_NO)&nbsp;Va&nbsp;WHERE&nbsp;A.DPT_NO=V.DPT_NO<BR>AND&nbsp;A.SAL&gt;V.AVG_SAL;<BR><BR>　　193.&nbsp;/*+NO_MERGE(TABLE)*/<BR><BR>　　对于有可合并的视图不再合并.例如:<BR>SELECT&nbsp;/*+NO_MERGE(V)&nbsp;*/&nbsp;A.EMP_NO,A.EMP_NAM,B.DPT_NO&nbsp;FROM&nbsp;BSEMPMS&nbsp;A&nbsp;(SELET&nbsp;DPT_NO<BR>,AVG(SAL)&nbsp;AS&nbsp;AVG_SAL&nbsp;FROM&nbsp;BSEMPMS&nbsp;B&nbsp;GROUP&nbsp;BY&nbsp;DPT_NO)&nbsp;V&nbsp;WHERE&nbsp;A.DPT_NO=V.DPT_NO<BR>AND&nbsp;A.SAL&gt;V.AVG_SAL;<BR><BR>　　194.&nbsp;/*+ORDERED*/<BR><BR>　　根据表出现在FROM中的顺序,ORDERED使ORACLE依此顺序对其连接.例如:<BR>SELECT&nbsp;/*+ORDERED*/&nbsp;A.COL1,B.COL2,C.COL3&nbsp;FROM&nbsp;TABLE1&nbsp;A,TABLE2&nbsp;B,TABLE3&nbsp;C<BR>WHERE&nbsp;A.COL1=B.COL1&nbsp;AND&nbsp;B.COL1=C.COL1;<BR><BR>　　195.&nbsp;/*+USE_NL(TABLE)*/<BR><BR>　　将指定表与嵌套的连接的行源进行连接,并把指定表作为内部表.例如:<BR>SELECT&nbsp;/*+ORDERED&nbsp;USE_NL(BSEMPMS)*/&nbsp;BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM&nbsp;FROM&nbsp;BSEMPMS,BSDPTMS&nbsp;WHERE&nbsp;BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;<BR><BR>　　196.&nbsp;/*+USE_MERGE(TABLE)*/<BR><BR>　　将指定的表与其他行源通过合并排序连接方式连接起来.例如:<BR>SELECT&nbsp;/*+USE_MERGE(BSEMPMS,BSDPTMS)*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS,BSDPTMS&nbsp;WHERE<BR>BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;<BR><BR>　　197.&nbsp;/*+USE_HASH(TABLE)*/<BR><BR>　　将指定的表与其他行源通过哈希连接方式连接起来.例如:<BR>SELECT&nbsp;/*+USE_HASH(BSEMPMS,BSDPTMS)*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS,BSDPTMS&nbsp;WHERE<BR>BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;<BR><BR>　　198.&nbsp;/*+DRIVING_SITE(TABLE)*/<BR><BR>　　强制与ORACLE所选择的位置不同的表进行查询执行.例如:<BR>SELECT&nbsp;/*+DRIVING_SITE(DEPT)*/&nbsp;*&nbsp;FROM&nbsp;BSEMPMS,DEPT@BSDPTMS&nbsp;WHERE&nbsp;BSEMPMS.DPT_NO=DEPT.DPT_NO;<BR><BR>　　199.&nbsp;/*+LEADING(TABLE)*/<BR><BR>　　将指定的表作为连接次序中的首表.<BR><BR>200.&nbsp;/*+CACHE(TABLE)*/<BR><BR>　　当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端例如:<BR>SELECT&nbsp;/*+FULL(BSEMPMS)&nbsp;CAHE(BSEMPMS)&nbsp;*/&nbsp;EMP_NAM&nbsp;FROM&nbsp;BSEMPMS;<BR><BR>　　201.&nbsp;/*+NOCACHE(TABLE)*/<BR><BR>　　当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端，例如:<BR>SELECT&nbsp;/*+FULL(BSEMPMS)&nbsp;NOCAHE(BSEMPMS)&nbsp;*/&nbsp;EMP_NAM&nbsp;FROM&nbsp;BSEMPMS;<BR><BR>　　202.&nbsp;/*+APPEND*/<BR><BR>　　直接插入到表的最后,可以提高速度.<BR>insert&nbsp;/*+append*/&nbsp;into&nbsp;test1&nbsp;select&nbsp;*&nbsp;from&nbsp;test4&nbsp;;<BR><BR>　　203.&nbsp;/*+NOAPPEND*/<BR><BR>　　通过在插入语句生存期内停止并行模式来启动常规插入.<BR>insert&nbsp;/*+noappend*/&nbsp;into&nbsp;test1&nbsp;select&nbsp;*&nbsp;from&nbsp;test4;<BR><BR></P><img src ="http://www.blogjava.net/Titan/aggbug/24431.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Titan/" target="_blank">Titan</a> 2005-12-18 00:01 <a href="http://www.blogjava.net/Titan/articles/24431.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>