﻿<?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-小菜毛毛技术分享-文章分类-数据库</title><link>http://www.blogjava.net/caizh2009/category/39398.html</link><description>与大家共同成长</description><language>zh-cn</language><lastBuildDate>Mon, 08 Mar 2010 15:42:39 GMT</lastBuildDate><pubDate>Mon, 08 Mar 2010 15:42:39 GMT</pubDate><ttl>60</ttl><item><title>查看oracle执行计划</title><link>http://www.blogjava.net/caizh2009/articles/312205.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Sat, 06 Feb 2010 09:30:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312205.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312205.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312205.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312205.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312205.html</trackback:ping><description><![CDATA[<p>日常开发活动中，有时候需要对oracle执行计划进行监控，以此来调优程序和数据库方面的性能。</p>
<p>　　常用方法有以下几种：</p>
<p>　　一、通过PL/SQL Dev工具</p>
<p>　　1、直接File-&gt;New-&gt;Explain Plan Window，在窗口中执行sql可以查看计划结果。其中，Cost表示cpu的消耗，单位为n%，Cardinality表示执行的行数，等价Rows。</p>
<p>　　2、先执行 EXPLAIN PLAN FOR　　 select * from tableA　where paraA=1，再 select * from table(DBMS_XPLAN.DISPLAY)便可以看到oracle的执行计划了，看到的结果和1中的一样，所以使用工具的时候推荐使用1方法。</p>
<p>　　注意：PL/SQL Dev工具的Command window中不支持set autotrance on的命令。还有使用工具方法查看计划看到的信息不全，有些时候我们需要sqlplus的支持。</p>
<p>　　二、通过sqlplus</p>
<p>　　1、一般情况都是本机链接远程服务器，所以命令如下：</p>
<p>　　sqlplus user/pwd@serviceName</p>
<p>　　此处的serviceName为tnsnames.ora中定义的命名空间。</p>
<p>　　2、执行set autotrace on，然后执行sql语句，会列出以下信息：</p>
<p>　　。。。（省略一些信息）</p>
<p>　　统计信息</p>
<p>　　----------------------------------------------------------</p>
<p>　　　　　　　　　　1　　recursive　calls　（归调用次数）<br />
　　　　　　　　　　0　　db　block　gets　　<br />
　　　　　　　　　　2　　consistent　gets<br />
　　　　　　　　　　0　　physical　reads　（物理读——执行SQL的过程中，从硬盘上读取的数据块个数）<br />
　　　　　　　　　　0　　redo　size　(重做数——执行SQL的过程中，产生的重做日志的大小)<br />
　　　　　　　　358　　bytes　sent　via　SQL*Net　to　client<br />
　　　　　　　　366　　bytes　received　via　SQL*Net　from　client<br />
　　　　　　　　　　1　　SQL*Net　roundtrips　to/from　client<br />
　　　　　　　　　　0　　sorts　(memory)　　　　　在内存中发生的排序<br />
　　　　　　　　　　0　　sorts　(disk)　　　　　在硬盘中发生的排序<br />
　　　　　　　　　　1　　rows　processed</p>
<p>　　省略部分信息和通过PL/SQL Dev工具查看执行计划的信息一样，下面的统计信息是更详细的。 </p>
<p>　　判断SQL效率高低不关通过时间来衡量，还应该通过执行SQL执行状态里面的逻辑读的数量</p>
<p>　　逻辑读=（db block gets+ consistent gets） </p>
<p>FengFly.Com <br />
ＷWＷ.ＦENGＦLy.ＣOM FengFly.Com </p>
<p><br />
原文来自：雨枫技术教程网 http://www.fengfly.com<br />
原文网址：http://www.fengfly.com/plus/view-161902-1.html</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312205.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-06 17:30 <a href="http://www.blogjava.net/caizh2009/articles/312205.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ORACLE执行计划的一些基本概念</title><link>http://www.blogjava.net/caizh2009/articles/312193.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Sat, 06 Feb 2010 08:24:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312193.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312193.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312193.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312193.html</trackback:ping><description><![CDATA[<p><strong>一．相关的概念</strong></p>
<p>Rowid的概念：rowid是一个伪列，既然是伪列，那么这个列就不是用户定义，而是系统自己给加上的。对每个表都有一个rowid的伪列，但是表中并不物理存储ROWID列的值。不过你可以像使用其它列那样使用它，但是不能删除改列，也不能对该列的值进行修改、插入。一旦一行数据插入数据库，则rowid在该行的生命周期内是唯一的，即即使该行产生行迁移，行的rowid也不会改变。</p>
<p>Recursive SQL概念：有时为了执行用户发出的一个sql语句，Oracle必须执行一些额外的语句，我们将这些额外的语句称之为'recursive calls'或'recursive SQL statements'。如当一个DDL语句发出后，ORACLE总是隐含的发出一些recursive SQL语句，来修改数据字典信息，以便用户可以成功的执行该DDL语句。当需要的数据字典信息没有在共享内存中时，经常会发生Recursive calls，这些Recursive calls会将数据字典信息从硬盘读入内存中。用户不比关心这些recursive SQL语句的执行情况，在需要的时候，ORACLE会自动的在内部执行这些语句。当然DML语句与SELECT都可能引起recursive SQL。简单的说，我们可以将触发器视为recursive SQL。</p>
<p>Row Source(行源)：用在查询中，由上一操作返回的符合条件的行的集合，即可以是表的全部行数据的集合；也可以是表的部分行数据的集合；也可以为对上2个row source进行连接操作(如join连接)后得到的行数据集合。</p>
<p>Predicate(谓词)：一个查询中的WHERE限制条件</p>
<p>Driving Table(驱动表)：该表又称为外层表(OUTER TABLE)。这个概念用于嵌套与HASH连接中。如果该row source返回较多的行数据，则对所有的后续操作有负面影响。注意此处虽然翻译为驱动表，但实际上翻译为驱动行源(driving row source)更为确切。一般说来，是应用查询的限制条件后，返回较少行源的表作为驱动表，所以如果一个大表在WHERE条件有有限制条件(如等值限制)，则该大表作为驱动表也是合适的，所以并不是只有较小的表可以作为驱动表，正确说法应该为应用查询的限制条件后，返回较少行源的表作为驱动表。在执行计划中，应该为靠上的那个row source，后面会给出具体说明。在我们后面的描述中，一般将该表称为连接操作的row source 1。</p>
<p>Probed Table(被探查表)：该表又称为内层表(INNER TABLE)。在我们从驱动表中得到具体一行的数据后，在该表中寻找符合连接条件的行。所以该表应当为大表(实际上应该为返回较大row source的表)且相应的列上应该有索引。在我们后面的描述中，一般将该表称为连接操作的row source 2。</p>
<p>组合索引(concatenated index)：由多个列构成的索引，如create index idx_emp on emp(col1, col2, col3, &#8230;&#8230;)，则我们称idx_emp索引为组合索引。在组合索引中有一个重要的概念：引导列(leading column)，在上面的例子中，col1列为引导列。当我们进行查询时可以使用&#8221;where col1 = ? &#8221;，也可以使用&#8221;where col1 = ? and col2 = ?&#8221;，这样的限制条件都会使用索引，但是&#8221;where col2 = ? &#8221;查询就不会使用该索引。所以限制条件中包含先导列时，该限制条件才会使用该组合索引。</p>
<p>可选择性(selectivity)：比较一下列中唯一键的数量和表中的行数，就可以判断该列的可选择性。如果该列的&#8221;唯一键的数量/表中的行数&#8221;的比值越接近1，则该列的可选择性越高，该列就越适合创建索引，同样索引的可选择性也越高。在可选择性高的列上进行查询时，返回的数据就较少，比较适合使用索引查询。<br />
<strong>二．oracle访问数据的存取方法</strong></p>
<p>1) 全表扫描（Full Table Scans, FTS）</p>
<p>为实现全表扫描，Oracle读取表中所有的行，并检查每一行是否满足语句的WHERE限制条件一个多块读操作可以使一次I/O能读取多块数据块(db_block_multiblock_read_count参数设定)，而不是只读取一个数据块，这极大的减少了I/O总次数，提高了系统的吞吐量，所以利用多块读的方法可以十分高效地实现全表扫描，而且只有在全表扫描的情况下才能使用多块读操作。在这种访问模式下，每个数据块只被读一次。<br />
使用FTS的前提条件：在较大的表上不建议使用全表扫描，除非取出数据的比较多，超过总量的5% -- 10%，或你想使用并行查询功能时。<br />
使用全表扫描的例子：<br />
~~~~~~~~~~~~~~~~~~~~~~~~
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>SQL&gt; explain plan for select * from dual;<br />
            Query Plan<br />
            -----------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=<br />
            TABLE ACCESS FULL DUAL
            <p>&nbsp;</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>2) 通过ROWID的表存取（Table Access by ROWID或rowid lookup）</p>
<p>行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置，所以通过ROWID来存取数据可以快速定位到目标数据上，是Oracle存取单行数据的最快方法。<br />
这种存取方法不会用到多块读操作，一次I/O只能读取一个数据块。我们会经常在执行计划中看到该存取方法，如通过索引查询数据。</p>
<p>使用ROWID存取的方法：
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>SQL&gt; explain plan for select * from dept where rowid = 'AAAAyGAADAAAAATAAF';<br />
            Query Plan<br />
            ------------------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=1<br />
            TABLE ACCESS BY ROWID DEPT [ANALYZED]</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>3）索引扫描（Index Scan或index lookup）</p>
<p>我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值)，然后根据rowid直接从表中得到具体的数据，这种查找方式称为索引扫描或索引查找(index lookup)。一个rowid唯一的表示一行数据，该行对应的数据块是通过一次i/o得到的，在此情况下该次i/o只会读取一个数据库块。</p>
<p>在索引中，除了存储每个索引的值外，索引还存储具有此值的行对应的ROWID值。索引扫描可以由2步组成：(1) 扫描索引得到对应的rowid值。 (2) 通过找到的rowid从表中读出具体的数据。每步都是单独的一次I/O，但是对于索引，由于经常使用，绝大多数都已经CACHE到内存中，所以第1步的I/O经常是逻辑I/O，即数据可以从内存中得到。但是对于第2步来说，如果表比较大，则其数据不可能全在内存中，所以其I/O很有可能是物理I/O，这是一个机械操作，相对逻辑I/O来说，是极其费时间的。所以如果多大表进行索引扫描，取出的数据如果大于总量的5% -- 10%，使用索引扫描会效率下降很多。如下列所示：</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>
            <p>SQL&gt; explain plan for select empno, ename from emp where empno=10;<br />
            Query Plan<br />
            ------------------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=1<br />
            TABLE ACCESS BY ROWID EMP [ANALYZED] <br />
            INDEX UNIQUE SCAN EMP_I1</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>但是如果查询的数据能全在索引中找到，就可以避免进行第2步操作，避免了不必要的I/O，此时即使通过索引扫描取出的数据比较多，效率还是很高的
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for select empno from emp where empno=10;-- 只查询empno列值<br />
            Query Plan<br />
            ------------------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=1<br />
            INDEX UNIQUE SCAN EMP_I1
            <p>&nbsp;</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>进一步讲，如果sql语句中对索引列进行排序，因为索引已经预先排序好了，所以在执行计划中不需要再对索引列进行排序</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>
            <p>SQL&gt; explain plan for select empno, ename from emp<br />
            where empno &gt; 7876 order by empno;<br />
            Query Plan<br />
            --------------------------------------------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=1<br />
            TABLE ACCESS BY ROWID EMP [ANALYZED] <br />
            INDEX RANGE SCAN EMP_I1 [ANALYZED] </p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>从这个例子中可以看到：因为索引是已经排序了的，所以将按照索引的顺序查询出符合条件的行，因此避免了进一步排序操作。</p>
<p>根据索引的类型与where限制条件的不同，有4种类型的索引扫描：<br />
索引唯一扫描(index unique scan)<br />
索引范围扫描(index range scan)<br />
索引全扫描(index full scan)<br />
索引快速扫描(index fast full scan)<br />
(1) 索引唯一扫描(index unique scan)</p>
<p>通过唯一索引查找一个数值经常返回单个ROWID。如果存在UNIQUE 或PRIMARY KEY 约束（它保证了语句只存取单行）的话，Oracle经常实现唯一性扫描。<br />
使用唯一性约束的例子：</p>
<p>SQL&gt; explain plan for<br />
select empno,ename from emp where empno=10;<br />
Query Plan<br />
------------------------------------<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED] <br />
INDEX UNIQUE SCAN EMP_I1<br />
(2) 索引范围扫描(index range scan)</p>
<p>使用一个索引存取多行数据，在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(如&gt;、&lt;、&lt;&gt;、&gt;=、&lt;=、between)<br />
使用索引范围扫描的例子： </p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for select empno,ename from emp<br />
            where empno &gt; 7876 order by empno;<br />
            Query Plan<br />
            --------------------------------------------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=1<br />
            TABLE ACCESS BY ROWID EMP [ANALYZED] <br />
            INDEX RANGE SCAN EMP_I1 [ANALYZED] </pre>
            </td>
        </tr>
    </tbody>
