<?xml version="1.0" encoding="GB2312"?>
<rss version="2.0">
<channel>
<title>Friends Life and Oracle</title>
<link>http://www.eygle.com/blog/</link>
<description>eygle的Oracle Blog，提供Oracle技术研究及深入探讨，同时记录个人爱好及生活历程。</description>
<copyright>Copyright 2006</copyright>
<lastBuildDate>Wed, 18 Oct 2006 11:56:39 +0800</lastBuildDate>
<generator>http://www.movabletype.org/?v=3.33</generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs> 

<item>
<title>使用外部表分析eygle.com的网站访问日志</title>
<description><![CDATA[<p>经过使用Oracle的外部表对Oracle的<a href="http://www.eygle.com/archives/2006/10/use_oracle_external_table.html">警告日志</a>文件、<a href="http://www.eygle.com/archives/2006/10/external_table_and_trace_file.html">跟踪文件</a>进行获取和分析之后，我发现外部表实在是非常易用，甚至到了随心所欲的境地（当然外部表尚不能修改外部文件）。</p>

<p>使用外部表可以很容易的实现网站的访问日志分析。<br />
虽然使用<a href="http://www.eygle.com/archives/2004/12/aeoeaawstatsapa.html">Awstats</a>等工具也可以实现，可是使用Oracle来分析我们更应该得心应手。<br />
而且这一切还是有那么一点点Cool的。</p>

<p>好了，闲言少叙，让我们来看一下我分析的过程。<br />
首先创建路径指向日志存放目录:<br />
<blockquote>[oracle@jumper elog]$ pwd<br />
/opt/oracle/elog<br />
[oracle@jumper elog]$ ls<br />
eygle_access_log.20061016<br />
[oracle@jumper elog]$ sqlplus "/ as sysdba"</p>

<p>SQL*Plus: Release 9.2.0.4.0 - Production on Wed Oct 18 08:59:35 2006</p>

<p>Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.</p>

<p><br />
Connected to:<br />
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production<br />
With the Partitioning option<br />
JServer Release 9.2.0.4.0 - Production</p>

<p>SQL> create or replace directory elog <br />
  2  as '/opt/oracle/elog';</p>

<p>Directory created.</blockquote></p>

<p>然后我将这个路径的访问权限授予eygle用户来进行具体操作:</p>

<blockquote>SQL> grant read,write on directory elog to eygle;

<p>Grant succeeded.</blockquote></p>

<p>选择合适的分隔符创建外部表:<br />
<blockquote>SQL> connect eygle/eygle<br />
Connected.</p>

<p>SQL> create table eygle_access_log_20061016 <br />
  2  ( ip_address_date  				varchar2(100),<br />
  3     acc_file                varchar2(400),<br />
  4     acc_cdsz                varchar2(20),<br />
  5     acc_url                 varchar2(400),<br />
  6     left_blank      				varchar2(10),<br />
  7     acc_agent               varchar2(400))<br />
  8     organization external (<br />
  9    type oracle_loader<br />
 10    default directory ELOG<br />
 11    access parameters (<br />
 12      records delimited by newline<br />
 13      nobadfile<br />
 14      nodiscardfile<br />
 15      nologfile<br />
 16      fields terminated by '"'<br />
 17      missing field values are null<br />
 18    )<br />
 19    location('eygle_access_log.20061016')<br />
 20  )  reject limit unlimited<br />
 21  /</p>

<p>Table created.</blockquote></p>

<p>此时我们就可以对<a href="http://www.eygle.com">eygle.com</a>的2006年10月16日的访问日志进行分析了。</p>

<p>我们可以先看一下各个字段的分界结果，示例如下:<br />
<blockquote>SQL> select ip_address_date from eygle_access_log_20061016<br />
  2  where rownum <11;</p>

<p>IP_ADDRESS_DATE<br />
-------------------------------------------------------------<br />
38.102.128.140 - - [16/Oct/2006:00:00:17 +0800]<br />
66.249.65.113 - - [16/Oct/2006:00:00:19 +0800]<br />
202.160.178.221 - - [16/Oct/2006:00:00:35 +0800]<br />
59.36.78.100 - - [16/Oct/2006:00:00:37 +0800]<br />
59.36.78.100 - - [16/Oct/2006:00:00:38 +0800]<br />
72.30.61.8 - - [16/Oct/2006:00:00:38 +0800]<br />
221.217.84.230 - - [16/Oct/2006:00:00:42 +0800]<br />
221.217.84.230 - - [16/Oct/2006:00:00:42 +0800]<br />
74.6.65.236 - - [16/Oct/2006:00:01:07 +0800]<br />
74.6.73.36 - - [16/Oct/2006:00:01:09 +0800]</p>

<p>10 rows selected.</blockquote></p>

<p>通过SQL析取出访问的ip地址:<br />
<blockquote>SQL> select substr(ip_address_date,1,instr(ip_address_date,' ')) ip_address <br />
  2  from eygle_access_log_20061016 where rownum <11;</p>

<p>IP_ADDRESS<br />
---------------------------------------------------------------------------<br />
38.102.128.140<br />
66.249.65.113<br />
202.160.178.221<br />
59.36.78.100<br />
59.36.78.100<br />
72.30.61.8<br />
221.217.84.230<br />
221.217.84.230<br />
74.6.65.236<br />
74.6.73.36</p>

<p>10 rows selected.</blockquote></p>

<p>接下来我们就可以很容易的获得当日访问我站点的独立IP数量了:<br />
<blockquote>SQL> set timing on<br />
SQL> select count(distinct(substr(ip_address_date,1,instr(ip_address_date,' ')))) uip<br />
  2  from eygle_access_log_20061016;</p>

<p>       UIP<br />
----------<br />
      7534</p>

<p>Elapsed: 00:00:06.86</blockquote><br />
因为外部表的处理性能上要差一些，我们记录了一下时间，以上查询大约用了7秒的时间。</p>

<p>我们可以对比一下数据库表的性能。<br />
首先将日志加载到数据库表中:<br />
<blockquote>SQL> create table ealog as<br />
  2  select * from eygle_access_log_20061016;</p>

<p>Table created.</p>

<p>SQL> desc ealog;<br />
 Name                                                              Null?    Type<br />
 ----------------------------------------------------------------- -------- --------------------------------------------<br />
 IP_ADDRESS_DATE                                                            VARCHAR2(100)<br />
 ACC_FILE                                                                   VARCHAR2(400)<br />
 ACC_CDSZ                                                                   VARCHAR2(20)<br />
 ACC_URL                                                                    VARCHAR2(400)<br />
 LEFT_BLANK                                                                 VARCHAR2(10)<br />
 ACC_AGENT                                                                  VARCHAR2(400)</p>

<p>SQL> select count(*) from ealog;</p>

<p>  COUNT(*)<br />
----------<br />
    165443</blockquote></p>

<p>然后我们<a href="http://www.eygle.com/archives/2005/12/oracle_howto_flush_buffer_cache.html">强制刷新Buffer Cache</a>，消除Cache的影响，再次执行查询：<br />
<blockquote>SQL> alter session set events = 'immediate trace name flush_cache';</p>

<p>Session altered.</p>

<p>Elapsed: 00:00:00.03<br />
SQL> select count(distinct(substr(ip_address_date,1,instr(ip_address_date,' ')))) uip<br />
  2  from ealog;</p>

<p>       UIP<br />
----------<br />
      7528</p>

<p>Elapsed: 00:00:02.15</blockquote></p>

<p>此时用了大约2秒的时间，也就是说，外部表的性能较数据库表大约慢了3倍左右。</p>

<p>继续，我们可以查询当日网站中，哪些网页是被最频繁访问的:<br />
<blockquote>SQL> select replace((replace(acc_file,'GET ','http://www.eygle.com')),'HTTP/1.1') accfile,ct from (<br />
  2  select ACC_FILE,count(*) ct from eygle_access_log_20061016<br />
  3  where acc_file like '%htm%'<br />
  4  group by acc_file order by ct desc)<br />
  5  where rownum <21;</p>

<p>ACCFILE                                                                                  CT<br />
-------------------------------------------------------------------------------- ----------<br />
http://www.eygle.com/index-tech.htm                                                     110<br />
http://www.eygle.com/archives/2006/10/wish_home.html                                    103<br />
http://www.eygle.com/index-ha.htm                                                        79<br />
http://www.eygle.com/me/fairy_tale_leaf.htm                                              77<br />
http://www.eygle.com/archives/2006/11/use_oracle_external_table.html                     73<br />
http://www.eygle.com/index-sql.htm                                                       69<br />
http://www.eygle.com/archives/2006/10/tom_oracle_9i10g.html                              68<br />
http://www.eygle.com/archives/2008/08/my_book_services.html                              63<br />
http://www.eygle.com/archives/2006/11/welcome_friend.html                                62<br />
http://www.eygle.com/archives/2006/10/veritas_vcs_simulator.html                         61<br />
http://www.eygle.com/index-case.htm                                                      60<br />
http://www.eygle.com/archives/2004/08/aoaouiiciona.html                                  59<br />
http://www.eygle.com/archives/2006/08/oracle_fundbook_recommand.html                     52<br />
http://www.eygle.com/archives/2006/08/5460_8174.html                                     49<br />
http://www.eygle.com/archives/2004/12/gmailaeaeoa.html                                   48<br />
http://www.eygle.com/archives/2005/06/howlsmovingcast.html                               48<br />
http://www.eygle.com/gbook/index.html                                                    48<br />
http://www.eygle.com/index-hist.htm                                                      44<br />
http://www.eygle.com/index-special.htm                                                   41<br />
http://www.eygle.com/index-f&l.htm                                                       37<br />
20 rows selected.</p>

<p>Elapsed: 00:00:06.31<br />
SQL></blockquote></p>

<p>通过外部表及SQL查询，只要日志文件中存在的信息，都可以很容易的被获取和分析.</p>

<p>-The End-<br />
</p>]]></description>
<link>http://www.eygle.com/archives/2006/10/use_external_talbe_analyze_eyglecom_log.html</link>
<guid>http://www.eygle.com/archives/2006/10/use_external_talbe_analyze_eyglecom_log.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Wed, 18 Oct 2006 11:56:39 +0800</pubDate>
</item>
<item>
<title>使用Oracle的外部表访问跟踪文件</title>
<description><![CDATA[<p>前面说过Oracle的外部表可以用来<a href="http://www.eygle.com/archives/2006/10/use_oracle_external_table.html">访问警告日志</a>文件，其实Oracle的外部表可以非常灵活的被使用。<br />
通过Create Directory命令创建相应的Directory之后，我们可以将目录的访问权限授予其他用户，这样其他用户就能通过外部表访问很多主机上的文件。<br />
关于<a href="http://www.eygle.com/archives/2005/04/using_create_di.html">Directory的使用</a>方法，可以参考:<br />
<a href="http://www.eygle.com/archives/2005/04/using_create_di.html">http://www.eygle.com/archives/2005/04/using_create_di.html</a></p>

<p>我们看一下使用外部表访问跟踪文件的例子(我的例子是用SYS用户来完成的)。</p>

<p>首先创建一个指向跟踪文件的Directory：<br />
<blockquote>[oracle@jumper oracle]$ sqlplus "/ as sysdba"</p>

<p>SQL*Plus: Release 9.2.0.4.0 - Production on Tue Oct 17 22:10:05 2006</p>

<p>Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.</p>

<p><br />
Connected to:<br />
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production<br />
With the Partitioning option<br />
JServer Release 9.2.0.4.0 - Production</p>

<p>SQL> show parameter user_dump</p>

<p>NAME                                 TYPE        VALUE<br />
------------------------------------ ----------- ------------------------------<br />
user_dump_dest                       string      /opt/oracle/admin/eygle/udump<br />
SQL> create or replace directory udump <br />
  2  as '/opt/oracle/admin/eygle/udump';</p>

<p>Directory created.</p>

<p>SQL> col DIRECTORY_PATH for a30<br />
SQL> select * from dba_directories;</p>

<p>OWNER      DIRECTORY_NAME                 DIRECTORY_PATH<br />
---------- ------------------------------ ------------------------------<br />
SYS        BDUMP                          /opt/oracle/admin/eygle/bdump<br />
SYS        UDUMP                          /opt/oracle/admin/eygle/udump</blockquote></p>

<p>如果我们的某些操作需要生成跟踪文件:</p>

<blockquote>SQL> alter session set sql_trace=true;

<p>Session altered.</p>

<p>SQL> select count(*) from dba_users;</p>

<p>  COUNT(*)<br />
----------<br />
         7</p>

<p>SQL> alter session set sql_trace=false;</p>

<p>Session altered.</blockquote></p>

<p>通过简单的脚本我们可以获得跟踪文件的名称:<br />
<blockquote>SQL> set echo on<br />
SQL> @gettrcname<br />
SQL> SELECT       d.VALUE<br />
  2         || '/'<br />
  3         || LOWER (RTRIM (i.INSTANCE, CHR (0)))<br />
  4         || '_ora_'<br />
  5         || p.spid<br />
  6         || '.trc' trace_file_name<br />
  7    FROM (SELECT p.spid<br />
  8            FROM SYS.v$mystat m, SYS.v$session s, SYS.v$process p<br />
  9           WHERE m.statistic# = 1 AND s.SID = m.SID AND p.addr = s.paddr) p,<br />
 10         (SELECT t.INSTANCE<br />
 11            FROM SYS.v$thread t, SYS.v$parameter v<br />
 12           WHERE v.NAME = 'thread'<br />
 13             AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i,<br />
 14         (SELECT VALUE<br />
 15            FROM SYS.v$parameter<br />
 16           WHERE NAME = 'user_dump_dest') d<br />
 17  /</p>

<p>TRACE_FILE_NAME<br />
------------------------------------------------------------------------------------------------------------------------<br />
/opt/oracle/admin/eygle/udump/eygle_ora_29731.trc</p>

<p>SQL> </blockquote></p>

<p>然后我们可以创建外部表用以访问这个跟踪文件:<br />
<blockquote>SQL> create table eygle_ora_29731 ( text varchar2(400) )<br />
  2  organization external (<br />
  3    type oracle_loader<br />
  4    default directory UDUMP<br />
  5    access parameters (<br />
  6      records delimited by newline<br />
  7      nobadfile<br />
  8      nodiscardfile<br />
  9      nologfile<br />
 10    )<br />
 11    location('eygle_ora_29731.trc')<br />
 12  )  reject limit unlimited<br />
 13  /</p>

<p>Table created.</blockquote></p>

<p>最后，我们可以很容易的使用外部表访问和查询这个跟踪文件的内容:<br />
<blockquote>SQL> set pagesize 100<br />
SQL> select * from eygle_ora_29731;</p>

<p>TEXT<br />
-----------------------------------------------------------------<br />
/opt/oracle/admin/eygle/udump/eygle_ora_29731.trc<br />
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production<br />
With the Partitioning option<br />
JServer Release 9.2.0.4.0 - Production<br />
ORACLE_HOME = /opt/oracle/product/9.2.0<br />
System name:    Linux<br />
Node name:      jumper.hurray.com.cn<br />
Release:        2.4.21-15.EL<br />
Version:        #1 Thu Apr 22 00:27:41 EDT 2004<br />
Machine:        i686<br />
Instance name: eygle<br />
Redo thread mounted by this instance: 1<br />
Oracle process number: 8<br />
Unix process pid: 29731<br />
*** 2006-10-17 22:15:50.310<br />
*** SESSION ID:(7.141) 2006-10-17 22:15:50.310<br />
APPNAME mod='sqlplus@jumper.hurray.com.cn (TNS V1-V3)' mh=0 act='' ah=0<br />
=====================<br />
PARSING IN CURSOR #1 len=32 dep=0 uid=0 oct=42 lid=0 tim=1133881396787772 hv=3943786303 ad='5ac609d4'<br />
alter session set sql_trace=true<br />
END OF STMT<br />
EXEC #1:c=0<br />
=====================<br />
PARSING IN CURSOR #3 len=37 dep=1 uid=0 oct=3 lid=0 tim=1133881402205250 hv=3468666020 ad='5adae2d8'<br />
select text from view$ where rowid=:1<br />
END OF STMT<br />
PARSE #3:c=0<br />
EXEC #3:c=0<br />
FETCH #3:c=0<br />
=====================<br />
PARSING IN CURSOR #4 len=116 dep=2 uid=0 oct=3 lid=0 tim=1133881402238727 hv=431456802 ad='5af20410'<br />
select o.owner#<br />
END OF STMT<br />
PARSE #4:c=10000<br />
EXEC #4:c=0<br />
FETCH #4:c=0<br />
STAT #3 id=1 cnt=1 pid=0 pos=1 obj=62 op='TABLE ACCESS BY USER ROWID VIEW$ (cr=1 r=0 w=0 time=79 us)'<br />
=====================<br />
PARSING IN CURSOR #1 len=30 dep=0 uid=0 oct=3 lid=0 tim=1133881402246452 hv=3198913505 ad='5adaa4ac'<br />
select count(*) from dba_users<br />
END OF STMT<br />
PARSE #1:c=10000<br />
EXEC #1:c=0<br />
FETCH #1:c=10000<br />
FETCH #1:c=0<br />
STAT #1 id=1 cnt=1 pid=0 pos=1 obj=0 op='SORT AGGREGATE (cr=48 r=0 w=0 time=5276 us)'<br />
STAT #1 id=2 cnt=7 pid=1 pos=1 obj=0 op='MERGE JOIN  (cr=48 r=0 w=0 time=5250 us)'<br />
STAT #1 id=3 cnt=7 pid=2 pos=1 obj=0 op='SORT JOIN (cr=45 r=0 w=0 time=5051 us)'<br />
=====================<br />
PARSING IN CURSOR #3 len=116 dep=1 uid=0 oct=3 lid=0 tim=1133881410335382 hv=431456802 ad='5af20410'<br />
select o.owner#<br />
END OF STMT<br />
PARSE #3:c=0<br />
EXEC #3:c=0<br />
FETCH #3:c=0<br />
STAT #1 id=4 cnt=7 pid=3 pos=1 obj=94 op='TABLE ACCESS BY INDEX ROWID PROFILE$ (cr=45 r=0 w=0 time=4881 us)'<br />
STAT #1 id=5 cnt=127 pid=4 pos=1 obj=0 op='NESTED LOOPS  (cr=44 r=0 w=0 time=3951 us)'<br />
STAT #1 id=6 cnt=7 pid=5 pos=1 obj=0 op='NESTED LOOPS  (cr=42 r=0 w=0 time=3235 us)'<br />
STAT #1 id=7 cnt=7 pid=6 pos=1 obj=0 op='NESTED LOOPS  (cr=26 r=0 w=0 time=3021 us)'<br />
STAT #1 id=8 cnt=7 pid=7 pos=1 obj=0 op='MERGE JOIN  (cr=10 r=0 w=0 time=2760 us)'<br />
STAT #1 id=9 cnt=9 pid=8 pos=1 obj=0 op='SORT JOIN (cr=6 r=0 w=0 time=2479 us)'<br />
STAT #1 id=10 cnt=9 pid=9 pos=1 obj=94 op='TABLE ACCESS BY INDEX ROWID PROFILE$ (cr=6 r=0 w=0 time=2284 us)'<br />
STAT #1 id=11 cnt=163 pid=10 pos=1 obj=0 op='NESTED LOOPS  (cr=5 r=0 w=0 time=1303 us)'<br />
EXEC #3:c=0<br />
FETCH #3:c=0<br />
STAT #1 id=12 cnt=9 pid=11 pos=1 obj=280 op='TABLE ACCESS FULL USER_ASTATUS_MAP (cr=3 r=0 w=0 time=244 us)'<br />
STAT #1 id=13 cnt=153 pid=11 pos=2 obj=139 op='INDEX RANGE SCAN I_PROFILE (cr=2 r=0 w=0 time=518 us)'<br />
STAT #1 id=14 cnt=7 pid=8 pos=2 obj=0 op='SORT JOIN (cr=4 r=0 w=0 time=200 us)'<br />
STAT #1 id=15 cnt=7 pid=14 pos=1 obj=22 op='TABLE ACCESS FULL USER$ (cr=4 r=0 w=0 time=117 us)'<br />
STAT #1 id=16 cnt=7 pid=7 pos=2 obj=16 op='TABLE ACCESS CLUSTER TS$ (cr=16 r=0 w=0 time=199 us)'<br />
STAT #1 id=17 cnt=7 pid=16 pos=1 obj=7 op='INDEX UNIQUE SCAN I_TS# (cr=2 r=0 w=0 time=69 us)'<br />
STAT #1 id=18 cnt=7 pid=6 pos=2 obj=16 op='TABLE ACCESS CLUSTER TS$ (cr=16 r=0 w=0 time=166 us)'<br />
STAT #1 id=19 cnt=7 pid=18 pos=1 obj=7 op='INDEX UNIQUE SCAN I_TS# (cr=2 r=0 w=0 time=37 us)'<br />
STAT #1 id=20 cnt=119 pid=5 pos=2 obj=139 op='INDEX RANGE SCAN I_PROFILE (cr=2 r=0 w=0 time=342 us)'<br />
STAT #1 id=21 cnt=7 pid=2 pos=2 obj=0 op='SORT JOIN (cr=3 r=0 w=0 time=121 us)'<br />
EXEC #3:c=0<br />
FETCH #3:c=0<br />
STAT #1 id=22 cnt=1 pid=21 pos=1 obj=95 op='TABLE ACCESS FULL PROFNAME$ (cr=3 r=0 w=0 time=66 us)'<br />
=====================<br />
PARSING IN CURSOR #1 len=33 dep=0 uid=0 oct=42 lid=0 tim=1133881410339660 hv=4238949625 ad='5ac49f60'<br />
alter session set sql_trace=false<br />
END OF STMT<br />
PARSE #1:c=0<br />
EXEC #1:c=0</p>

<p>84 rows selected.</p>

<p>SQL> </blockquote></p>

<p>外部表极大的简化了我们的很多管理工作。</p>

<p>-The End-<br />
</p>]]></description>
<link>http://www.eygle.com/archives/2006/10/external_table_and_trace_file.html</link>
<guid>http://www.eygle.com/archives/2006/10/external_table_and_trace_file.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Tue, 17 Oct 2006 22:42:10 +0800</pubDate>
</item>
<item>
<title>使用Oracle的外部表查询警告日志文件</title>
<description><![CDATA[<p>从Oracle9i开始，Oracle的外部表技术（Oracle External Tables）被极大的增强，通过外部表访问外部数据增强了Oracle数据库和外部数据源进行数据交互的能力，对于数据仓库和ETL来说，这些增强极大的方便了数据访问。</p>

<p>对于DBA来说，最常见一个例子是可以使用外部表来访问警告日志文件或其他跟踪文件.<br />
以下一个例子用来说明外部表的用途。</p>

<p>首先需要创建一个Directory：<br />
<blockquote>[oracle@jumper oracle]$ sqlplus "/ as sysdba"</p>

<p>SQL*Plus: Release 9.2.0.4.0 - Production on Sun Oct 15 21:42:28 2006</p>

<p>Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.</p>

<p><br />
Connected to:<br />
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production<br />
With the Partitioning option<br />
JServer Release 9.2.0.4.0 - Production</p>

<p>SQL> create or replace directory bdump <br />
  2  as '/opt/oracle/admin/eygle/bdump';</p>

<p>Directory created.</p>

<p>SQL> col DIRECTORY_PATH for a30<br />
SQL> col owner for a10<br />
SQL> select * from dba_directories;</p>

<p>OWNER      DIRECTORY_NAME                 DIRECTORY_PATH<br />
---------- ------------------------------ ------------------------------<br />
SYS        BDUMP                          /opt/oracle/admin/eygle/bdump</blockquote></p>

<p>然后创建一个外部表:<br />
<blockquote>SQL> create table alert_log ( text varchar2(400) )<br />
  2  organization external (<br />
  3    type oracle_loader<br />
  4    default directory BDUMP<br />
  5    access parameters (<br />
  6      records delimited by newline<br />
  7      nobadfile<br />
  8      nodiscardfile<br />
  9      nologfile<br />
 10     )<br />
 11     location('alert_eygle.log')<br />
 12  )<br />
 13  reject limit unlimited<br />
 14  /</p>

<p>Table created.</blockquote><br />
然后我们就可以通过外部表进行查询警告日志的内容:<br />
<blockquote>SQL> select * from alert_log where rownum < 51;</p>

<p>TEXT<br />
-----------------------------------------------------------------------------------------<br />
Mon Jun 26 12:00:24 2006<br />
Starting ORACLE instance (normal)<br />
Mon Jun 26 12:00:25 2006<br />
WARNING: EINVAL creating segment of size 0x0000000008c00000<br />
fix shm parameters in /etc/system or equivalent<br />
LICENSE_MAX_SESSION = 0<br />
LICENSE_SESSIONS_WARNING = 0<br />
SCN scheme 2<br />
Using log_archive_dest parameter default value<br />
LICENSE_MAX_USERS = 0<br />
SYS auditing is disabled<br />
Starting up ORACLE RDBMS Version: 9.2.0.4.0.<br />
System parameters with non-default values:<br />
  processes                = 150<br />
  timed_statistics         = TRUE<br />
  shared_pool_size         = 104857600<br />
  large_pool_size          = 0<br />
  java_pool_size           = 0<br />
  control_files            = /opt/oracle/oradata/eygle/control01.ctl<br />
  db_block_size            = 8192<br />
  db_cache_size            = 16777216<br />
  db_cache_advice          = ON<br />
  compatible               = 9.2.0.0.0<br />
  db_file_multiblock_read_count= 16<br />
  fast_start_mttr_target   = 300<br />
  log_checkpoints_to_alert = TRUE<br />
  undo_management          = AUTO<br />
  undo_tablespace          = UNDOTBS1<br />
  undo_retention           = 10800<br />
  remote_login_passwordfile= EXCLUSIVE<br />
  db_domain                =<br />
  instance_name            = eygle<br />
  job_queue_processes      = 10<br />
  hash_join_enabled        = TRUE<br />
  background_dump_dest     = /opt/oracle/admin/eygle/bdump<br />
  user_dump_dest           = /opt/oracle/admin/eygle/udump<br />
  core_dump_dest           = /opt/oracle/admin/eygle/cdump<br />
  sort_area_size           = 524288<br />
  db_name                  = eygle<br />
  open_cursors             = 500<br />
  star_transformation_enabled= FALSE<br />
  query_rewrite_enabled    = FALSE<br />
  pga_aggregate_target     = 52428800<br />
  aq_tm_processes          = 0<br />
PMON started with pid=2<br />
DBW0 started with pid=3<br />
LGWR started with pid=4<br />
CKPT started with pid=5<br />
SMON started with pid=6<br />
RECO started with pid=7</p>

<p>50 rows selected.</p>

<p>SQL> </blockquote></p>]]></description>
<link>http://www.eygle.com/archives/2006/10/use_oracle_external_table.html</link>
<guid>http://www.eygle.com/archives/2006/10/use_oracle_external_table.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Sun, 15 Oct 2006 23:14:10 +0800</pubDate>
</item>
<item>
<title>使用分析函数进行行列转换</title>
<description><![CDATA[经常有朋友问到行列转换的问题，留言板上也有这样的<a href="http://www.eygle.com/gbook/reply.php?gbid=2746">提问</a>。<br><br>

其实使用分析函数进行处理是很好的方式，翻一下Tom的书，将其中的一个例子收录在这里.
比如查询scott.emp表的用户SAL排序信息，可以使用如下查询：<br>
<blockquote><pre>SQL> SELECT deptno, ename,
  2         ROW_NUMBER () OVER (PARTITION BY deptno ORDER BY sal DESC) seq
  3    FROM emp;

    DEPTNO ENAME             SEQ
---------- ---------- ----------
        10 KING                1
        10 CLARK               2
        10 MILLER              3
        20 SCOTT               1
        20 FORD                2
        20 JONES               3
        20 ADAMS               4
        20 SMITH               5
        30 BLAKE               1
        30 ALLEN               2
        30 TURNER              3
        30 WARD                4
        30 MARTIN              5
        30 JAMES               6

14 rows selected.</pre></blockquote><br><br>

再结合其他函数进行一下行列转换:<br>
<blockquote><pre>SQL> select deptno,
  2  max(decode(seq,1,ename,null)) highest,
  3  max(decode(seq,2,ename,null)) second,
  4  max(decode(seq,3,ename,null)) third
  5  from (
  6  select deptno,ename,
  7  row_number() over
  8  (partition by deptno order by sal desc) seq
  9  from emp)
 10  where seq <=3 group by deptno
 11  /

    DEPTNO HIGHEST    SECOND     THIRD
---------- ---------- ---------- ----------
        10 KING       CLARK      MILLER
        20 SCOTT      FORD       JONES
        30 BLAKE      ALLEN      TURNER</pre></blockquote>

这个结果基本上还是差强人意的。<br><br>

-The End-
<br>]]></description>
<link>http://www.eygle.com/archives/2006/09/use_any_function.html</link>
<guid>http://www.eygle.com/archives/2006/09/use_any_function.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Tue, 26 Sep 2006 16:50:58 +0800</pubDate>
</item>
<item>
<title>学习-SQL查询连续号码段的巧妙解法</title>
<description><![CDATA[<p>在ITPUB上有一则非常巧妙的<a href="http://www.itpub.net/showthread.php?threadid=354052">SQL技巧</a>，学习一下，记录在这里。</p>

<p>最初的问题是这样的:<br />
<blockquote><br />
我有一个表结构，<br />
fphm,kshm<br />
2014,00000001<br />
2014,00000002<br />
2014,00000003<br />
2014,00000004<br />
2014,00000005<br />
2014,00000007<br />
2014,00000008<br />
2014,00000009<br />
2013,00000120<br />
2013,00000121<br />
2013,00000122<br />
2013,00000124<br />
2013,00000125</p>

<p>(第二个字段内可能是连续的数据，可能存在断点。)</p>

<p>怎样能查询出来这样的结果,查询出连续的记录来。<br />
就像下面的这样？<br />
2014,00000001,00000005<br />
2014,00000009,00000007<br />
2013,00000120,00000122<br />
2013,00000124,00000125</blockquote></p>

<p>ITPUB上的朋友给出了一个非常巧妙的答案:<br />
<blockquote></p>

<p>SQL> SELECT   b.fphm, MIN (b.kshm) Start_HM, MAX (b.kshm) End_HM<br />
  2      FROM (SELECT a.*, TO_NUMBER (a.kshm - ROWNUM) cc<br />
  3              FROM (SELECT   *<br />
  4                        FROM t<br />
  5                    ORDER BY fphm, kshm) a) b<br />
  6  GROUP BY b.fphm, b.cc<br />
  7  /</p>

<p>      FPHM START_HM END_HM<br />
---------- -------- --------<br />
      2013 00000120 00000122<br />
      2013 00000124 00000125<br />
      2014 00000001 00000005<br />
      2014 00000007 00000009<br />
</blockquote></p>

<p>巧思妙想，就在一念之间。<br />
ITPUB其他参考链接如下:<br />
<a href="http://blog.itpub.net/post/5042/27936">http://blog.itpub.net/post/5042/27936</a></p>

<p>-The End-<br />
</p>]]></description>
<link>http://www.eygle.com/archives/2006/09/sql_tips.html</link>
<guid>http://www.eygle.com/archives/2006/09/sql_tips.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Tue, 26 Sep 2006 15:04:32 +0800</pubDate>
</item>
<item>
<title>Oracle9i基于视图(view)的约束声名</title>
<description><![CDATA[<p>从Oracle9i开始，Oracle允许对于视图(view)进行主键、唯一键、外键约束的声名。NOT NULL约束可以从基表继承，所以不允许显示声明。<br />由于视图约束仅仅是声明而已，所以其状态只能是DISABLE NOVALIDATE。</p>
<p>以下是一个简单范例说明:<br /></p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; CREATE VIEW d10_emp<br />&nbsp; 2&nbsp; ( empno, ename, job,deptno,<br />&nbsp; 3&nbsp; <strong><em>CONSTRAINT</em></strong> pk_d10<br />&nbsp; 4&nbsp; <strong>PRIMARY KEY (ename)</strong><br />&nbsp; 5&nbsp; <strong>RELY DISABLE NOVALIDATE</strong><br />&nbsp; 6&nbsp; ) AS<br />&nbsp; 7&nbsp; SELECT empno, ename, job ,deptno<br />&nbsp; 8&nbsp; FROM emp<br />&nbsp; 9&nbsp; WHERE deptno = 10;&nbsp; </pre>
            <pre>View created.</pre>
            <pre>SQL&gt; select * from d10_emp;</pre>
            <pre>&nbsp;&nbsp;&nbsp;&nbsp; EMPNO ENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JOB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEPTNO<br />---------- ---------- --------- ----------<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7782 CLARK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MANAGER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7839 KING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PRESIDENT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7934 MILLER&nbsp;&nbsp;&nbsp;&nbsp; CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10</pre>
            <pre>SQL&gt; select CONSTRAINT_NAME,TABLE_NAME,CONSTRAINT_TYPE from user_constraints<br />&nbsp; 2&nbsp; where table_name='D10_EMP';</pre>
            <pre>CONSTRAINT_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C<br />------------------------------ ------------------------------ -<br />PK_D10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D10_EMP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; P&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>由于此约束仅仅为&quot;约束声明&quot;,所以不具有实际约束力:</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; insert into d10_emp values(7777,'EYGLE','MANAGER',10);</pre>
            <pre>1 row created.</pre>
            <pre>SQL&gt; insert into d10_emp values(8888,'EYGLE','MANAGER',10);</pre>
            <pre>1 row created.</pre>
            <pre>SQL&gt; select * from d10_emp;</pre>
            <pre>&nbsp;&nbsp;&nbsp;&nbsp; EMPNO ENAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JOB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEPTNO<br />---------- ---------- --------- ----------<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7782 CLARK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MANAGER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7839 KING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PRESIDENT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7934 MILLER&nbsp;&nbsp;&nbsp;&nbsp; CLERK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7777 EYGLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MANAGER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8888 EYGLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MANAGER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>]]></description>
<link>http://www.eygle.com/archives/2006/02/oracle9i_view_constraints_declarative.html</link>
<guid>http://www.eygle.com/archives/2006/02/oracle9i_view_constraints_declarative.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Mon, 27 Feb 2006 17:27:45 +0800</pubDate>
</item>
<item>
<title>基于主键和唯一约束的显示索引控制</title>
<description><![CDATA[<p>从Oracle9i开始，主键创建时的索引和唯一性约束可以在建表时独立定义。<br />随后，约束可以被独立drop，而索引可以保留。这是Oracle9i中对于索引增强的几个特性之一。</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; CREATE TABLE employees<br />&nbsp; 2&nbsp; (<br />&nbsp; 3&nbsp;&nbsp;&nbsp; empno NUMBER(6),<br />&nbsp; 4&nbsp;&nbsp;&nbsp; NAME VARCHAR2(30),<br />&nbsp; 5&nbsp;&nbsp;&nbsp; dept_no NUMBER(2),<br />&nbsp; 6&nbsp;&nbsp;&nbsp; CONSTRAINT emp_pk PRIMARY KEY(empno)<br />&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; USING INDEX<br />&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (CREATE UNIQUE INDEX emp_pk_idx ON employees(empno))<br />&nbsp; 9&nbsp; );</pre>
            <pre>Table created.</pre>
            <pre>SQL&gt; select index_name,UNIQUENESS from user_indexes<br />&nbsp; 2&nbsp; where table_name=upper('employees');</pre>
            <pre>INDEX_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNIQUENES<br />------------------------------ ---------<br />EMP_PK_IDX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNIQUE</pre>
            <pre>SQL&gt; select CONSTRAINT_NAME,CONSTRAINT_TYPE,INDEX_NAME from user_constraints<br />&nbsp; 2&nbsp; where table_name=upper('employees');</pre>
            <pre>CONSTRAINT_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C INDEX_NAME<br />------------------------------ - ------------------------------<br />EMP_PK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; P EMP_PK_IDX&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>Oracle9i中新增的命令可以用以DROP约束保留索引.</p>
<blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
<p><strong><em>ALTER TABLE employees DROP PRIMARY KEY KEEP INDEX;</em></strong></p>
</blockquote>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; ALTER TABLE employees DROP PRIMARY KEY KEEP INDEX;</pre>
            <pre>Table altered.</pre>
            <pre>SQL&gt; select index_name,UNIQUENESS from user_indexes<br />&nbsp; 2&nbsp; where table_name=upper('employees');</pre>
            <pre>INDEX_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNIQUENES<br />------------------------------ ---------<br />EMP_PK_IDX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNIQUE&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>]]></description>
<link>http://www.eygle.com/archives/2006/02/oracle9i_enhancement_keep_index.html</link>
<guid>http://www.eygle.com/archives/2006/02/oracle9i_enhancement_keep_index.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Mon, 27 Feb 2006 12:18:17 +0800</pubDate>
</item>
<item>
<title>Oracle HowTo:如何使用Leading提示改变表连接方式</title>
<description><![CDATA[<p>在多表联合查询中,当<a href="http://www.eygle.com/archives/2006/02/oracle_ordered_hints_usage.html">使用Ordered提示改变SQL执行计划</a>之后,通常我们很难再次控制结果集中进一步Join的顺序.</p>
<p>这时候我们可以使用Oracle提供的另外一个Hints: Leading 提示.</p>
<p>这个Hints在Oracle9i中的含义为:</p>
<blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
<p class="BP">The <code><font face="新宋体">LEADING</font></code> hint causes Oracle to use the specified table as the first table in the join order.</p>
<p class="BP">If you specify two or more <code><font face="新宋体">LEADING</font></code> hints on different tables, then all of them are ignored. If you specify the <code><font face="新宋体">ORDERED</font></code> hint, then it overrides all <code><font face="新宋体">LEADING</font></code> hints.</p>
</blockquote>
<p class="BP" dir="ltr">通过Leading 和 use_hash 提示连用,我们可以巧妙的影响SQL中表和结果集的Join顺序.</p>
<p class="BP" dir="ltr">我们通过如下示例看一下这个提示是如何影响SQL执行的:</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; SELECT /*+ leading(t_max) use_hash(t_max t_middle) */ COUNT (*)<br />&nbsp; 2&nbsp;&nbsp;&nbsp; FROM t_small, t_max, t_middle<br />&nbsp; 3&nbsp; WHERE t_small.object_id = t_middle.object_id<br />&nbsp; 4&nbsp; AND t_middle.object_id = t_max.object_id<br />&nbsp; 5&nbsp; /</pre>
            <pre>Execution Plan<br />----------------------------------------------------------<br />&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE (Cost=262 Card=1 Bytes=12)<br />&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; SORT (AGGREGATE)<br />&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; HASH JOIN (Cost=262 Card=400 Bytes=4800)<br />&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HASH JOIN (Cost=225 Card=113776 Bytes=910208)<br />&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'T_MAX' (Cost=151 Card=113792 Bytes=455168)<br />&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'T_MIDDLE' (Cost=39 Card=28447 Bytes=113788)<br />&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'T_SMALL' (Cost=2 Card=100 Bytes=400)&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>我们看到,通过这两个Hints的联合使用,该查询首先对T_MAX和T_MIDDLE表进行HASH JOIN,再以这个结果集同T_SMALL进行HASH JION.</p>]]></description>
<link>http://www.eygle.com/archives/2006/02/use_leading_hints_change_sql_explain.html</link>
<guid>http://www.eygle.com/archives/2006/02/use_leading_hints_change_sql_explain.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Sun, 26 Feb 2006 12:21:45 +0800</pubDate>
</item>
<item>
<title>如何使用ordered提示改变SQL执行计划</title>
<description><![CDATA[<p>ORDERED提示强制Oracle按照From子句中表出现的顺序进行表连接。</p>
<p>通过ordered提示，可以避免CBO SQL解析过程中的表连接评估，从而避免Oracle产生错误的执行计划，或者强制Oracle按照我们指定的方式执行。</p>
<p>在很多时候，当我们清楚地了解数据结构和数据分布之后，就可以通过ORDERED提示来提高SQL性能。</p>
<p>通过以下例子我们来说明一下Ordered提示的作用.</p>
<p>1.不加Hints时SQL的执行计划</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; set autotrace trace explain<br />SQL&gt;&nbsp; SELECT COUNT (*)<br />&nbsp; 2&nbsp;&nbsp;&nbsp; FROM t_small, t_max, t_middle<br />&nbsp; 3&nbsp;&nbsp; WHERE t_small.object_id = t_middle.object_id<br />&nbsp; 4&nbsp;&nbsp; AND t_middle.object_id = t_max.object_id;</pre>
            <pre>Execution Plan<br />----------------------------------------------------------<br />&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE (Cost=194 Card=1 Bytes=12)<br />&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; SORT (AGGREGATE)<br />&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; HASH JOIN (Cost=194 Card=400 Bytes=4800)<br />&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HASH JOIN (Cost=42 Card=100 Bytes=800)<br />&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'T_SMALL' (Cost=2 Card=100 Bytes=400)<br />&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'T_MIDDLE' (Cost=39 Card=28447 Bytes=113788)<br />&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (FULL) OF 'T_MAX' (Cost=151 Card=113792 Bytes=455168)<br />&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>我们可以通过10053事件跟踪一下该SQL的解析:</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; alter session set events='10053 trace name context forever,level 1';</pre>
            <pre>Session altered.</pre>
            <pre>SQL&gt; explain plan for<br />&nbsp; 2&nbsp; SELECT COUNT (*)<br />&nbsp; 3&nbsp;&nbsp;&nbsp; FROM t_small, t_max, t_middle<br />&nbsp; 4&nbsp; WHERE t_small.object_id = t_middle.object_id<br />&nbsp; 5&nbsp; AND t_middle.object_id = t_max.object_id;&nbsp;&nbsp;&nbsp; </pre>
            <pre>Explained.&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>查看Trace文件可以看到,Oracle需要进行3! (6)次表连接顺序的评估:</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>bash-2.03$ cat testora9_ora_10862.trc |grep &quot;Join order&quot;<br />Join order[1]: T_SMALL [T_SMALL] T_MIDDLE [T_MIDDLE] T_MAX [T_MAX] <br />Join order[2]: T_SMALL [T_SMALL] T_MAX [T_MAX] T_MIDDLE [T_MIDDLE] <br />Join order[3]: T_MIDDLE [T_MIDDLE] T_SMALL [T_SMALL] T_MAX [T_MAX] <br />Join order[4]: T_MIDDLE [T_MIDDLE] T_MAX [T_MAX] T_SMALL [T_SMALL] <br />Join order[5]: T_MAX [T_MAX] T_SMALL [T_SMALL] T_MIDDLE [T_MIDDLE] <br />Join order[6]: T_MAX [T_MAX] T_MIDDLE [T_MIDDLE] T_SMALL [T_SMALL] &nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>]]></description>
<link>http://www.eygle.com/archives/2006/02/oracle_ordered_hints_usage.html</link>
<guid>http://www.eygle.com/archives/2006/02/oracle_ordered_hints_usage.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Sat, 25 Feb 2006 12:28:07 +0800</pubDate>
</item>
<item>
<title>索引与Null值对于Hints及执行计划的影响</title>
<description><![CDATA[<p>由于B*Tree索引不存储Null值,所以在索引字段允许为空的情况下,某些Oracle查询不会使用索引.</p>
<p>很多时候,我们看似可以使用全索引扫描(Full Index Scan)的情况,可能Oracle就会因为Null值的存在而放弃索引.</p>
<p>在此情况下即使使用Hints,Oracle也不会使用索引,其根本原因就是因为Null值的存在.</p>
<p>我们看以下测试.</p>
<p>在<strong>username</strong>字段为Not Null时,Index Hints可以生效.</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; create table t as select username,password from dba_users;</pre>
            <pre>Table created.</pre>
            <pre>SQL&gt; desc t<br />&nbsp;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; Null?&nbsp;&nbsp;&nbsp; Type<br />&nbsp;----------------------------------------- -------- ----------------------------<br />&nbsp;USERNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NOT NULL VARCHAR2(30)<br />&nbsp;PASSWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARCHAR2(30)</pre>
            <pre>SQL&gt; create index i_t on t(username);</pre>
            <pre>Index created.</pre>
            <pre>SQL&gt; set autotrace trace explain<br />SQL&gt; select * from t where username='EYGLE';</pre>
            <pre>Execution Plan<br />----------------------------------------------------------<br />Plan hash value: 1601196873</pre>
            <pre>--------------------------------------------------------------------------<br />| Id&nbsp; | Operation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Name | Rows&nbsp; | Bytes | Cost (%CPU)| Time&nbsp;&nbsp;&nbsp;&nbsp; |<br />--------------------------------------------------------------------------<br />|&nbsp;&nbsp; 0 | SELECT STATEMENT&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1 |&nbsp;&nbsp;&nbsp; 34 |&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp; (0)| 00:00:01 |<br />|*&nbsp; 1 |&nbsp; TABLE ACCESS FULL| T&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1 |&nbsp;&nbsp;&nbsp; 34 |&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp; (0)| 00:00:01 |<br />--------------------------------------------------------------------------</pre>
            <pre>Predicate Information (identified by operation id):<br />---------------------------------------------------</pre>
            <pre>&nbsp;&nbsp; 1 - filter(&quot;USERNAME&quot;='EYGLE')</pre>
            <pre>Note<br />-----<br />&nbsp;&nbsp; - dynamic sampling used for this statement</pre>
            <pre>SQL&gt; set linesize 120<br />SQL&gt; select /*+ index(t,i_t) */ * from t where username='EYGLE';</pre>
            <pre>Execution Plan<br />----------------------------------------------------------<br />Plan hash value: 2928007915</pre>
            <pre>------------------------------------------------------------------------------------<br />| Id&nbsp; | Operation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Name | Rows&nbsp; | Bytes | Cost (%CPU)| Time&nbsp;&nbsp;&nbsp;&nbsp; |<br />------------------------------------------------------------------------------------<br />|&nbsp;&nbsp; 0 | SELECT STATEMENT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1 |&nbsp;&nbsp;&nbsp; 34 |&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp; (0)| 00:00:01 |<br />|&nbsp;&nbsp; 1 |&nbsp; TABLE ACCESS BY INDEX ROWID| T&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1 |&nbsp;&nbsp;&nbsp; 34 |&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp; (0)| 00:00:01 |<br />|*&nbsp; 2 |&nbsp;&nbsp; INDEX RANGE SCAN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | I_T&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; (0)| 00:00:01 |<br />------------------------------------------------------------------------------------</pre>
            <pre>Predicate Information (identified by operation id):<br />---------------------------------------------------</pre>
            <pre>&nbsp;&nbsp; 2 - access(&quot;USERNAME&quot;='EYGLE')</pre>
            <pre>Note<br />-----<br />&nbsp;&nbsp; - dynamic sampling used for this statement</pre>
            </td>
        </tr>
    </tbody>
</table>]]></description>
<link>http://www.eygle.com/archives/2006/02/index_null_hints_explain.html</link>
<guid>http://www.eygle.com/archives/2006/02/index_null_hints_explain.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Wed, 22 Feb 2006 17:19:55 +0800</pubDate>
</item>
<item>
<title>使用Index提示 强制使用索引</title>
<description><![CDATA[<p>虽然索引并不总会快于全表扫描,但是很多时候我们希望Oracle使用索引来执行某些SQL,这时候我们可以通过index hints来强制SQL使用index.</p>
<p>Index Hints的格式如下:</p>
<blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
<pre><font face="verdana,helvetica,arial" size="2"><font face="arial, helvetica" size="3"><font face="arial, helvetica" size="3">/*+ <strong>INDEX</strong> ( table [index [index]...] ) */</font></font></font></pre>
</blockquote>
<p>我们简单看一下这个提示的用法(范例为<strong><em>Oracle10g</em></strong>数据库):</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; create table t as select username,password from dba_users;</pre>
            <pre>Table created.</pre>
            <pre>SQL&gt; create index i_t on t(username);</pre>
            <pre>Index created.</pre>
            <pre>SQL&gt; set autotrace trace explain</pre>
            <pre>SQL&gt; select /*+ index(t i_t) */ * from t where username='EYGLE';</pre>
            <pre>Execution Plan<br />----------------------------------------------------------<br />Plan hash value: 2928007915</pre>
            <pre>------------------------------------------------------------------------------------<br />| Id&nbsp; | Operation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Name | Rows&nbsp; | Bytes | Cost (%CPU)| Time&nbsp;&nbsp;&nbsp;&nbsp; |<br />------------------------------------------------------------------------------------<br />|&nbsp;&nbsp; 0 | SELECT STATEMENT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1 |&nbsp;&nbsp;&nbsp; 34 |&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp; (0)| 00:00:01 |<br />|&nbsp;&nbsp; 1 |&nbsp; TABLE ACCESS BY INDEX ROWID| T&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1 |&nbsp;&nbsp;&nbsp; 34 |&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp; (0)| 00:00:01 |<br />|*&nbsp; 2 |&nbsp;&nbsp; INDEX RANGE SCAN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | I_T&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp; (0)| 00:00:01 |<br />------------------------------------------------------------------------------------</pre>
            <pre>Predicate Information (identified by operation id):<br />---------------------------------------------------</pre>
            <pre>&nbsp;&nbsp; 2 - access(&quot;USERNAME&quot;='EYGLE')</pre>
            <pre>Note<br />-----<br />&nbsp;&nbsp; - dynamic sampling used for this statement&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>这里的查询使用了索引.</p>
<p>需要注意的是使用CTAS方式创建数据表,新建表会继承原表的约束属性:</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; desc t<br />&nbsp;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; Null?&nbsp;&nbsp;&nbsp; Type<br />&nbsp;----------------------------------------- -------- ----------------------------<br />&nbsp;USERNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NOT NULL VARCHAR2(30)<br />&nbsp;PASSWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARCHAR2(30)&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>]]></description>
<link>http://www.eygle.com/archives/2006/02/index_hints_usage.html</link>
<guid>http://www.eygle.com/archives/2006/02/index_hints_usage.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Tue, 21 Feb 2006 22:44:17 +0800</pubDate>
</item>
<item>
<title>基于自定义函数的Function-Based索引创建</title>
<description><![CDATA[<p>留言版上的第<a href="http://www.eygle.com/gbook/reply.php?gbid=2330">2330号</a>问题是:</p>
<blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
<p><strong>在oralce中给自建函数创建索引，结果不成功。</strong></p>
<p><strong>source:Create Index IDX_T_SP_TWOTYPESTAT_0_f On T_SP_TWOTYPESTAT_0(f_dateadd(yearmonth,12,2)); <br />err:the function is not deterministic.</strong> </p>
</blockquote>
<p dir="ltr">我们看一下这是为什么?</p>
<p dir="ltr">随便一个测试可以再现这个问题,我门创建一个函数(本范例函数用于进行16进制向10进制转换):</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>CREATE OR REPLACE FUNCTION h2ten (<br />&nbsp;&nbsp; p_str&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IN&nbsp;&nbsp; VARCHAR2,<br />&nbsp;&nbsp; p_from_base&nbsp;&nbsp; IN&nbsp;&nbsp; NUMBER DEFAULT 16<br />)<br />&nbsp;&nbsp; RETURN NUMBER <br />IS<br />&nbsp;&nbsp; l_num&nbsp;&nbsp; NUMBER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEFAULT 0;<br />&nbsp;&nbsp; l_hex&nbsp;&nbsp; VARCHAR2 (16) DEFAULT '0123456789ABCDEF';<br />BEGIN<br />&nbsp;&nbsp; FOR i IN 1 .. LENGTH (p_str)<br />&nbsp;&nbsp; LOOP<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l_num :=<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l_num * p_from_base + INSTR (l_hex, UPPER (SUBSTR (p_str, i, 1)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 1;<br />&nbsp;&nbsp; END LOOP;</pre>
            <pre>&nbsp;&nbsp; RETURN l_num;<br />END h2ten;<br />&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>
<p>此时创建索引,获得如下错误信息:</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; create table t as select username,'a' hex from dba_users;</pre>
            <pre>Table created</pre>
            <pre>SQL&gt; create index i_t on t (h2ten(hex));</pre>
            <pre>create index i_t on t (h2ten(hex))</pre>
            <pre>ORA-30553: The function is not deterministic<br />&nbsp;</pre>
            </td>
        </tr>
    </tbody>
</table>]]></description>
<link>http://www.eygle.com/archives/2006/01/create_function_based_index.html</link>
<guid>http://www.eygle.com/archives/2006/01/create_function_based_index.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Mon, 23 Jan 2006 10:59:11 +0800</pubDate>
</item>
<item>
<title>Definer and Invoker Rights</title>
<description><![CDATA[<p>本文用以回答<a href="http://www.eygle.com/gbook/index.html">留言板</a>上的<a href="http://www.eygle.com/gbook/reply.php?gbid=2111">2111</a>号问题.</p>
<p>在Oracle8i以前，所有已编译存储对象(包括packages, procedures, functions, triggers, and views)只能以定义者(Definer)身份解析运行；从Oracle8i开始，Oracle引入调用者(invoker)权限，使得对象可以以调用者身份和权限执行。</p>
<p>定义者(Definer)指编译存储对象的所有者.<br />调用者(Invoker)指拥有当前会话权限的模式，这可能和当前登录用户相同或不同(alter session set current_schema 可以改变调用者Schema).</p>
<p>TOM在他的《Expert One on One》的第23章曾经详细介绍这一特性，本文引用Tom的一个例子用于说明Definer and Invoker权限。</p>
<p>1.以Eygle用户(definer)创建2个过程</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>&nbsp;$ sqlplus eygle/eygle</pre>
            <pre>SQL*Plus: Release 9.2.0.4.0 - Production on Sun Dec 11 11:39:27 2005</pre>
            <pre>Copyright (c) 1982, 2002, Oracle Corporation.&nbsp; All rights reserved.</pre>
            <pre><br />Connected to:<br />Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production<br />With the Partitioning option<br />JServer Release 9.2.0.4.0 - Production</pre>
            <pre>SQL&gt; create or replace procedure definer_proc<br />&nbsp; 2&nbsp; as<br />&nbsp; 3&nbsp; begin<br />&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for x in<br />&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( select sys_context( 'userenv', 'current_user' ) current_user,<br />&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sys_context( 'userenv', 'session_user' ) session_user,<br />&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sys_context( 'userenv', 'current_schema' ) current_schema<br />&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from dual )<br />&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loop<br />&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbms_output.put_line( 'Current User:&nbsp;&nbsp; ' || x.current_user );<br />&nbsp;11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbms_output.put_line( 'Session User:&nbsp;&nbsp; ' || x.session_user );<br />&nbsp;12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbms_output.put_line( 'Current Schema: ' || x.current_schema );<br />&nbsp;13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end loop;<br />&nbsp;14&nbsp; end;<br />&nbsp;15&nbsp; /</pre>
            <pre>Procedure created.</pre>
            <pre>SQL&gt; <br />SQL&gt; grant execute on definer_proc to test;</pre>
            <pre>Grant succeeded.</pre>
            <pre>SQL&gt; <br />SQL&gt; create or replace procedure invoker_proc<br />&nbsp; 2&nbsp; <strong>AUTHID CURRENT_USER</strong><br />&nbsp; 3&nbsp; as<br />&nbsp; 4&nbsp; begin<br />&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for x in<br />&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( select sys_context( 'userenv', 'current_user' ) current_user,<br />&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sys_context( 'userenv', 'session_user' ) session_user,<br />&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sys_context( 'userenv', 'current_schema' ) current_schema<br />&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from dual )<br />&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loop<br />&nbsp;11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbms_output.put_line( 'Current User:&nbsp;&nbsp; ' || x.current_user );<br />&nbsp;12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbms_output.put_line( 'Session User:&nbsp;&nbsp; ' || x.session_user );<br />&nbsp;13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbms_output.put_line( 'Current Schema: ' || x.current_schema );<br />&nbsp;14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end loop;<br />&nbsp;15&nbsp; end;<br />&nbsp;16&nbsp; /</pre>
            <pre>Procedure created.</pre>
            <pre>SQL&gt; <br />SQL&gt; grant execute on invoker_proc to test;</pre>
            <pre>Grant succeeded.<br /></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>注意invoker权限的本质是引入了AUTHID CURRENT_USER子句，通过此句Oracle得以使用invoker身份编译执行对象。</p>
<p>2.以test用户(invoker)身份执行</p>
<table>
    <tbody>
        <tr>
            <td width="500" bgcolor="#999999">
            <pre>SQL&gt; connect test/test<br />Connected.<br />SQL&gt; <br />SQL&gt; set serveroutput on<br />SQL&gt; exec eygle.definer_proc<br />Current User:&nbsp;&nbsp; EYGLE<br />Session User:&nbsp;&nbsp; TEST<br /><strong>Current Schema: EYGLE</strong></pre>
            <pre>PL/SQL procedure successfully completed.</pre>
            <pre>SQL&gt; exec eygle.invoker_proc<br />Current User:&nbsp;&nbsp; TEST<br />Session User:&nbsp;&nbsp; TEST<br /><strong>Current Schema: TEST</strong></pre>
            <pre>PL/SQL procedure successfully completed.<br /></pre>
            </td>
        </tr>
    </tbody>
</table>
<p>注意只有使用invoker者权限执行时，Schema才转换为TEST.</p>]]></description>
<link>http://www.eygle.com/archives/2005/12/definer_and_invoker_rights.html</link>
<guid>http://www.eygle.com/archives/2005/12/definer_and_invoker_rights.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Mon, 12 Dec 2005 12:08:34 +0800</pubDate>
</item>
<item>
<title>批量绑定(bulk binds):FOR循环与FORALL的性能比较</title>
<description><![CDATA[通常在SQL语句中给PL/SQL变量赋值叫做绑定（Binding）,一次绑定一个完整的集合称为批量绑定（Bulk Binding）。<br>
<br>
批量绑定（Bulk binds）可以通过减少在PL/SQL和SQL引擎之间的上下文切换(context switches )提高了性能.<br>
<br>
批量绑定（Bulk binds）包括：<br>
(i)  Input collections, use the FORALL statement，一般用来改善DML（INSERT、UPDATE和DELETE) 操作的性能<br>
(ii) Output collections, use BULK COLLECT clause，一般用来提高查询（SELECT）的性能<br>
<br>
FORALL的语法如下：<br>
<br>
<blockquote><strong>FORALL index IN lower_bound..upper_bound
<em>sql_statement</em>;</strong><br></blockquote>
<br>
下面是一个简单测试，用以说明FORALL与FOR循环的性能差异。<br>
<table><td width="500" bgcolor="#999999"><pre>
SQL> drop table blktest;

Table dropped.

Elapsed: 00:00:00.13
SQL> 
SQL> CREATE TABLE blktest (num NUMBER(20), name varchar2(50));

Table created.

Elapsed: 00:00:00.08
SQL> 
SQL> CREATE OR REPLACE PROCEDURE bulktest
  2  IS
  3     TYPE numtab IS TABLE OF NUMBER (20)
  4        INDEX BY BINARY_INTEGER;
  5  
  6     TYPE nametab IS TABLE OF VARCHAR2 (50)
  7        INDEX BY BINARY_INTEGER;
  8  
  9     pnums    numtab;
 10     pnames   nametab;
 11     t1       NUMBER;
 12     t2       NUMBER;
 13     t3       NUMBER;
 14  BEGIN
 15     FOR j IN 1 .. 1000000
 16     LOOP
 17        pnums (j)         := j;
 18        pnames (j)        := 'Seq No. ' || TO_CHAR (j);
 19     END LOOP;
 20  
 21     SELECT DBMS_UTILITY.get_time
 22       INTO t1
 23       FROM DUAL;
 24  
 25     FOR i IN 1 .. 1000000
 26     LOOP
 27        INSERT INTO blktest
 28             VALUES (pnums (i), pnames (i));
 29     END LOOP;
 30  
 31     SELECT DBMS_UTILITY.get_time
 32       INTO t2
 33       FROM DUAL;
 34  
 35     FORALL i IN 1 .. 1000000
 36        INSERT INTO blktest
 37             VALUES (pnums (i), pnames (i));
 38  
 39     SELECT DBMS_UTILITY.get_time
 40       INTO t3
 41       FROM DUAL;
 42  
 43     DBMS_OUTPUT.put_line ('Execution Time (hsecs)');
 44     DBMS_OUTPUT.put_line ('---------------------');
 45     DBMS_OUTPUT.put_line ('FOR loop: ' || TO_CHAR (t2 - t1));
 46     DBMS_OUTPUT.put_line ('FORALL:   ' || TO_CHAR (t3 - t2));
 47  END;
 48  /

Procedure created.

Elapsed: 00:00:01.46
SQL> exec bulktest;
Execution Time (hsecs)
---------------------
<strong>FOR loop: 30361
FORALL:   4792</strong>

PL/SQL procedure successfully completed.

Elapsed: 00:06:32.92
</pre></td></table><br>
]]></description>
<link>http://www.eygle.com/archives/2005/11/bulk_binds_forall.html</link>
<guid>http://www.eygle.com/archives/2005/11/bulk_binds_forall.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Sun, 13 Nov 2005 20:28:09 +0800</pubDate>
</item>
<item>
<title>How to use Oracle Dump Function</title>
<description><![CDATA[<p class="BP"><code><font face="新宋体">DUMP</font></code> returns a <code><font face="新宋体">VARCHAR2</font></code> value containing the datatype code, length in bytes, and internal representation of <em><code><font face="新宋体">expr</font></code></em>. The returned result is always in the database character set.</p>
<p class="BP">The syntax is:</p>
<pre><strong>DUMP</strong>(expr[,return_fmt[,start_position[,length]]])
</pre>
<a name="83079"></a>
<p class="BP">The argument <em><code><font face="新宋体">return_fmt</font></code></em> specifies the format of the return value and can have any of the following values:</p>
<ul class="LB1">
    <li class="LB1" type="disc"><a name="89718"></a>8 returns result in octal notation. </li>
    <li class="LB1" type="disc"><a name="89719"></a>10 returns result in decimal notation. </li>
    <li class="LB1" type="disc"><a name="89720"></a>16 returns result in hexadecimal notation. </li>
    <li class="LB1" type="disc"><a name="89721"></a>17 returns result as single characters. </li>
</ul>
<a name="83095"></a>
<p class="BP">By default, the return value contains no character set information. To retrieve the character set name of <em><code><font face="新宋体">expr</font></code></em>, specify any of the preceding format values, plus 1000. For example, a <em><code><font face="新宋体">return_fmt</font></code></em> of 1008 returns the result in octal, plus provides the character set name of <em><code><font face="新宋体">expr</font></code></em>.</p>
<a name="83114"></a>
<p class="BP">The arguments <em><code><font face="新宋体">start_position</font></code></em> and <em><code><font face="新宋体">length</font></code></em> combine to determine which portion of the internal representation to return. The default is to return the entire internal representation in decimal notation.</p>
<a name="83115"></a>
<p class="BP">If <em><code><font face="新宋体">expr</font></code></em> is null, then this function returns a null.</p>
<h4 class="SH1"><font face="Arial, Helvetica, sans-serif">Examples</font></h4>
<a name="1023569"></a>
<p class="BP">The following examples show how to extract dump information from a string expression and a column:</p>
<pre class="CE"><a name="83121"></a>SELECT DUMP('abc', 1016)
<a name="83122"></a>   FROM DUAL;
<a name="83123"></a>
<a name="83124"></a>DUMP('ABC',1016)
<a name="83125"></a>------------------------------------------
<a name="82996"></a>Typ=96 Len=3 CharacterSet=WE8DEC: 61,62,63
<a name="95853"></a>
<a name="1202355"></a>SELECT DUMP(last_name, 8, 3, 2) &quot;OCTAL&quot;
<a name="83134"></a>   FROM employees
<a name="83135"></a>   WHERE last_name = 'Hunold';
<a name="83136"></a>
<a name="83137"></a>OCTAL
<a name="1023552"></a>-------------------------------------------------------------------
<a name="1023553"></a>Typ=1 Len=6: 156,157
<a name="1023554"></a>
<a name="95857"></a>SELECT DUMP(last_name, 10, 3, 2) &quot;ASCII&quot;
<a name="83147"></a>   FROM employees
<a name="83148"></a>   WHERE last_name = 'Hunold';
<a name="83149"></a>
<a name="83150"></a>ASCII
<a name="1023561"></a>--------------------------------------------------------------------
<a name="1023562"></a>Typ=1 Len=6: 110,111
</pre>
<!-- Start Footer -->]]></description>
<link>http://www.eygle.com/archives/2005/11/how_to_use_oracle_dump_function.html</link>
<guid>http://www.eygle.com/archives/2005/11/how_to_use_oracle_dump_function.html</guid>
<category>SQL.PLSQL</category>
<pubDate>Thu, 10 Nov 2005 12:33:41 +0800</pubDate>
</item>


</channel>
</rss>