</table>
在非唯一索引上，谓词col = 5可能返回多行数据，所以在非唯一索引上都使用索引范围扫描。<br />
使用index rang scan的3种情况：
<p>(a) 在唯一索引列上使用了range操作符(&gt; &lt; &lt;&gt; &gt;= &lt;= between)<br />
(b) 在组合索引上，只使用部分列进行查询，导致查询出多行<br />
(c) 对非唯一索引列上进行的任何查询。<br />
(3) 索引全扫描(index full scan)</p>
<p>与全表扫描对应，也有相应的全索引扫描。而且此时查询出的数据都必须从索引中可以直接得到。<br />
全索引扫描的例子：</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            An Index full scan will not perform single block i/o's and so it may prove to be inefficient.
            <p>e.g.<br />
            Index BE_IX is a concatenated index on big_emp (empno, ename)</p>
            <p>SQL&gt; explain plan for select empno, ename from big_emp order by empno,ename;<br />
            Query Plan<br />
            --------------------------------------------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=26<br />
            INDEX FULL SCAN BE_IX [ANALYZED]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>(4) 索引快速扫描(index fast full scan)
<p>扫描索引中的所有的数据块，与 index full scan很类似，但是一个显著的区别就是它不对查询出的数据进行排序，即数据不是以排序顺序被返回。在这种存取方法中，可以使用多块读功能，也可以使用并行读入，以便获得最大吞吐量与缩短执行时间。</p>
<p>索引快速扫描的例子：</p>
<p>BE_IX索引是一个多列索引： </p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>big_emp (empno,ename)
            <p>&nbsp;</p>
            <p>SQL&gt; explain plan for select empno,ename from big_emp;<br />
            Query Plan<br />
            ------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=1<br />
            INDEX FAST FULL SCAN BE_IX [ANALYZED]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>只选择多列索引的第2列：
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for select ename from big_emp;<br />
            Query Plan<br />
            ------------------------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=1<br />
            INDEX FAST FULL SCAN BE_IX [ANALYZED]</pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>ORACLE执行计划的一些基本概念(2)<br />
<strong>三.表之间的连接</strong> </p>
<p>&nbsp;</p>
<p>Join是一种试图将两个表结合在一起的谓词，一次只能连接2个表，表连接也可以被称为表关联。在后面的叙述中，我们将会使用&#8221;row source&#8221;来代替&#8221;表&#8221;，因为使用row source更严谨一些，并且将参与连接的2个row source分别称为row source1和row source 2。Join过程的各个步骤经常是串行操作，即使相关的row source可以被并行访问，即可以并行的读取做join连接的两个row source的数据，但是在将表中符合限制条件的数据读入到内存形成row source后，join的其它步骤一般是串行的。有多种方法可以将2个表连接起来，当然每种方法都有自己的优缺点，每种连接类型只有在特定的条件下才会发挥出其最大优势。</p>
<p>row source(表)之间的连接顺序对于查询的效率有非常大的影响。通过首先存取特定的表，即将该表作为驱动表，这样可以先应用某些限制条件，从而得到一个较小的row source，使连接的效率较高，这也就是我们常说的要先执行限制条件的原因。一般是在将表读入内存时，应用where子句中对该表的限制条件。<br />
根据2个row source的连接条件的中操作符的不同，可以将连接分为等值连接(如WHERE A.COL3 = B.COL4)、非等值连接(WHERE A.COL3 &gt; B.COL4)、外连接(WHERE A.COL3 = B.COL4(+))。上面的各个连接的连接原理都基本一样，所以为了简单期间，下面以等值连接为例进行介绍。</p>
<p>在后面的介绍中，都已：<br />
SELECT A.COL1, B.COL2 <br />
FROM A, B<br />
WHERE A.COL3 = B.COL4;<br />
为例进行说明，假设A表为Row Soruce1，则其对应的连接操作关联列为COL 3；B表为Row Soruce2，则其对应的连接操作关联列为COL 4；</p>
<p>连接类型：<br />
目前为止，无论连接操作符如何，典型的连接类型共有3种：<br />
排序 - - 合并连接(Sort Merge Join (SMJ) )<br />
嵌套循环(Nested Loops (NL) )<br />
哈希连接(Hash Join)</p>
<p>排序 - - 合并连接(Sort Merge Join, SMJ)<br />
内部连接过程：<br />
1) 首先生成row source1需要的数据，然后对这些数据按照连接操作关联列(如A.col3)进行排序。<br />
2) 随后生成row source2需要的数据，然后对这些数据按照与sort source1对应的连接操作关联列(如B.col4)进行排序。<br />
3) 最后两边已排序的行被放在一起执行合并操作，即将2个row source按照连接条件连接起来<br />
下面是连接步骤的图形表示：<br />
MERGE<br />
/\<br />
SORTSORT<br />
||<br />
Row Source 1Row Source 2</p>
<p>如果row source已经在连接关联列上被排序，则该连接操作就不需要再进行sort操作，这样可以大大提高这种连接操作的连接速度，因为排序是个极其费资源的操作，特别是对于较大的表。预先排序的row source包括已经被索引的列(如a.col3或b.col4上有索引)或row source已经在前面的步骤中被排序了。尽管合并两个row source的过程是串行的，但是可以并行访问这两个row source(如并行读入数据，并行排序).</p>
<p>SMJ连接的例子：</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre>
            <p>SQL&gt; explain plan for<br />
            select /*+ ordered */ e.deptno, d.deptno<br />
            from emp e, dept d<br />
            where e.deptno = d.deptno<br />
            order by e.deptno, d.deptno;</p>
            <p>Query Plan<br />
            -------------------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=17<br />
            MERGE JOIN<br />
            SORT JOIN<br />
            TABLE ACCESS FULL EMP [ANALYZED]<br />
            SORT JOIN<br />
            TABLE ACCESS FULL DEPT [ANALYZED]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>排序是一个费时、费资源的操作，特别对于大表。基于这个原因，SMJ经常不是一个特别有效的连接方法，但是如果2个row source都已经预先排序，则这种连接方法的效率也是蛮高的。</p>
<p>嵌套循环(Nested Loops, NL)<br />
这个连接方法有驱动表(外部表)的概念。其实，该连接过程就是一个2层嵌套循环，所以外层循环的次数越少越好，这也就是我们为什么将小表或返回较小row source的表作为驱动表(用于外层循环)的理论依据。但是这个理论只是一般指导原则，因为遵循这个理论并不能总保证使语句产生的I/O次数最少。有时不遵守这个理论依据，反而会获得更好的效率。如果使用这种方法，决定使用哪个表作为驱动表很重要。有时如果驱动表选择不正确，将会导致语句的性能很差、很差。</p>
<p>内部连接过程：<br />
Row source1的Row 1 ---------------- Probe -&gt;Row source 2<br />
Row source1的Row 2 ---------------- Probe -&gt;Row source 2 <br />
Row source1的Row 3 ---------------- Probe -&gt;Row source 2<br />
&#8230;&#8230;.<br />
Row source1的Row n ---------------- Probe -&gt;Row source 2<br />
从内部连接过程来看，需要用row source1中的每一行，去匹配row source2中的所有行，所以此时保持row source1尽可能的小与高效的访问row source2(一般通过索引实现)是影响这个连接效率的关键问题。这只是理论指导原则，目的是使整个连接操作产生最少的物理I/O次数，而且如果遵守这个原则，一般也会使总的物理I/O数最少。但是如果不遵从这个指导原则，反而能用更少的物理I/O实现连接操作，那尽管违反指导原则吧！因为最少的物理I/O次数才是我们应该遵从的真正的指导原则，在后面的具体案例分析中就给出这样的例子。</p>
<p>在上面的连接过程中，我们称Row source1为驱动表或外部表。Row Source2被称为被探查表或内部表。</p>
<p>在NESTED LOOPS连接中，Oracle读取row source1中的每一行，然后在row sourc2中检查是否有匹配的行，所有被匹配的行都被放到结果集中，然后处理row source1中的下一行。这个过程一直继续，直到row source1中的所有行都被处理。这是从连接操作中可以得到第一个匹配行的最快的方法之一，这种类型的连接可以用在需要快速响应的语句中，以响应速度为主要目标。</p>
<p>如果driving row source(外部表)比较小，并且在inner row source(内部表)上有唯一索引，或有高选择性非唯一索引时，使用这种方法可以得到较好的效率。NESTED LOOPS有其它连接方法没有的的一个优点是：可以先返回已经连接的行，而不必等待所有的连接操作处理完才返回数据，这可以实现快速的响应时间。</p>
<p>如果不使用并行操作，最好的驱动表是那些应用了where 限制条件后，可以返回较少行数据的的表，所以大表也可能称为驱动表，关键看限制条件。对于并行查询，我们经常选择大表作为驱动表，因为大表可以充分利用并行功能。当然，有时对查询使用并行操作并不一定会比查询不使用并行操作效率高，因为最后可能每个表只有很少的行符合限制条件，而且还要看你的硬件配置是否可以支持并行(如是否有多个CPU，多个硬盘控制器)，所以要具体问题具体对待。 </p>
<p>NL连接的例子：
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for<br />
            select a.dname,b.sql<br />
            from dept a,emp b<br />
            where a.deptno = b.deptno;
            <p>Query Plan<br />
            -------------------------<br />
            SELECT STATEMENT [CHOOSE] Cost=5<br />
            NESTED LOOPS<br />
            TABLE ACCESS FULL DEPT [ANALYZED]<br />
            TABLE ACCESS FULL EMP [ANALYZED]</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<p>哈希连接(Hash Join, HJ)</p>
<p>这种连接是在oracle 7.3以后引入的，从理论上来说比NL与SMJ更高效，而且只用在CBO优化器中。<br />
较小的row source被用来构建hash table与bitmap，第2个row source被用来被hansed，并与第一个row source生成的hash table进行匹配，以便进行进一步的连接。Bitmap被用来作为一种比较快的查找方法，来检查在hash table中是否有匹配的行。特别的，当hash table比较大而不能全部容纳在内存中时，这种查找方法更为有用。这种连接方法也有NL连接中所谓的驱动表的概念，被构建为hash table与bitmap的表为驱动表，当被构建的hash table与bitmap能被容纳在内存中时，这种连接方式的效率极高。 </p>
<p>HASH连接的例子：</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for<br />
            select /*+ use_hash(emp) */ empno <br />
            from emp, dept<br />
            where emp.deptno = dept.deptno;
            <p>Query Plan<br />
            ----------------------------<br />
            SELECT STATEMENT[CHOOSE] Cost=3<br />
            HASH JOIN<br />
            TABLE ACCESS FULL DEPT<br />
            TABLE ACCESS FULL EMP</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>要使哈希连接有效，需要设置HASH_JOIN_ENABLED=TRUE，缺省情况下该参数为TRUE，另外，不要忘了还要设置hash_area_size参数，以使哈希连接高效运行，因为哈希连接会在该参数指定大小的内存中运行，过小的参数会使哈希连接的性能比其他连接方式还要低。
<p>总结一下，在哪种情况下用哪种连接方法比较好：</p>
<p>排序 - - 合并连接(Sort Merge Join, SMJ)：<br />
a) 对于非等值连接，这种连接方式的效率是比较高的。<br />
b) 如果在关联的列上都有索引，效果更好。<br />
c) 对于将2个较大的row source做连接，该连接方法比NL连接要好一些。<br />
d) 但是如果sort merge返回的row source过大，则又会导致使用过多的rowid在表中查询数据时，数据库性能下降，因为过多的I/O。</p>
<p>嵌套循环(Nested Loops, NL)：<br />
a) 如果driving row source(外部表)比较小，并且在inner row source(内部表)上有唯一索引，或有高选择性非唯一索引时，使用这种方法可以得到较好的效率。<br />
b) NESTED LOOPS有其它连接方法没有的的一个优点是：可以先返回已经连接的行，而不必等待所有的连接操作处理完才返回数据，这可以实现快速的响应时间。</p>
<p>哈希连接(Hash Join, HJ)：<br />
a) 这种方法是在oracle7后来引入的，使用了比较先进的连接理论，一般来说，其效率应该好于其它2种连接，但是这种连接只能用在CBO优化器中，而且需要设置合适的hash_area_size参数，才能取得较好的性能。<br />
b) 在2个较大的row source之间连接时会取得相对较好的效率，在一个row source较小时则能取得更好的效率。<br />
c) 只能用于等值连接中</p>
<p>笛卡儿乘积(Cartesian Product) </p>
<p>当两个row source做连接，但是它们之间没有关联条件时，就会在两个row source中做笛卡儿乘积，这通常由编写代码疏漏造成(即程序员忘了写关联条件)。笛卡尔乘积是一个表的每一行依次与另一个表中的所有行匹配。在特殊情况下我们可以使用笛卡儿乘积，如在星形连接中，除此之外，我们要尽量使用笛卡儿乘积，否则，自己想结果是什么吧！</p>
<p>注意在下面的语句中，在2个表之间没有连接。</p>
<p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" bgcolor="#e6e6e6">
            <pre><br />
            SQL&gt; explain plan for<br />
            select emp.deptno,dept,deptno <br />
            from emp,dept
            <p>Query Plan<br />
            ------------------------<br />
            SLECT STATEMENT [CHOOSE] Cost=5<br />
            MERGE JOIN CARTESIAN<br />
            TABLE ACCESS FULL DEPT<br />
            SORT JOIN<br />
            TABLE ACCESS FULL EMP</p>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>CARTESIAN关键字指出了在2个表之间做笛卡尔乘积。假如表emp有n行，dept表有m行，笛卡尔乘积的结果就是得到n * m行结果。 </p>
<p><br />
</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-06 16:24 <a href="http://www.blogjava.net/caizh2009/articles/312193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle系统表 字典表</title><link>http://www.blogjava.net/caizh2009/articles/312099.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 05 Feb 2010 05:38:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312099.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312099.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312099.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312099.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312099.html</trackback:ping><description><![CDATA[<span class="hilite1">ORACLE</span>系统表处理 <br />
<br />
1.取得指定用户的所有表名： <br />
<li><span><span>SELECT&nbsp;OWNER&nbsp;&nbsp;AS&nbsp;</span><span class="string">"对象所有者"</span><span>,OBJECT_NAME&nbsp;AS&nbsp;</span><span class="string">"表名"</span><span>,OBJECT_ID&nbsp;AS&nbsp;</span><span class="string">"对象编号"</span><span>&nbsp;from&nbsp;dba_objects&nbsp;where&nbsp;owner&nbsp;=&nbsp;</span><span class="string">'RAXNYB'</span><span>&nbsp;AND&nbsp;OBJECT_TYPE&nbsp;=&nbsp;</span><span class="string">'TABLE'</span><span>&nbsp;ORDER&nbsp;BY&nbsp;OWNER,OBJECT_TYPE; &nbsp;&nbsp;</span></span></li>
<li><span>或 &nbsp;&nbsp;</span></li>
<li><span>OWNER&nbsp;&nbsp;AS&nbsp;</span><span class="string">"对象所有者"</span><span>,TABLE_NAME&nbsp;AS&nbsp;</span><span class="string">"表名"</span><span>&nbsp;from&nbsp;DBA_TABLES&nbsp;where&nbsp;owner&nbsp;=&nbsp;</span><span class="string">'RAXNYB'</span><span>&nbsp;&nbsp;ORDER&nbsp;BY&nbsp;OWNER,TABLE_NAME;&nbsp;</span></li>
<p><span><br />
2.取得指定用户的所有视图名称：<br />
<span><span>SELECT&nbsp;OWNER&nbsp;&nbsp;AS&nbsp;</span><span class="string">"对象所有者"</span><span>,VIEW_NAME&nbsp;AS&nbsp;</span><span class="string">"视图名称"</span><span>&nbsp;from&nbsp;DBA_VIEWS&nbsp;&nbsp;where&nbsp;owner&nbsp;=&nbsp;</span><span class="string">'RAXNYB'</span><span>&nbsp;&nbsp;ORDER&nbsp;BY&nbsp;OWNER,VIEW_NAME;&nbsp;</span></span><br />
<br />
Oracle系统表查询<br />
数据字典dict总是属于Oracle用户sys的。 <br />
1、用户： <br />
　select username from dba_users; <br />
改口令 <br />
　alter user spgroup identified by spgtest; <br />
2、表空间： <br />
　select * from dba_data_files; <br />
　select * from dba_tablespaces;//表空间 <br />
　select tablespace_name,sum(bytes), sum(blocks) <br />
from dba_free_space group by tablespace_name;//空闲表空间 <br />
　select * from dba_data_files <br />
where tablespace_name='RBS';//表空间对应的数据文件 <br />
　select * from dba_segments <br />
where tablespace_name='INDEXS'; <br />
3、数据库对象： <br />
　select * from dba_objects; <br />
　CLUSTER、DATABASE LINK、FUNCTION、INDEX、LIBRARY、PACKAGE、PACKAGE BODY、 <br />
　PROCEDURE、SEQUENCE、SYNONYM、TABLE、TRIGGER、TYPE、UNDEFINED、VIEW。 <br />
4、表： <br />
　select * from dba_tables; <br />
　analyze my_table compute statistics;-&gt;dba_tables后6列 <br />
　select extent_id,bytes from dba_extents <br />
　where segment_name='CUSTOMERS' and segment_type='TABLE' <br />
　order by extent_id;//表使用的extent的信息。segment_type='ROLLBACK'查看回滚段的空间分配信息 <br />
　列信息： <br />
select distinct table_name <br />
from user_tab_columns <br />
where column_name='SO_TYPE_ID'; <br />
5、索引：　 <br />
　select * from dba_indexes;//索引，包括主键索引 <br />
　select * from dba_ind_columns;//索引列 <br />
　select i.index_name,i.uniqueness,c.column_name <br />
from user_indexes i,user_ind_columns c <br />
　where i.index_name=c.index_name <br />
　and i.table_name ='ACC_NBR';//联接使用 <br />
6、序列： <br />
　select * from dba_sequences; <br />
7、视图： <br />
　select * from dba_views; <br />
　select * from all_views; <br />
text 可用于查询视图生成的脚本 <br />
8、聚簇： <br />
　select * from dba_clusters; <br />
9、快照： <br />
　select * from dba_snapshots; <br />
快照、分区应存在相应的表空间。 <br />
10、同义词： <br />
　select * from dba_synonyms <br />
where table_owner='SPGROUP'; <br />
//if owner is PUBLIC,then the synonyms is a public synonym. <br />
　if owner is one of users,then the synonyms is a private synonym. <br />
11、数据库链： <br />
　select * from dba_db_links; <br />
在spbase下建数据库链 <br />
　create database link dbl_spnew <br />
　connect to spnew identified by spnew using 'jhhx'; <br />
　insert into acc_nbr@dbl_spnew <br />
　select * from acc_nbr where nxx_nbr='237' and line_nbr='8888'; <br />
12、触发器： <br />
　select * from dba_trigers; <br />
存储过程，函数从dba_objects查找。 <br />
其文本：select text from user_source where name='BOOK_SP_EXAMPLE'; <br />
建立出错：select * from user_errors; <br />
oracle总是将存储过程，函数等软件放在SYSTEM表空间。 <br />
13、约束： <br />
（1）约束是和表关联的，可在create table或alter table table_name add/drop/modify来建立、修改、删除约束。 <br />
可以临时禁止约束，如： <br />
　alter table book_example <br />
　disable constraint book_example_1; <br />
　alter table book_example <br />
　enable constraint book_example_1; <br />
（2）主键和外键被称为表约束，而not null和unique之类的约束被称为列约束。通常将主键和外键作为单独的命名约束放在字段列表下面，而列约束可放在列定义的同一行，这样更具有可读性。 <br />
（3）列约束可从表定义看出，即describe;表约束即主键和外键，可从dba_constraints和dba_cons_columns 查。 <br />
　select * from user_constraints <br />
　where table_name='BOOK_EXAMPLE'; <br />
　select owner,CONSTRAINT_NAME,TABLE_NAME <br />
from user_constraints <br />
where constraint_type='R' <br />
order by table_name; <br />
（4）定义约束可以无名（系统自动生成约束名）和自己定义约束名（特别是主键、外键） <br />
如：create table book_example <br />
(identifier number not null); <br />
create table book_example <br />
(identifier number constranit book_example_1 not null); <br />
14、回滚段： <br />
在所有的修改结果存入磁盘前，回滚段中保持恢复该事务所需的全部信息，必须以数据库发生的事务来相应确定其大小（DML语句才可回滚，create,drop,truncate等DDL不能回滚）。 <br />
回滚段数量=并发事务/4，但不能超过50；使每个回滚段大小足够处理一个完整的事务； <br />
　create rollback segment r05 <br />
　tablespace rbs; <br />
　create rollback segment rbs_cvt <br />
　tablespace rbs <br />
　storage(initial 1M next 500k); <br />
使回滚段在线 <br />
　alter rollback segment r04 online; <br />
用dba_extents,v$rollback_segs监测回滚段的大小和动态增长。 <br />
回滚段的区间信息 <br />
　select * from dba_extents <br />
　where segment_type='ROLLBACK' and segment_name='RB1'; <br />
回滚段的段信息,其中bytes显示目前回滚段的字节数 <br />
　select * from dba_segments <br />
where segment_type='ROLLBACK' and segment_name='RB1'; <br />
为事物指定回归段 <br />
　set transaction use rollback segment rbs_cvt <br />
针对bytes可以使用回滚段回缩。 <br />
　alter rollback segment rbs_cvt shrink; <br />
　select bytes,extents,max_extents from dba_segments <br />
where segment_type='ROLLBACK' and segment_name='RBS_CVT'; <br />
回滚段的当前状态信息： <br />
　select * from dba_rollback_segs <br />
where segment_name='RB1'; <br />
比多回滚段状态status，回滚段所属实例instance_num <br />
查优化值optimal <br />
　select n.name,s.optsize <br />
from v$rollname n,v$rollstat s <br />
　where n.usn=s.usn; <br />
回滚段中的数据 <br />
　set transaction use rollback segment rb1;/*回滚段名*/ <br />
　select n.name,s.writes <br />
from v$rollname n,v$rollstat s <br />
　where n.usn=s.usn; <br />
当事务处理完毕，再次查询$rollstat，比较writes(回滚段条目字节数)差值，可确定事务的大小。 <br />
查询回滚段中的事务 <br />
　column rr heading 'RB Segment' format a18 <br />
　column us heading 'Username' format a15 <br />
　column os heading 'Os User' format a10 <br />
　column te heading 'Terminal' format a10 <br />
　select r.name rr,nvl(s.username,'no transaction') us,s.osuser os,s.terminal te <br />
from v$lock l,v$session s,v$rollname r <br />
　where l.sid=s.sid(+) <br />
　and trunc(l.id1/65536)=R.USN <br />
　and l.type='TX' <br />
　and l.lmode=6 <br />
　order by r.name; <br />
15、作业 <br />
查询作业信息 <br />
　select job,broken,next_date,interval,what from user_jobs; <br />
　select job,broken,next_date,interval,what from dba_jobs; <br />
查询正在运行的作业 <br />
　select * from dba_jobs_running; <br />
使用包exec dbms_job.submit(:v_num,'a;',sysdate,'sysdate + (10/(24*60*60))')加入作业。间隔10秒钟 <br />
exec dbms_job.submit(:v_num,'a;',sysdate,'sysdate + (11/(24*60))')加入作业。间隔11分钟使用包exec dbms_job.remove(21)删除21号作业。 <br />
</span></p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312099.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-05 13:38 <a href="http://www.blogjava.net/caizh2009/articles/312099.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入学习Oracle分区表及分区索引</title><link>http://www.blogjava.net/caizh2009/articles/312092.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 05 Feb 2010 04:56:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312092.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312092.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312092.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312092.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312092.html</trackback:ping><description><![CDATA[关于分区表和分区索引(About Partitioned Tables and Indexes)对于10gR2而言，基本上可以分成几类：
<ul>
    <li>　　 Range(范围)分区
    <li>　　 Hash(哈希)分区
    <li>　　 List(列表)分区
    <li>　　 以及组合分区：Range-Hash,Range-List。 </li>
</ul>
<p>　　对于表而言(常规意义上的堆组织表)，上述分区形式都可以应用(甚至可以对某个分区指定compress属性)，只不过分区依赖列不能是lob,long之类数据类型，每个表的分区或子分区数的总数不能超过1023个。</p>
<p>　　对于索引组织表，只能够支持普通分区方式，不支持组合分区，常规表的限制对于索引组织表同样有效，除此之外呢，还有一些其实的限制，比如要求索引组织表的分区依赖列必须是主键才可以等。</p>
<p>　　注：本篇所有示例仅针对常规表，即堆组织表!</p>
<p>　　对于索引，需要区分创建的是全局索引，或本地索引：</p>
<p>　　l 全局索引(global index)：即可以分区，也可以不分区。即可以建range分区，也可以建hash分区，即可建于分区表，又可创建于非分区表上，就是说，全局索引是完全独立的，因此它也需要我们更多的维护操作。</p>
<p>　　l 本地索引(local index)：其分区形式与表的分区完全相同，依赖列相同，存储属性也相同。对于本地索引，其索引分区的维护自动进行，就是说你add/drop/split/truncate表的分区时，本地索引会自动维护其索引分区。</p>
<p>　　Oracle建议如果单个表超过2G就最好对其进行分区，对于大表创建分区的好处是显而易见的，这里不多论述why，而将重点放在when以及how。</p>
<p>　　<strong>WHEN</strong></p>
<p>　　一、When使用Range分区</p>
<p>　　Range分区呢是应用范围比较广的表分区方式，它是以列的值的范围来做为分区的划分条件，将记录存放到列值所在的range分区中，比如按照时间划分，2008年1季度的数据放到a分区，08年2季度的数据放到b分区，因此在创建的时候呢，需要你指定基于的列，以及分区的范围值，如果某些记录暂无法预测范围，可以创建maxvalue分区，所有不在指定范围内的记录都会被存储到maxvalue所在分区中，并且支持指定多列做为依赖列，后面在讲how的时候会详细谈到。</p>
<p>　　二、When使用Hash分区</p>
<p>　　通常呢，对于那些无法有效划分范围的表，可以使用hash分区，这样对于提高性能还是会有一定的帮助。hash分区会将表中的数据平均分配到你指定的几个分区中，列所在分区是依据分区列的hash值自动分配，因此你并不能控制也不知道哪条记录会被放到哪个分区中，hash分区也可以支持多个依赖列。</p>
<p>　　三、When使用List分区</p>
<p>　　List分区与range分区和hash分区都有类似之处，该分区与range分区类似的是也需要你指定列的值，但这又不同与range分区的范围式列值---其分区值必须明确指定，也不同与hash分区---通过明确指定分区值，你能控制记录存储在哪个分区。它的分区列只能有一个，而不能像range或者hash分区那样同时指定多个列做为分区依赖列，不过呢，它的单个分区对应值可以是多个。</p>
<p>　　你在分区时必须确定分区列可能存在的值，一旦插入的列值不在分区范围内，则插入/更新就会失败，因此通常建议使用list分区时，要创建一个default分区存储那些不在指定范围内的记录，类似range分区中的maxvalue分区。</p>
<p>　　四、When使用组合分区</p>
<p>　　如果某表按照某列分区之后，仍然较大，或者是一些其它的需求，还可以通过分区内再建子分区的方式将分区再分区，即组合分区的方式。</p>
<p>　　组合分区呢在10g中有两种：range-hash，range-list。注意顺序哟，根分区只能是range分区，子分区可以是hash分区或list分区。</p>
<p>　　提示：11g在组合分区功能这块有所增强，又推出了range-range,list-range,list-list,list-hash，这就相当于除hash外三种分区方式的笛卡尔形式都有了。为什么会没有hash做为根分区的组合分区形式呢，再仔细回味一下第二点，你一定能够想明白~~。</p>
<strong>一、如何创建</strong>
<p>　　如果想对某个表做分区，必须在创建表时就指定分区，我们可以对一个包含分区的表中的分区做修改，但不能直接将一个未分区的表修改成分区表(起码在10g是不行的，当然你可能会说，可以通过在线重定义的方式，但是这不是直接哟，这也是借助临时表间接实现的)。</p>
<p>　　创建表或索引的语法就不说了，大家肯定比我还熟悉，而想在建表(索引)同时指定分区也非常容易，只需要把创建分区的子句放到";"前就行啦，同时需要注意表的row movement属性，它用来控制是否允许修改列值所造成的记录移动至其它分区存储，有enable|disable两种状态，默认是disable row movement，当disable时，如果记录要被更新至其它分区，则更新语句会报错。</p>
<p>　　下面分别演示不同分区方式的表和索引的创建：</p>
<p>　　<strong>1、创建range分区</strong></p>
<p>　　语法如下，图：[range_partitioning.gif]</p>
<p>　　<img height="102" alt="" src="http://space.itpub.net/attachments/2008/05/7607759_200805070916581.gif" width="400" /></p>
<p>　　需要我们指定的有：</p>
<p>　　l column:分区依赖列(如果是多个，以逗号分隔);</p>
<p>　　l partition:分区名称;</p>
<p>　　l values less than:后跟分区范围值(如果依赖列有多个，范围对应值也应是多个，中间以逗号分隔);</p>
<p>　　l tablespace_clause:分区的存储属性，例如所在表空间等属性(可为空)，默认继承基表所在表空间的属性。</p>
<p>　　<strong>①　创建一个标准的range分区表：</strong></p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;table&nbsp;t_partition_range&nbsp;(id&nbsp;number,name&nbsp;varchar2(50)) <br />
            　　2&nbsp;partition&nbsp;by&nbsp;range(id)( <br />
            　　3&nbsp;partition&nbsp;t_range_p1&nbsp;values&nbsp;less&nbsp;than&nbsp;(10)&nbsp;tablespace&nbsp;tbspart01, <br />
            　　4&nbsp;partition&nbsp;t_range_p2&nbsp;values&nbsp;less&nbsp;than&nbsp;(20)&nbsp;tablespace&nbsp;tbspart02, <br />
            　　5&nbsp;partition&nbsp;t_range_p3&nbsp;values&nbsp;less&nbsp;than&nbsp;(30)&nbsp;tablespace&nbsp;tbspart03, <br />
            　　6&nbsp;partition&nbsp;t_range_pmax&nbsp;values&nbsp;less&nbsp;than&nbsp;(maxvalue)&nbsp;tablespace&nbsp;tbspart04 <br />
            　　7&nbsp;);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　表已创建。</p>
　要查询创建分区的信息，可以通过查询user_part_tables,user_tab_partitions两个数据字典(索引分区、组织分区等信息也有对应的数据字典，后续示例会逐步提及)。
<p>　　user_part_tables：记录分区的表的信息;</p>
<p>　　user_tab_partitions：记录表的分区的信息。</p>
<p>　　例如：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font face="Verdana">JSSWEB&gt; select table_name,partitioning_type,partition_count</font>
            <p><font face="Verdana">&nbsp; 2&nbsp; From user_part_tables where table_name='T_PARTITION_RANGE';</font></p>
            <font face="Verdana">
            <p><br />
            TABLE_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARTITI PARTITION_COUNT</p>
            <p>------------------------------ ------- ---------------</p>
            <p>T_PARTITION_RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</p>
            <p><br />
            JSSWEB&gt; select partition_name,high_value,tablespace_name</p>
            <p>&nbsp; 2&nbsp; from user_tab_partitions where table_name='T_PARTITION_RANGE'</p>
            <p>&nbsp; 3&nbsp; order by partition_position;</p>
            <p><br />
            PARTITION_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HIGH_VALUE TABLESPACE_NAME</p>
            <p>------------------------------ ---------- --------------------</p>
            <p>T_RANGE_P1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>T_RANGE_P2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</p>
            <p>T_RANGE_P3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART03</p>
            <p>T_RANGE_PMAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAXVALUE&nbsp;&nbsp; TBSPART04</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
创建global索引range分区：
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;index&nbsp;idx_parti_range_id&nbsp;on&nbsp;t_partition_range(id) <br />
            　　2&nbsp;global&nbsp;partition&nbsp;by&nbsp;range(id)( <br />
            　　3&nbsp;partition&nbsp;i_range_p1&nbsp;values&nbsp;less&nbsp;than&nbsp;(10)&nbsp;tablespace&nbsp;tbspart01, <br />
            　　4&nbsp;partition&nbsp;i_range_p2&nbsp;values&nbsp;less&nbsp;than&nbsp;(40)&nbsp;tablespace&nbsp;tbspart02, <br />
            　　5&nbsp;partition&nbsp;i_range_pmax&nbsp;values&nbsp;less&nbsp;than&nbsp;(maxvalue)&nbsp;tablespace&nbsp;tbspart03);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　索引已创建。</p>
<p>　　由上例可以看出，创建global索引的分区与创建表的分区语句格式完全相同，而且其分区形式与索引所在表的分区形式没有关联关系。</p>
<p>　　注意：我们这里借助上面的表t_partition_range来演示创建range分区的global索引，并不表示range分区的表，只能创建range分区的global索引，只要你想，也可以为其创建hash分区的global索引。</p>
<p>　　查询索引的分区信息可以通过user_part_indexes、user_ind_partitions两个数据字典：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font face="Verdana">JSSWEB&gt; select index_name, partitioning_type, partition_count</font>
            <p><font face="Verdana">&nbsp; 2&nbsp;&nbsp;&nbsp; From user_part_indexes</font></p>
            <p><font face="Verdana">&nbsp; 3&nbsp;&nbsp; where index_name = 'IDX_PARTI_RANGE_ID';</font></p>
            <font face="Verdana">
            <p><br />
            INDEX_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARTITI PARTITION_COUNT</p>
            <p>------------------------------ ------- ---------------</p>
            <p>IDX_PARTI_RANGE_ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3</p>
            <p><br />
            JSSWEB&gt; select partition_name, high_value, tablespace_name</p>
            <p>&nbsp; 2&nbsp;&nbsp;&nbsp; from user_ind_partitions</p>
            <p>&nbsp; 3&nbsp;&nbsp; where index_name = 'IDX_PARTI_RANGE_ID'</p>
            <p>&nbsp; 4&nbsp;&nbsp; order by partition_position;</p>
            <p><br />
            PARTITION_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HIGH_VALUE TABLESPACE_NAME</p>
            <p>------------------------------ ---------- --------------------</p>
            <p>I_RANGE_P1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>I_RANGE_P2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</p>
            <p>I_RANGE_PMAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAXVALUE&nbsp;&nbsp; TBSPART03</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<strong>③　Local分区索引的创建最简单</strong>，例如：
<p>　　仍然借助t_partition_range表来创建索引</p>
<p>　　--首先删除之前创建的global索引</p>
<p>　　JSSWEB&gt; drop index IDX_PARTI_RANGE_ID;</p>
<p>　　索引已删除。</p>
<p>　　JSSWEB&gt; create index IDX_PARTI_RANGE_ID on T_PARTITION_RANGE(id) local;</p>
<p>　　索引已创建。</p>
<p>　　查询相关数据字典：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font face="Verdana">JSSWEB&gt; select index_name, partitioning_type, partition_count</font>
            <p><font face="Verdana">&nbsp; 2&nbsp;&nbsp;&nbsp; From user_part_indexes</font></p>
            <p><font face="Verdana">&nbsp; 3&nbsp;&nbsp; where index_name = 'IDX_PARTI_RANGE_ID';</font></p>
            <font face="Verdana">
            <p><br />
            INDEX_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARTITI PARTITION_COUNT</p>
            <p>------------------------------ ------- ---------------</p>
            <p>IDX_PARTI_RANGE_ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</p>
            <p><br />
            JSSWEB&gt; select partition_name, high_value, tablespace_name</p>
            <p>&nbsp; 2&nbsp;&nbsp;&nbsp; from user_ind_partitions</p>
            <p>&nbsp; 3&nbsp;&nbsp; where index_name = 'IDX_PARTI_RANGE_ID'</p>
            <p>&nbsp; 4&nbsp;&nbsp; order by partition_position;</p>
            <p><br />
            PARTITION_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HIGH_VALUE TABLESPACE_NAME</p>
            <p>------------------------------ ---------- --------------------</p>
            <p>T_RANGE_P1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>T_RANGE_P2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</p>
            <p>T_RANGE_P3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART03</p>
            <p>T_RANGE_PMAX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAXVALUE&nbsp;&nbsp; TBSPART04</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
可以看出，local索引的分区完全继承表的分区的属性，包括分区类型，分区的范围值即不需指定也不能更改，这就是前面说的：local索引的分区维护完全依赖于其索引所在表。
<p>　　不过呢分区名称，以及分区所在表空间等信息是可以自定义的，例如：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　SQL&gt;&nbsp;create&nbsp;index&nbsp;IDX_PART_RANGE_ID&nbsp;ON&nbsp;T_PARTITION_RANGE(id)&nbsp;local&nbsp;( <br />
            　　2&nbsp;partition&nbsp;i_range_p1&nbsp;tablespace&nbsp;tbspart01, <br />
            　　3&nbsp;partition&nbsp;i_range_p2&nbsp;tablespace&nbsp;tbspart01, <br />
            　　4&nbsp;partition&nbsp;i_range_p3&nbsp;tablespace&nbsp;tbspart02, <br />
            　　5&nbsp;partition&nbsp;i_range_pmax&nbsp;tablespace&nbsp;tbspart02 <br />
            　　6&nbsp;);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　索引已创建。</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3"><font face="Verdana">SQL&gt; select index_name, partitioning_type, partition_count</font>
            <p><font face="Verdana">&nbsp; 2&nbsp;&nbsp; From user_part_indexes</font></p>
            <p><font face="Verdana">&nbsp; 3&nbsp; where index_name = 'IDX_PART_RANGE_ID';</font></p>
            <font face="Verdana">
            <p><br />
            INDEX_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PARTITI PARTITION_COUNT</p>
            <p>------------------------------ ------- ---------------</p>
            <p>IDX_PART_RANGE_ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4</p>
            <p><br />
            SQL&gt; select partition_name, high_value, tablespace_name</p>
            <p>&nbsp; 2&nbsp;&nbsp; from user_ind_partitions</p>
            <p>&nbsp; 3&nbsp; where index_name = 'IDX_PART_RANGE_ID'</p>
            <p>&nbsp; 4&nbsp; order by partition_position;</p>
            <p><br />
            PARTITION_NAME&nbsp; HIGH_VALUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLESPACE_NAME</p>
            <p>--------------- --------------- --------------------</p>
            <p>I_RANGE_P1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>I_RANGE_P2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART01</p>
            <p>I_RANGE_P3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</p>
            <p>I_RANGE_PMAX&nbsp;&nbsp;&nbsp; MAXVALUE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TBSPART02</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<strong>创建hash分区</strong>
<p>　　语法如下：[图:hash_partitioning.gif]</p>
<p>　　<img height="166" alt="" src="http://space.itpub.net/attachments/2008/05/7607759_200805081300421.gif" width="400" /></p>
<p>　　语法看起来比range复杂，其实使用起来比range更简单，这里需要我们指定的有：</p>
<p>　　l column:分区依赖列(支持多个，中间以逗号分隔);</p>
<p>　　l partition:指定分区，有两种方式：</p>
<p>　　n 直接指定分区名，分区所在表空间等信息</p>
<p>　　n 只指定分区数量，和可供使用的表空间。</p>
<p>　　<strong>①　创建hash分区表</strong></p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;table&nbsp;t_partition_hash&nbsp;(id&nbsp;number,name&nbsp;varchar2(50)) <br />
            　　2&nbsp;partition&nbsp;by&nbsp;hash(id)( <br />
            　　3&nbsp;partition&nbsp;t_hash_p1&nbsp;tablespace&nbsp;tbspart01, <br />
            　　4&nbsp;partition&nbsp;t_hash_p2&nbsp;tablespace&nbsp;tbspart02, <br />
            　　5&nbsp;partition&nbsp;t_hash_p3&nbsp;tablespace&nbsp;tbspart03);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　表已创建。</p>
<p>　　要实现同样效果，你还可以这样：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;table&nbsp;t_partition_hash2&nbsp;(id&nbsp;number,name&nbsp;varchar2(50)) <br />
            　　2&nbsp;partition&nbsp;by&nbsp;hash(id) <br />
            　　3&nbsp;partitions&nbsp;3&nbsp;store&nbsp;in(tbspart01,tbspart02,tbspart03);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　表已创建。</p>
这就是上面说的，直接指定分区数量和可供使用的表空间。
<p>　　提示：这里分区数量和可供使用的表空间数量之间没有直接对应关系。分区数并不一定要等于表空间数。</p>
<p>　　要查询表的分区信息，仍然是通过user_part_tables,user_tab_partitions两个数据字典，这里不再举例。</p>
<p>　　<strong>②　Global索引hash分区</strong></p>
<p>　　Hash分区索引的子句与hash分区表的创建子句完全相同，例如：</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">　　JSSWEB&gt;&nbsp;create&nbsp;index&nbsp;idx_part_hash_id&nbsp;on&nbsp;t_partition_hash(id) <br />
            　　2&nbsp;global&nbsp;partition&nbsp;by&nbsp;hash(id) <br />
            　　3&nbsp;partitions&nbsp;3&nbsp;store&nbsp;in(tbspart01,tbspart02,tbspart03);</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　索引已创建。</p>
<p>　　查询索引的分区信息也仍是通过user_part_indexes、user_ind_partitions两个数据字典，不再举例。</p>
<p>　　<strong>③　创建Local索引</strong></p>
<p>　　在前面学习range分区时，我们已经对Local索引的特性做了非常清晰的概述，因此这里也不再举例，如有疑问，建议再仔细复习range分区的相关示例，如果还有疑问，当面问我好了:)</p>
<p>　　综上：</p>
<p>　　&#216; 对于global索引分区而言，在10g中只能支持range分区和hash分区，因此后续示例中不会再提及。</p>
<p>　　&#216; 对于local索引分区而言，其分区形式完全依赖于索引所在表的分区形式，不管从创建语法还是理解难度均无技术含量，因此后续也不再提供示例。</p>
<p>　　&#216; 注意，在创建索引时如果不显式指定global或local，则默认是global。</p>
<p>　　&#216; 注意，在创建global索引时如果不显式指定分区子句，则默认不分区(废话)。<br />
全面学习Oracle分区表及分区索引(4)-创建list分区</p>
<strong>创建list分区</strong>
<p>　　创建语法如下：[图：list_partitioning.gif]</p>
<p>　　<img height="111" alt="" src="http://space.itpub.net/attachments/2008/05/7607759_200805120936071.gif" width="400" /></p>
<p>　　<strong>需要我们指定的有：</strong></p>
<p>　　l column:分区依赖列，注意：只能是一个;</p>
<p>　　l <a class="fllink" href="http://whatis.ctocio.com.cn/searchwhatis/427/6025927.shtml" target="_bank">partition</a>:分区名称;</p>
<p>　　l literal:分区对应值，注意：每个分区可以对应多个值;</p>
<p>　　l tablespace_clause:分区的存储属性，例如所在表空间等属性(可为空)，默认继承基表所在表空间的属性。</p>
<p>　<strong>　创建list分区表示例：</strong></p>
<p>　　JSSWEB&gt; create <a class="fllink" href="http://whatis.ctocio.com.cn/searchwhatis/456/6028456.shtml" target="_bank">table</a> t_partition_list (id number,name varchar2(50))</p>
<p>　　2 partition by list(id)(</p>
<p>　　3 partition t_list_p1 values (1,2,3,4,5,6,7,8,9) <a class="fllink" href="http://whatis.ctocio.com.cn/searchwhatis/458/6028458.shtml" target="_bank">tablespace</a> tbspart01,</p>
<p>　　4 partition t_list_p2 values (10,11,12,13,14,15,16,17,18,19) tablespace tbspart02,</p>
<p>　　5 partition t_list_p3 values (20,21,22,23,24,25,26,27,28,29) tablespace tbspart03,</p>
<p>　　6 partition t_list_pd values (default) tablespace tbspart04);</p>
<p>　　表已创建。</p>
<p>　　上例能够实现与前面range分区示例相同的效果，当然针对本示例而言，list分区显然不好用啊~~~</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-05 12:56 <a href="http://www.blogjava.net/caizh2009/articles/312092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 触发器 trigger 调试</title><link>http://www.blogjava.net/caizh2009/articles/312015.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 10:25:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312015.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312015.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312015.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312015.html</trackback:ping><description><![CDATA[trigger不能直接使用断点调式：<br />
不过可以通过 抛出异常 确定出现问题的位置，并通过打印出相关变量的值<br />
&nbsp;RAISE_APPLICATION_ERROR(-20001, '工单状态已经为最终状态,不能变更!');<br />
&nbsp;exception <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; when others then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbms_output.put_line(:new.task_info_id||' '||sqlerrm||'&nbsp; '||sqlcode);
<img src ="http://www.blogjava.net/caizh2009/aggbug/312015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 18:25 <a href="http://www.blogjava.net/caizh2009/articles/312015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于错误:"ORA-04091: table is mutating, trigger/function may not see it"的分析(触发器操作自身表)</title><link>http://www.blogjava.net/caizh2009/articles/312014.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 10:22:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/312014.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/312014.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/312014.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/312014.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/312014.html</trackback:ping><description><![CDATA[<p>在写trigger的时候,经常会遇到这种情况<br />
当在程序块中需要对trigger本表进行修改或查询的时候,系统会提示错误:&nbsp;&nbsp;ORA-04091: table is mutating, trigger/function may not see it<br />
<br />
关于这个错误,其实是由于对本表的操作造成的.ORACLE DB里默认在写TRIGGER的时候把本表锁死,不允许对其进行操作,也就是说这个错误是不能通过系统的手段解决的,只能改用一些其它的SQL来绕开它.<br />
<br />
<span style="background-color: yellow">对此可通过<span style="color: red">自治事物</span>解决：<br />
<br />
</p>
<div class="t_msgfont" id="message11143957">SQL&gt; CREATE TABLE T(ID NUMBER(18),MC VARCHAR2(20),DT DATE);<br />
<br />
表已创建。<br />
<br />
SQL&gt; CREATE OR REPLACE TRIGGER TR_T<br />
&nbsp;&nbsp;2&nbsp;&nbsp;AFTER DELETE ON T<br />
&nbsp;&nbsp;3&nbsp;&nbsp;FOR EACH ROW<br />
&nbsp;&nbsp;4&nbsp;&nbsp;DECLARE V_COUNT NUMBER;<br />
&nbsp;&nbsp;5&nbsp;<span style="color: red">&nbsp;--PRAGMA AUTONOMOUS_TRANSACTION;<br />
</span>&nbsp;&nbsp;6&nbsp;&nbsp;BEGIN<br />
&nbsp;&nbsp;7&nbsp; &nbsp;&nbsp;&nbsp;INSERT INTO T VALUES(:OLD.ID,:OLD.MC,SYSDATE);<br />
&nbsp;&nbsp;8&nbsp; &nbsp;&nbsp;&nbsp;COMMIT;<br />
&nbsp;&nbsp;9&nbsp;&nbsp;END TR_DEL_CABLE;<br />
10&nbsp;&nbsp;/<br />
<br />
触发器已创建<br />
<br />
SQL&gt; INSERT INTO T VALUES(1,'111111',SYSDATE);<br />
<br />
已创建 1 行。<br />
<br />
SQL&gt; INSERT INTO T VALUES(2,'222222',SYSDATE);<br />
<br />
已创建 1 行。<br />
<br />
SQL&gt; COMMIT;<br />
<br />
提交完成。<br />
<br />
SQL&gt; SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;ID MC&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; TO_CHAR(DT,'YYYYM<br />
---------- -------------------- -----------------<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 111111&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:36<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2 222222&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:43<br />
<br />
SQL&gt; DELETE FROM T WHERE ID=1;<br />
DELETE FROM T WHERE ID=1<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;*<br />
第 1 行出现错误:<br />
ORA-04091: 表 TEST.T 发生了变化, 触发器/函数不能读它<br />
ORA-06512: 在 "TEST.TR_T", line 4<br />
ORA-04088: 触发器 'TEST.TR_T' 执行过程中出错<br />
<br />
<br />
SQL&gt; SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;ID MC&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; TO_CHAR(DT,'YYYYM<br />
---------- -------------------- -----------------<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 111111&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:36<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2 222222&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:43<br />
<br />
SQL&gt; CREATE OR REPLACE TRIGGER TR_T<br />
&nbsp;&nbsp;2&nbsp;&nbsp;AFTER DELETE ON T<br />
&nbsp;&nbsp;3&nbsp;&nbsp;FOR EACH ROW<br />
&nbsp;&nbsp;4&nbsp;&nbsp;DECLARE V_COUNT NUMBER;<br />
&nbsp;&nbsp;5&nbsp;&nbsp;<span style="color: red">PRAGMA AUTONOMOUS_TRANSACTION;--开启自治事物</span><br />
&nbsp;&nbsp;6&nbsp;&nbsp;BEGIN<br />
&nbsp;&nbsp;7&nbsp; &nbsp;&nbsp;&nbsp;INSERT INTO T VALUES(:OLD.ID,:OLD.MC,SYSDATE);<br />
&nbsp;&nbsp;8&nbsp; &nbsp;&nbsp;&nbsp;COMMIT<span style="color: red">;--提交自治事物</span><br />
&nbsp;&nbsp;9&nbsp;&nbsp;END TR_DEL_CABLE;<br />
10&nbsp;&nbsp;/<br />
<br />
触发器已创建<br />
<br />
SQL&gt; DELETE FROM T WHERE ID=1;<br />
<br />
已删除 1 行。<br />
<br />
SQL&gt; COMMIT;<br />
<br />
提交完成。<br />
<br />
SQL&gt; SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;ID MC&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; TO_CHAR(DT,'YYYYM<br />
---------- -------------------- -----------------<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2 222222&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:07:43<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 111111&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20080802 11:08:32<br />
<br />
</div>
</span>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/312014.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 18:22 <a href="http://www.blogjava.net/caizh2009/articles/312014.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle java</title><link>http://www.blogjava.net/caizh2009/articles/311933.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 04:48:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/311933.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/311933.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/311933.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/311933.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/311933.html</trackback:ping><description><![CDATA[<p>利用Java存储过程沟通SQL、XML、Java、J2EE和Web服务。 </p>
<p>存储过程（stored procedure）允许将运行于数据库层中的持久性逻辑与运行于中间层中的商务逻辑有效地分离开来。这种分离可以降低整个应用程序的复杂性，并提供其重用性、安全性、性能和可伸缩性。 </p>
<p>但是，妨碍存储过程广泛采用的一个主要障碍是不同数据库厂商使用各种专有的、且依赖于数据库的实现语言。使用基于Java的存储过程可以解决这一问题。Oracle已经实现了ANSI标准，这些标准规定了从SQL中将静态Java方法作为过程或函数进行调用的能力。这种实现被简单地称作"Java存储过程"。</p>
<p>在本文中，你将了解基于Java的存储过程如何帮助简化商务逻辑、提高其性能，并扩展数据库的功能。本文将介绍Oracle如何在数据库内启用基于Java的存储过程。还会介绍Java存储过程如何访问数据，以及如何创建基本Java存储过程。 </p>
<p>选择PL/SQL还是Java</p>
<p>在考虑Oracle存储过程时，你可能会想到PL/SQL。不过，从Oracle8i开始，Oracle已经在数据库中支持Java，从而为存储过程提供了不同于PL/SQL的开放式和可移植的方法。我可以听到"$64 000问题"："我如何在PL/SQL和Java之间做出选择？我是否应当忘记已经学习的所有PL/SQL相关知识，而变为一个Java天地的新手？" </p>
<p>两种语言都适用于数据库编程，都有自己的优点和弱点。在决定选择哪一种语言时，可以参考下面根据经验得出的通用规则： </p>
<p><br />
对于要求与SQL进行无缝集成的数据库中心来说则逻辑使用PL/SQL，从而完成对数据库对象、类型和特性的访问。 </p>
<p><br />
出于与数据库的无关性考虑时，可以选择Java作为开放式的语言来取代PL/SQL，同时也为了集成和沟通SQL、XML、J2EE和Web服务等各个领域。 <br />
OralceJVM使得Java可以运行在数据库中</p>
<p>从Oracle8i版本1（Oralce8.1.5）开始，Oracle便提供紧密集成的Java虚拟机（JVM），JVM支持Oralce的数据库会话期结构。任何数据库对话期都可以在第一Java代码调用时启动一个虚拟上专用的JVM，后续的用户可以使用这一已经存在的支持Java的会话期。事实上，所有会话共享同一JVM代码并保持"仅静态"的私有状态，而垃圾则收集在单个对话期空间内，从而为各个Java对话期提供了和SQL操作相同的对话期隔离和数据完整性能力。这里，不需要为了数据完整性而进行单独的Java支持的过程。这一基于对话期的结构提供了较小的内存占用率，并使OracleJVM具有与Oracle数据库一样的线性SMP可伸缩性。 </p>
<p>创建Java存储过程 </p>
<p>要将Java方法转换为Java存储过程需要几个步骤，包括：用loadjava实用程序将Java类加载到数据库中，利用调用规范（Call Spec）发布Java方法，将Java方法、参数类型和返回类型映射到其SQL的对应部分。下面部分说明如何完成这些步骤。 </p>
<p>我将使用一个简单的Hello类，它有一个方法Hello.world()，返回字符串"Hello world"：</p>
<p><br />
public class Hello { public static String world () { return "Hello world"; } } <br />
Loadjava 实用程序</p>
<p>Loadjava是加载Java源文件、Java类文件和Java资源文件的实用程序，它可以用来验证字节码，并将Java类和JAR文件布置到数据库中。它既可以通过命令行调用，也可以通过包含于DBMS_JAVA类中的loadjava()方法调用。为了加载我们的Hello.class示例，输入：</p>
<p><br />
loadjava -user scott/tiger Hello.class </p>
<p>从Oracle9i版本2开始，loadjava允许通过为包含在被处理的类中的方法创建相应的Call Specs来自动将Java类发布为存储过程。Oracle为开发、测试、调试和布置Java存储过程提供了Oracle9i JDeveloper。</p>
<p>The Resolver Spec </p>
<p>基于JDK的JVM在列于CLASSPATH中的目录中查找类引用，并对其进行解析。因为Oracle数据库类存在于数据库模式中，所以OracleJVM利用数据库解析器（resolver）通过列于Resolver Spec中的模式查找并解析类引用。与CLASSPATH不同（CLASSPATH可以应用于所有的类），Resover Spec根据每类的情况进行应用。缺省解析器首先在加载类的模式中搜寻类，然后在公共同义词（public synonyms）中搜索。 </p>
<p><br />
&nbsp;loadjava -resolve &lt;myclass&gt; <br />
你可能需要指定不同的解析器，也可以在使用loadjava时强制进行解析，从而在布置时确定可能在以后运行时发生的任何问题。 </p>
<p><br />
loadjava -resolve -resolver "((* SCOTT) (foo/bar/* OTHERS) (* PUBLIC))" <br />
Call Spec和存储过程调用 </p>
<p>为了从SQL中调用Java方法（以及从PL/SQl和JDBC中调用），必须首先通过Call Spec发布公共静态方法，它为SQL定义方法采用的参数以及返回的SQL类型。</p>
<p>在我们的例子中，我们将利用SQL＊Plus连接到数据库，并为Hello.world()定义一个顶级Call Spec： </p>
<p><br />
SQL&gt; connect scott/tiger SQL&gt; create or replace function helloworld return VARCHAR2 as language java name 'Hello.world () return java.lang.String'; / Function created. <br />
可以像下面这样调用Java存储过程：</p>
<p><br />
SQL&gt; variable myString varchar2[20]; SQL&gt; call helloworld() into :myString; Call completed. SQL&gt; print myString; MYSTRING --------------------- Hello world <br />
Java存储过程可以通过其Call Spec从以下各项中进行调用：SQL DML语句（INSERT, UPDATE、DELETE、SELECT、CALL、EXPLAIN PLAN、LOCK TABLE和MERGE）、PL/SQL块、子程序、程序包以及数据库触发器。Call Spec的美妙之处在于存储过程实现可以从PL/SQL转换为Java，反之亦可，这一点对于请求者是透明的。</p>
<p>Call Spec从实现语言中（PL/SQL或Java）中抽象出调用界面，因而使之能够在原有应用程序和新的基于Java／J2EE的应用程序之间共享商务逻辑。但是，在从Java客户程序调用在数据库驻留的Java类时，你可能不希望通过PL/SQL包装器(wrapper)。在以后的版本中，Oracle计划提供一种机制，它可以使开发人员略过Call Spec。</p>
<p>高级数据访问控制 </p>
<p>Java存储过程可用于控制和限制对Oracle数据的访问，其方法是只允许用户通过存储过程管理数据，而存储过程在其调用者的权限内执行，而不能对表本身进行访问。例如，你可以在特定时间内禁止更新数据，或者使管理者只具有查询工资数据的权利，而不能进行更新，或者记录所有的访问并通知某一安全机构。</p>
<p>原有应用程序与J2EE应用程序之间的数据逻辑共享</p>
<p>因为原有应用程序与J2EE应用程序都通过Call Spec调用存储过程，所以J2EE和非J2EE应用程序可以共享相同的数据逻辑。由于有了Call Spec，所以不用考虑所用的是何种实现语言（无论是PL/SQL还是Java），该数据逻辑都可以共享。 </p>
<p>为BMP实体Bean自动生成主关键字</p>
<p>在对EJB实体bean应用BMP时，一个bean实例可以由自动生成的与新插入的数据相关联的主关键字惟一确定，它是ejbCreate()的返回值。可以利用一个插入相应数据的存储过程在一个数据库操作中检索ejbCeater()中的该值，并检索或计算主关键字。作为另一种方法，也可以利用JDBC3.0的RETURN_GENERATED_KEYS特性，以一个SQL语句插入该数据并检索相应的关键字（或ROWID）。但是，存储过程方法在各个JDBC驱动器版本和数据库之间更具可移植性。</p>
<p>可以用以下三个步骤实现这一模式：</p>
&gt;<br />
创建一个Java存储过程，在公共GenPk类中定义一个公共静态Java方法insertAccount()。此方法将插入数据、计算惟一的关键字（通过发出一个序列号），并返回计算出的关键字作为主关键字。
<p>&nbsp;</p>
<p><br />
定义Call Spec </p>
<p><br />
CREATE OR REPLACE PROCEDURE insertAccount(owner IN varchar, bal IN number, newid OUT number) AS LANGUAGE JAVA NAME 'GenPK.insertAccount( java.lang.String [])'; / </p>
<p><br />
在ejbCreate()内调用存储过程 </p>
<p><br />
Public AccountPK ejbCreate(String ownerName, int balance) throws CreateException { try { CallableStatement call = conn.prepareCall{ "{call insertAccount(?, ?, ?)}"}; return new AccountPK(accountID); } } <br />
为CMP实体Bean定制主关键字查找器 </p>
<p>查找器方法（Finder methods）用于检索已存在的EJB实体bean实例。主关键字查找器使你能够检索惟一标识的EJB实例。对于CMP实体bean，EJB容器根据声明描述，自动生成主关键字查找器findByPrimaryKey()方法。但是，在某些情况下，可能需要更多的控制，例如可能需要专门的查找器，如findByStoredProcKey()。在这些情况下，你可以结合使用Java存储过程和对象关系框架（如Oracle9i应用服务器[Oracle9iAS] TopLink）来实现定制的主关键字查找器方法。在将EJB查找器定义为REDIRECT或NAMED查找器后，TopLink将生成一个SQL查询用于检索bean实例。</p>
<p>数据驱动的EJB调用 </p>
<p>在数据驱动体系结构中，商务逻辑调用可以作为数据库操作（如插入、更新或删除）的结果来触发。实现该数据逻辑的Java存储过程可以被声明为数据库触发器，用以调用运行于中间层J2EE应用服务器的EJB。EJB的调用既可以采用J2EE1.3兼容的服务器通过Interoperable Inter-ORB Protocol（IIOP）标准远程方法调用（remote method invocation，RMI）实现，也可以通过销售商特定的传输协议（如Oracle9iAS/Oc4J的ORMI，或者通过BEA WebLogic的T3）用RMI来实现。每个应用服务器提供商在提供基于IIOP的RMI，以提供互操作性的同时，都有其自己优化的协议。Oracle9iAS同时支持基于IIOP的RMI调用和基于ORMI协议的RMI调用。 </p>
<p>数据驱动的消息传送 </p>
<p>Oracle9i数据库嵌入了Advanced Queuing（AQ，高级排队），它是一种集成的、稳定、可靠、安全、可扩展和事务处理式的消息排队框架。Oracle通过标准的Java消息传送系统（Java Messaging System，JMS）API为Java开发人员提供AQ功能。Java存储过程可以通过JMS接口调用AQ操作，从而能够实现快速、在会话期内、可扩展的、数据驱动的消息传送。 </p>
<p>Java存储过程可以利用JMS调用AQ操作。可以用以下4个步骤实现这一模式：</p>
<p><br />
创建并启动JMS Queue（为此，可以将以下一些操作嵌入SQL脚本内）： </p>
<p><br />
execute dbms_aqadm.create_queue_table(queue_table =&gt; 'queue1', queue_payload_type =&gt; 'SYS.AQ$_JMS_TEXT_MESSAGE', comment =&gt; 'a test queue', multiple_consumers =&gt; false, compatible =&gt; '8.1.0'); execute dbms_aqadm.create_queue( queue_name =&gt; 'queue1', queue_table =&gt; 'queue1' ); execute dbms_aqadm.start_queue(queue_name =&gt; 'queue1'); </p>
<p><br />
创建Java存储过程（代码摘录如下）： </p>
<p><br />
public static void runTest(String msgBody) { try { // get database connection ora_drv = new OracleDriver(); db_conn = ora_drv.defaultConnection(); // setup sender (cf online code sample) .. // create message s_msg = s_session.createTextMessage(msgBody); // send message sender.send(s_msg); s_session.commit(); // receive message r_msg = (TextMessage) receiver.receive(); r_session.commit(); // output message text String body = r_msg.getText(); System.out.println("message was '"+body+"'"); ..} } </p>
<p><br />
创建Call Spec： </p>
<p><br />
create or replace procedure jmsproc (t1 IN VARCHAR) as language java name 'jmsSample.main (java.lang.String[])'; / </p>
<p><br />
调用存储过程： </p>
<p><br />
call jmsproc('hello'); <br />
数据库辅助的Web发布（缓冲失效）</p>
<p>各应用程序结构必须面对的一个共同问题是如果可靠地将数据库信息进行缓存，以提高整个系统的性能。JCACHE是一种即将公布的标准规范（JSR 107），它可以解决这一问题。它说明了一种对Java对象临时在内存中进行缓存的方法，包括对象的创建、共享访问、假脱机（spooling）、失效、各JVM的一致性等。它可被用于缓存JSP内最经常读取的数据，如产品目录和价格列表。利用JCACHE，多数查询的反应时间会因为有缓存的数据而加快（内部测试表明反应时间大约快15倍）。 </p>
<p>为了跟踪原始数据的所有变化，并刷新已缓存的数据，Java存储过程会作为一个触发器被附加在一个表上。这个表的任何变化都会自动调用该存储过程，后者再调出一个已定义的JSP使JCACHE对象失效，该对象将其状态映射到该数据库表。在失效时，紧跟其后的查询将强制缓存器根据数据库的数据进行更新。 下面的步骤 <br />
阅读关于Java存储过程的更多信息<br />
本文摘自白皮书"释放Java存储过程的能量（Unleash the Power of Java Stored Procedures）"，可以在以下位置找到该白皮书：<br />
otn.oracle.com/tech/java/java_db/pdf/<br />
OW_30820_JAVA_STORED_PROC_paper.PDF </p>
<p>Oracle9i数据库第2版中的新PL/SQL特性<br />
otn.oracle.com/tech/pl_sql/pdf/<br />
Paper_30720_Doc.pdf </p>
<p>Resolver Spec<br />
otn.oracle.com/docs/products/oracle9i/<br />
doc_library/release2/java.920/a96659.pdf </p>
<p>OracleJVM and Java 2 Security<br />
otn.oracle.com/docs/products/oracle9i/<br />
doc_library/release2/java.920/a96656.pdf </p>
<p>下载代码<br />
练习本文中的代码示例： <br />
otn.oracle.com/sample_code/tech/<br />
java/jsp/Oracle9iJSPSamples.html </p>
<p>了解作为Web服务的存储过程<br />
otn.oracle.com/tech/webservices <br />
&nbsp;</p>
<p><br />
扩展数据库的功能 </p>
<p>在数据库中直接运行Java代码的一个妙处就在于要实现新的功能，只需要简单地加载代码或库，并利用Call Spec制作可用于SQL、PL/SQL、Java、J2EE和非Java API的进入点（公共静态方法）。Oracle9i数据库用户可以很容易地扩展数据库</p>
功能。Oracle自己利用这种能力来获得新的应用程序和工具包，如XML Developer Kits（XDKs）。
<p>&nbsp;</p>
<p>沟通SQL、PL/SQL、Java、J2EE、.NET和XML </p>
<p>Oracle XDK是用Java编写的，并将其公共方法可用作Java存储过程，从而扩展了数据库的XML可编程能力。SQL、PL/SQL、Java、J2EE和非Java（.NET）商务逻辑都能够访问XML分析器、XSLT处理器、XPath引擎和XML SQL Utility（XSU）。 </p>
<p>XML分析器可以通过xmlparser和xmldom包进行访问。XSU是一种Java实用程序，它可以由SQL查询结果或JDBC ResultSet生成XML文档，并将XML文档中的数据写入数据库表或视图中。利用XSU，XML输出可以输出为文本、Dom树或DTS。通过dbms_xmlquery和dbms_xmlsave包，XSU即可用于PL/SQL。 </p>
<p>结论</p>
<p>Oracle数据库与Java VM的集成可以创建可移植、功能强大和与数据库无关的数据逻辑和持续性逻辑（persistence logic）。运行于中间层的商务逻辑和运行于数据库层的数据逻辑之间的分离提高了应用程序的可扩展性、灵活性和可维护性。</p>
<p<p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/311933.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 12:48 <a href="http://www.blogjava.net/caizh2009/articles/311933.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 调用 java简单示例</title><link>http://www.blogjava.net/caizh2009/articles/311926.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 04:39:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/311926.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/311926.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/311926.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/311926.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/311926.html</trackback:ping><description><![CDATA[<div id="hunter_recommended" style="border-right: #ccc 1px solid; padding-right: 4px; border-top: #ccc 1px solid; padding-left: 4px; background: #fff; float: left; margin-bottom: 10px; padding-bottom: 4px; border-left: #ccc 1px solid; width: 557px; padding-top: 4px; border-bottom: #ccc 1px solid"><span id="hunters_nav" style="margin-right: 5px"><a style="border-right: #ccc 1px solid; padding-right: 3px; border-top: #ccc 1px solid; padding-left: 3px; padding-bottom: 0px; border-left: #ccc 1px solid; padding-top: 0px; border-bottom: #ccc 1px solid; text-decoration: none; size: 13px" onclick="hunter_id <= 0 ? hunter_id = hunters.length - 1 : hunter_id--; $('hunters').update(hunters[hunter_id]);return false;" href="http://www.javaeye.com/topic/248953#">&lt;</a> <a style="border-right: #ccc 1px solid; padding-right: 3px; border-top: #ccc 1px solid; padding-left: 3px; padding-bottom: 0px; border-left: #ccc 1px solid; padding-top: 0px; border-bottom: #ccc 1px solid; text-decoration: none; size: 13px" onclick="hunter_id >= hunters.length - 1 ? hunter_id = 0 : hunter_id++; $('hunters').update(hunters[hunter_id]);return false;" href="http://www.javaeye.com/topic/248953#">&gt;</a> </span>猎头职位: <span id="hunters"><script type="text/javascript">document.write(hunters[hunter_id]);</script><a style="color: #000" href="http://www.javaeye.com/jobs/522" target="_blank"><span style="font-weight: bold">上海: </span>上海:25---40万年薪诚聘技术经理</a></span> </div>
<div style="position: relative" _madepositioned="true">前提是数据库上需要安装java虚拟机(JVM),使用下面的语句查看 </div>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/248953#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>select&nbsp;*&nbsp;from&nbsp;dba_registry&nbsp;where&nbsp;comp_id&nbsp;=&nbsp;</span><span class="string">'JAVAVM'</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">select * from dba_registry where comp_id = 'JAVAVM'</pre>
<br />
为空,则未安装,请执行 $ORACLE_HOME/javavm/install/initjvm.sql安装. <br />
创建函数 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/248953#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>create&nbsp;or&nbsp;replace&nbsp;function&nbsp;fn_oraclecall(mArea&nbsp;in&nbsp;VARCHAR2,mDevID&nbsp;in&nbsp;Number,mPORT&nbsp;in&nbsp;Number) &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">return</span><span>&nbsp;varchar2 &nbsp;&nbsp;</span></span></li>
    <li><span>as &nbsp;&nbsp;</span></li>
    <li><span>language&nbsp;java&nbsp;name&nbsp;</span><span class="string">'Caller.call(java.lang.String,Integer,Integer)&nbsp;return&nbsp;java.lang.String'</span><span>;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">create or replace function fn_oraclecall(mArea in VARCHAR2,mDevID in Number,mPORT in Number)
return varchar2
as
language java name 'Caller.call(java.lang.String,Integer,Integer) return java.lang.String';</pre>
<br />
<br />
创建存储过程 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/248953#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>create&nbsp;or&nbsp;replace&nbsp;procedure&nbsp;CHK_SETCAB_NUM &nbsp;&nbsp;</span></span></li>
    <li><span>(mArea&nbsp;in&nbsp;VARCHAR2,mDevID&nbsp;in&nbsp;Number,mPORT&nbsp;in&nbsp;Number,v_out&nbsp;out&nbsp;varchar2)&nbsp;is &nbsp;&nbsp;</span></li>
    <li><span>begin &nbsp;&nbsp;</span></li>
    <li><span>v_out&nbsp;:=&nbsp;fn_oraclecall(mArea,mDevID,mPORT); &nbsp;&nbsp;</span></li>
    <li><span>end&nbsp;CHK_SETCAB_NUM;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">create or replace procedure CHK_SETCAB_NUM
(mArea in VARCHAR2,mDevID in Number,mPORT in Number,v_out out varchar2) is
begin
v_out := fn_oraclecall(mArea,mDevID,mPORT);
end CHK_SETCAB_NUM;</pre>
<br />
<br />
loadjava <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/topic/248953#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>loadjava&nbsp;-u&nbsp;sys/sys</span><span class="annotation">@sid</span><span>&nbsp;&nbsp;-oci8&nbsp;-verbose&nbsp;-grant&nbsp;user&nbsp;-synonym&nbsp;-resolve&nbsp;-schema&nbsp;user&nbsp;D:\Caller.jar &nbsp;&nbsp;</span></span></li>
    <li><span>--这里也可以是</span><span class="keyword">class</span><span>文件,注意兼容oracle的jre版本&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">loadjava -u sys/sys@sid  -oci8 -verbose -grant user -synonym -resolve -schema user D:\Caller.jar
--这里也可以是class文件,注意兼容oracle的jre版本
</pre>
<br />
<br />
注意编写的java文件里,即Caller.java的call()方法,需要是staic <br />
<img src ="http://www.blogjava.net/caizh2009/aggbug/311926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 12:39 <a href="http://www.blogjava.net/caizh2009/articles/311926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle调用java</title><link>http://www.blogjava.net/caizh2009/articles/311923.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Thu, 04 Feb 2010 04:36:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/311923.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/311923.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/311923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/311923.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/311923.html</trackback:ping><description><![CDATA[前提是数据库上需要安装java虚拟机(JVM),使用下面的语句查看 <br />
<span><span>select&nbsp;*&nbsp;from&nbsp;dba_registry&nbsp;where&nbsp;comp_id&nbsp;=&nbsp;</span><span class="string">'JAVAVM'</span><span>&nbsp;&nbsp;</span></span><br />
为空,则未安装,请执行 $ORACLE_HOME/javavm/install/initjvm.sql安装. <br />
<p>一、如何创建java存储过程？<br />
通常有三种方法来创建java存储过程。</p>
<p>1. 使用oracle的sql语句来创建：</p>
<p>e.g. 使用create or replace and compile java source named "&lt;name&gt;" as<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后边跟上java源程序。要求类的方法必须是public static的，才能用于存储过程。</p>
<p>SQL&gt; create or replace and compile java source named "javademo1"<br />
&nbsp; 2&nbsp; as<br />
&nbsp; 3&nbsp; import java.sql.*;<br />
&nbsp; 4&nbsp; public class JavaDemo1<br />
&nbsp; 5&nbsp; {<br />
&nbsp; 6&nbsp; public static void main(String[] argv)<br />
&nbsp; 7&nbsp; {<br />
&nbsp; 8&nbsp; System.out.println("hello, java demo1");<br />
&nbsp; 9&nbsp; }<br />
&nbsp;10&nbsp; }<br />
&nbsp;11&nbsp; /</p>
<p>Java 已创建。</p>
<p>SQL&gt; show errors java source "javademo1"<br />
没有错误。</p>
<p>SQL&gt; create or replace procedure javademo1<br />
&nbsp; 2&nbsp; as<br />
&nbsp; 3&nbsp; language java name ''JavaDemo1.main(java.lang.String[])'';<br />
&nbsp; 4&nbsp; /</p>
<p>过程已创建。</p>
<p>SQL&gt; set serveroutput on<br />
SQL&gt; call javademo1();</p>
<p>调用完成。</p>
<p>SQL&gt; call dbms_java.set_output(5000);</p>
<p>调用完成。</p>
<p>SQL&gt; call javademo1();<br />
hello, java demo1</p>
<p>调用完成。</p>
<p>SQL&gt; call javademo1();<br />
hello, java demo1<br />
调用完成。<br />
2. 使用外部class文件来装载创建<br />
e.g. 这里既然用到了外部文件，必然要将class文件放到oracle Server的某一目录下边。</p>
<p><br />
public class OracleJavaProc<br />
{<br />
&nbsp;&nbsp;&nbsp; public static void main(String[] argv)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("It''s a Java Oracle procedure.");<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p><br />
SQL&gt; grant create any directory to scott;</p>
<p>授权成功。</p>
<p>SQL&gt; conn scott/tiger@iihero.oracledb<br />
已连接。<br />
SQL&gt; create or&nbsp;&nbsp; replace&nbsp;&nbsp; directory&nbsp;&nbsp; test_dir&nbsp;&nbsp; as&nbsp; ''d:\oracle'';</p>
<p>目录已创建。</p>
<p>SQL&gt; create or replace java class using bfile(test_dir, ''OracleJavaProc.CLASS'')<br />
&nbsp; 2&nbsp; /</p>
<p>Java 已创建。</p>
<p>SQL&gt; create or replace procedure testjavaproc as language java name ''OracleJavaProc.main(java.lang.String[])'';<br />
&nbsp; 2&nbsp; /</p>
<p>过程已创建。</p>
<p>SQL&gt; call testjavaproc();</p>
<p>调用完成。</p>
<p>SQL&gt; execute testjavaproc;</p>
<p>PL/SQL 过程已成功完成。</p>
<p>SQL&gt; set serveroutput on size 5000<br />
SQL&gt; call dbms_java.set_output(5000);</p>
<p>调用完成。</p>
<p>SQL&gt; execute testjavaproc;<br />
It''s a Java Oracle procedure.<br />
3. 我推荐的一种方法，直接使用loadjava命令远程装载并创建。<br />
&nbsp;&nbsp;&nbsp; 先创建一个类, e.g.</p>
<p><br />
import java.sql.*;<br />
import oracle.jdbc.*;</p>
<p>public class OracleJavaProc ...{</p>
<p>&nbsp;&nbsp; //Add a salgrade to the database.<br />
&nbsp;&nbsp; public static void addSalGrade(int grade, int losal, int hisal) ...{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Creating new salgrade for EMPLOYEE...");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection conn =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DriverManager.getConnection("jdbc:default:connection:");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sql =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "INSERT INTO salgrade " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "(GRADE,LOSAL,HISAL) " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "VALUES(?,?,?)";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PreparedStatement pstmt = conn.prepareStatement(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(1,grade);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(2,losal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(3,hisal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.executeUpdate();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(SQLException e) ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println("ERROR! Adding Salgrade: " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + e.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
}<br />
使用loadjava命令将其装载到服务器端并编译：</p>
<p><br />
D:eclipse3.1workspacedbtest&gt;loadjava -u scott/tiger@iihero.oracledb -v -resolve Or<br />
acleJavaProc.java<br />
arguments: ''-u'' ''scott/tiger@iihero.oracledb ''-v'' ''-resolve'' ''OracleJavaProc.java''<br />
creating : source OracleJavaProc<br />
loading&nbsp; : source OracleJavaProc<br />
resolving: source OracleJavaProc<br />
查询一下状态：</p>
<p><br />
连接到:<br />
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production<br />
With the Partitioning, OLAP and Oracle Data Mining options<br />
JServer Release 9.2.0.1.0 - Production</p>
<p>SQL&gt; SELECT object_name, object_type, status FROM user_objects WHERE object_type LIKE ''JAVA%'';</p>
<p>OBJECT_NAME<br />
--------------------------------------------------------------------------------</p>
<p>OBJECT_TYPE&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; STATUS<br />
------------------------------------ --------------<br />
OracleJavaProc<br />
JAVA CLASS&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; VALID</p>
<p>OracleJavaProc<br />
JAVA SOURCE&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; VALID<br />
测试一下存储过程：</p>
<p><br />
SQL&gt; create or replace procedure add_salgrade(id number, losal number, hisal num<br />
ber) as language java name ''OracleJavaProc.addSalGrade(int, int, int)'';<br />
&nbsp; 2&nbsp; /</p>
<p>过程已创建。</p>
<p>SQL&gt; set serveroutput on size 2000<br />
SQL&gt; call dbms_java.set_output(2000);</p>
<p>调用完成。</p>
<p>SQL&gt; execute add_salgrade(6, 10000, 15000);<br />
Creating new salgrade for EMPLOYEE...</p>
<p>PL/SQL 过程已成功完成。</p>
<p>SQL&gt; select * from salgrade where grade=6;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; GRADE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOSAL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HISAL<br />
---------- ---------- ----------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 15000<br />
&nbsp;</p>
<p>二、如何更新你已经编写的java存储过程？&nbsp; </p>
<p>假如要往类OracleJavaProc里添加一个存储过程方法，如何开发？<br />
正确的步骤应该是先dropjava, 改程序，再loadjava。</p>
<p>e.g.修改OracleJavaProc类内容如下：</p>
<p><br />
import java.sql.*;<br />
import oracle.jdbc.*;</p>
<p>public class OracleJavaProc ...{</p>
<p>&nbsp;&nbsp; // Add a salgrade to the database.<br />
&nbsp;&nbsp; public static void addSalGrade(int grade, int losal, int hisal) ...{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Creating new salgrade for EMPLOYEE...");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection conn =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DriverManager.getConnection("jdbc:default:connection:");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sql =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "INSERT INTO salgrade " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "(GRADE,LOSAL,HISAL) " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "VALUES(?,?,?)";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PreparedStatement pstmt = conn.prepareStatement(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(1,grade);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(2,losal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.setInt(3,hisal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.executeUpdate();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pstmt.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(SQLException e) ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println("ERROR! Adding Salgrade: " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + e.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; public static int getHiSal(int grade)<br />
&nbsp;&nbsp; ...{<br />
&nbsp;&nbsp;&nbsp; try ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection conn =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DriverManager.getConnection("jdbc:default:connection:");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sql = "SELECT hisal FROM salgrade WHERE grade = ?";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PreparedStatement pstmt = conn.prepareStatement(sql);pstmt.setInt(1, grade);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResultSet rset = pstmt.executeQuery();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int res = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rset.next())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; res = rset.getInt(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rset.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return res;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; catch (SQLException e) <br />
&nbsp;&nbsp;&nbsp; ...{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println("ERROR! Querying Salgrade: " <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + e.getMessage());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
}</p>
<p>如何更新呢？</p>
<p><br />
D:eclipse3.1workspacedbtest&gt;dropjava -u scott -v OracleJavaProc</p>
<p>D:/tiger@iihero.oracledbeclipse3.1workspacedbtest&gt;loadjava -u scott -v -resolve Or<br />
acleJavaProc/tiger@iihero.oracledb.java<br />
arguments: ''-u'' ''scott/tiger@iihero.oracledb'' ''-v'' ''-resolve'' ''OracleJavaProc.java''<br />
creating : source OracleJavaProc<br />
loading&nbsp; : source OracleJavaProc<br />
resolving: source OracleJavaProc<br />
后边的应用示例：</p>
<p><br />
SQL&gt; create or replace function query_hisal(grade number) return number as langu<br />
age java name ''OracleJavaProc.getHiSal(int) return int'';<br />
&nbsp; 2&nbsp; /</p>
<p>函数已创建。</p>
<p>SQL&gt; set serveroutput on size 2000<br />
SQL&gt; call dbms_java.set_output(2000);</p>
<p>调用完成。<br />
SQL&gt; select query_hisal(5) from dual;</p>
<p>QUERY_HISAL(5)<br />
--------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9999<br />
全文完！</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/thinker28754/archive/2009/03/07/3962989.aspx</p>
<br />
<img src ="http://www.blogjava.net/caizh2009/aggbug/311923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-02-04 12:36 <a href="http://www.blogjava.net/caizh2009/articles/311923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有效创建oracle dblink 的两种方式</title><link>http://www.blogjava.net/caizh2009/articles/308439.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Wed, 06 Jan 2010 06:32:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/308439.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/308439.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/308439.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/308439.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/308439.html</trackback:ping><description><![CDATA[两台不同的数据库服务器，从一台数据库服务器的一个用户读取另一台数据库服务器下的某个用户的数据，这个时候可以使用dblink。
<p>　　其实dblink和数据库中的view差不多，建dblink的时候需要知道待读取数据库的ip地址，ssid以及数据库用户名和密码。</p>
<p>　　创建可以采用两种方式：</p>
<p>　　1、已经配置本地服务</p>
<p>&nbsp;</p>
<p>
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">以下是引用片段：<br />
            　　create&nbsp;public&nbsp;database <br />
            　　link&nbsp;fwq12&nbsp;connect&nbsp;to&nbsp;fzept <br />
            　　identified&nbsp;by&nbsp;neu&nbsp;using&nbsp;'fjept'</td>
        </tr>
    </tbody>
</table>
　　CREATE DATABASE LINK数据库链接名CONNECT TO 用户名 IDENTIFIED BY 密码 USING &#8216;本地配置的数据的实例名&#8217;;</p>
<p>　　2、未配置本地服务</p>
<p>　　<img height="16" alt="有效创建oracle dblink 的两种方式图片1" src="http://www.abcdown.net/uploadImages/2007-8-28/2007828927317346.gif" width="11" align="top" />
<table style="border-right: #cccccc 1px dotted; table-layout: fixed; border-top: #cccccc 1px dotted; border-left: #cccccc 1px dotted; border-bottom: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
    <tbody>
        <tr>
            <td style="word-wrap: break-word" bgcolor="#f3f3f3">以下是引用片段：<br />
            create&nbsp;database&nbsp;link&nbsp;linkfwq <br />
            　　&nbsp;connect&nbsp;to&nbsp;fzept&nbsp;identified&nbsp;by&nbsp;neu <br />
            　　&nbsp;using&nbsp;'(DESCRIPTION&nbsp;= <br />
            　　&nbsp;(ADDRESS_LIST&nbsp;= <br />
            　　&nbsp;(ADDRESS&nbsp;=&nbsp;(PROTOCOL&nbsp;=&nbsp;TCP)(HOST&nbsp;=&nbsp;10.142.202.12)(PORT&nbsp;=&nbsp;1521)) <br />
            　　&nbsp;) <br />
            　　&nbsp;(CONNECT_DATA&nbsp;= <br />
            　　&nbsp;(SERVICE_NAME&nbsp;=&nbsp;fjept) <br />
            　　&nbsp;) <br />
            　　&nbsp;)';</td>
        </tr>
    </tbody>
</table>
　　host=数据库的ip地址，service_name=数据库的ssid。</p>
<p>　　其实两种方法配置dblink是差不多的，我个人感觉还是第二种方法比较好，这样不受本地服务的影响。</p>
<p>　　数据库连接字符串可以用NET8 EASY CONFIG或者直接修改TNSNAMES.ORA里定义.</p>
<p>　　数据库参数global_name=true时要求数据库链接名称跟远端数据库名称一样</p>
<p>　　数据库全局名称可以用以下命令查出</p>
<p>　　SELECT * FROM GLOBAL_NAME;</p>
<p>　　查询远端数据库里的表</p>
<p>　　SELECT &#8230;&#8230; FROM 表名@数据库链接名;</p>
<p>　　查询、删除和插入数据和操作本地的数据库是一样的，只不过表名需要写成&#8220;表名@dblink服务器&#8221;而已。</p>
<p>　　附带说下同义词创建:</p>
<p>　　CREATE SYNONYM同义词名FOR 表名;</p>
<p>　　CREATE SYNONYM同义词名FOR 表名@数据库链接名;</p>
<p>　　删除dblink：DROP PUBLIC DATABASE LINK linkfwq。</p>
<p>　　如果创建全局dblink，必须使用systm或sys用户，在database前加public。</p>
<p>　　参考资料:</p>
<p>　　<a href="http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14231/ds_admin.htm#i1008271">http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14231/ds_admin.htm#i1008271</a> </p>
<img src ="http://www.blogjava.net/caizh2009/aggbug/308439.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2010-01-06 14:32 <a href="http://www.blogjava.net/caizh2009/articles/308439.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分区表PARTITION table </title><link>http://www.blogjava.net/caizh2009/articles/306536.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 18 Dec 2009 05:28:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/306536.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/306536.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/306536.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/306536.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/306536.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1.1 分区表PARTITION table在ORACLE里如果遇到特别大的表，可以使用分区的表来改变其应用程序的性能。1.1.1 分区表的建立： 某公司的每年产生巨大的销售记录，DBA向公司建议每季度的数据放在一个分区内，以下示范的是该公司1999年的数据(假设每月产生30M的数据)，操作如下： 范围分区表：CREATE TABLE sales (invoice_no N...&nbsp;&nbsp;<a href='http://www.blogjava.net/caizh2009/articles/306536.html'>阅读全文</a><img src ="http://www.blogjava.net/caizh2009/aggbug/306536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/caizh2009/" target="_blank">小菜毛毛</a> 2009-12-18 13:28 <a href="http://www.blogjava.net/caizh2009/articles/306536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 的redo和undo 收藏</title><link>http://www.blogjava.net/caizh2009/articles/306534.html</link><dc:creator>小菜毛毛</dc:creator><author>小菜毛毛</author><pubDate>Fri, 18 Dec 2009 05:17:00 GMT</pubDate><guid>http://www.blogjava.net/caizh2009/articles/306534.html</guid><wfw:comment>http://www.blogjava.net/caizh2009/comments/306534.html</wfw:comment><comments>http://www.blogjava.net/caizh2009/articles/306534.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/caizh2009/comments/commentRss/306534.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/caizh2009/services/trackbacks/306534.html</trackback:ping><description><![CDATA[在这里会介绍UNDO，REDO是如何产生的，对TRANSACTIONS的影响，<br />
以及他们之间如何协同工作的。 什么是REDO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REDO记录transaction logs，分为online和archived。<br />
以恢复为目的。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如，机器停电，那么在重起之后需要online redo logs去恢复系统到失败点。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
比如，磁盘坏了，需要用archived redo logs和online redo logs区恢复数据。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
比如，truncate一个表或其他的操作，想恢复到之前的状态，同样也需要。 <br />
什么是UNDO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
REDO是为了重新实现你的操作，而UNDO相反，是为了撤销你做的操作，比如你得一个TRANSACTION执行失败了或你自己后悔了，<br />
则需要用ROLLBACK命令回退到操作之前。<br />
回滚是在逻辑层面实现而不是物理层面，因为在一个多用户系统中，数据结构，blocks等都在时时变化，<br />
比如我们INSERT一个数据，表的空间不够，扩展了一个新的EXTENT，我们的数据保存在这新的EXTENT里，其它用户随后也在这EXTENT里插入了数据，<br />
而此时我想ROLLBACK，那么显然物理上讲这EXTENT撤销是不可能的，因为这么做会影响其他用户的操作。<br />
所以，ROLLBACK是逻辑上回滚，比如对INSERT来说，那么ROLLBACK就是DELETE了。<br />
COMMIT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
以前，常想当然地认为，一个大的TRANSACTION（比如大批量地INSERT数据）的COMMIT会花费时间比短的TRANSACTION长。<br />
而事实上是没有什么区别的，因为ORACLE在COMMIT之前已经把该写的东西写到DISK中了，<br />
我们COMMIT只是 <br />
1，产生一个SCN给我们TRANSACTION，SCN简单理解就是给TRANSACTION排队，以便恢复和保持一致性。 <br />
2，REDO写REDO到DISK中（LGWR，这就是log file sync），记录SCN在ONLINE REDO LOG，当这一步发生时，我们可以说事实上已经提交了，<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这个TRANSACTION已经结束（在V$TRANSACTION里消失了） <br />
3，SESSION所拥有的LOCK（V$LOCK）被释放。 <br />
4，Block Cleanout（这个问题是产生ORA-01555: snapshot too old的根本原因） ROLLBACK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
ROLLBACK和COMMIT正好相反，ROLLBACK的时间和TRANSACTION的大小有直接关系。<br />
因为ROLLBACK必须物理上恢复数据。COMMIT之所以快，是因为ORACLE在COMMIT之前已经作了很多工作（产生UNDO，修改BLOCK，REDO，LATCH分配），<br />
ROLLBACK慢也是基于相同的原因。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
ROLLBACK会&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
1，恢复数据，DELETE的就重新INSERT，INSERT的就重新DELETE，UPDATE的就再UPDATE。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
2，RELEASE LOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ROLLBACK要比COMMIT消耗更多资源，因为ORACLE认为你一旦做数据更新，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么就意味着你要COMMIT（其他数据库不全是这种设计理念，比如DB2），所以在你更新数据的时候就做了大量的工作，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这也可以理解为什么不建议用TABLE来做TEMPORARY TABLE。<br />
（TEMP TABLE消耗的REDO比固定表在INSERT时要少很多&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ，UPDATE时差不多是1/2，但是DELETE却相差无几） REDO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
产生REDO 越多，你的系统越慢，不但影响你自己的SESSION，还影响其他SESSION，LGWR管理REDO，并且是TRANSACTION的结束标志。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
首先要知道怎么监控REDO，当然，SET AUTOTRACE ON可以，不过只能监控DML语句，而像PROCEDURE则无法监视。那么我们就需要观察字典了，<br />
V$MYSTAT, V$STATNAME，<br />
前面有两个脚本，<br />
mystat，mystat2 SQL&gt; @mystat "redo size" NAME&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;&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; <br />
VALUE ---------------------------------------------------------------- ---------- redo size&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 1016784 SQL&gt; insert into t select * from big_table; 已创建46990行。 <br />
SQL&gt; @mystat2 NAME&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
V ---------------------------------------------------------------- ---------- DIFF ---------------- redo size&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;&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; <br />
6604308&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5,587,524&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 看到产生了5,587,524的REDO，再对比下用NOLOG插入<br />
SQL&gt; @mystat "redo size" NAME&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;&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; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
VALUE ---------------------------------------------------------------- ---------- redo size&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; 6604308 SQL&gt; insert /*+ APPEND */ into t select * from big_table; 已创建46990行。 <br />
SQL&gt; @mystat2 NAME&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; V ---------------------------------------------------------------- ---------- DIFF ---------------- redo size&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6616220&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11,912&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 看到APPEND插入用了11,912字节的REDO，比一般性插入要少很多。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
或者用这个PROCEDURE也可以观察SQL消耗的REDO create or replace procedure do_sql( p_sql in varchar2 ) 2 as 3 l_start_redo number; 4 l_redo number; <br />
5 begin 6 select v$mystat.value 7 into l_start_redo 8 from v$mystat, v$statname 9 where v$mystat.statistic# = v$statname.statistic# 10 and v$statname.name = 'redo size'; <br />
11 12 execute immediate p_sql; 13 commit; 14 15 select v$mystat.value-l_start_redo 16 into l_redo 17 from v$mystat, <br />
v$statname 18 where v$mystat.statistic# = v$statname.statistic# 19 and v$statname.name = 'redo size'; <br />
20 21 dbms_output.put_line 22 ( to_char(l_redo,'9,999,999') ||' bytes of redo generated for "' || 23 substr( replace( p_sql, chr(10), ' '), 1, 25 ) || '"...' ); 24 end; 25 /&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; 用法就不多说了。 减少REDO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 既然REDO这么消耗资源，那我们能屏蔽REDO吗？显然不能，那我们能减少REDO吗？这是可以的<br />
（注意，9.2以后，可以用FORCE LOGGING开关来控制是否强制REDO，如果YES，则不管NOLOGGING还是APPEND都是不起任何作用的，<br />
可以SELECT FORCE_LOGGING FROM V$DATABASE查看是否FORCE。另外需要明白，没有一个办法能彻底不记录REDO，只能是减少REDO。<br />
因为不管如何，数据字典总是要产生一些REDO的。 create table nologging as select xxx新建的表没有原来表的索引和默认值,只有非空(not null)的约束素条件可以继承过来. <br />
INSERT /*+ APPEND */ INTO target_tablename SELECT 如果运行此命令时还有对target_tablename的DML操作会排队在它后面,对OLTP系统在用的表操作是不合适的。<br />
快速插入数据可以指定append提示，但是需要注意 noarchivelog模式下，默认用了append就是nologging模式的。 在archivelog下，需要把表设置程Nologging模式。<br />
可以通过如下语句设置为NO FORCE LOGGING。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Alter database no force logging; 这两种方法转移数据时没有用SGA里数据缓冲区和事物处理的回滚段, <br />
也不写联机事物日志，就象数据库装载工具SQLLOAD一样直接把数据写到物理文件。 REDO的问题 <br />
&nbsp;&nbsp;&nbsp; 有时，会在ALERT中发现 Thread 1 cannot allocate new log, sequence 1466 Checkpoint not complete Current log# 3 seq# 1465 mem# 0: /home/ora10g/oradata/ora10g/redo03.log&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; 这问题出现在系统尝试reuse online redo log file但是却没有可用的。可能是由于DBWR没有完成(Checkpoint not complete)或ARCH没有完成。&nbsp;&nbsp;&nbsp; <br />
&nbsp;