<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
   <channel>
      <title>Hey!! Sky!</title>
      <link>http://www.heysky.net/</link>
      <description></description>
      <language>en</language>
      <copyright>Copyright 2007</copyright>
      <lastBuildDate>Sun, 18 Mar 2007 23:20:24 +0700</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

            <item>
         <title>SPIDER-MAN 3</title>
         <description><![CDATA[<div style="float: left; margin-right: 10px; margin-bottom: 10px"> <a href="http://www.yupoo.com/photos/view?id=ff808081114493150111654cb1156885" target="_blank" title="photo sharing"> <img src="http://photo1.yupoo.com/20070318/214636_829882415.jpg" border="0" width="135" height="200" /> </a> <br /> <span style="font-size: 0.8em; margin-top: 0px"> <a href="http://www.yupoo.com/photos/view?id=ff808081114493150111654cb1156885">双面蜘蛛侠</a><br /> 由<a href="http://sky1010.yupoo.com/profile/" target="_blank">Sky</a>上传于<a href="http://www.yupoo.com/">Yupoo</a>. </span> </div> <div> Find a new poster of spider-man 3 on netease. I have looked forward to it for a long time. And fortunately, it will be on show in May. In this film, we can see two spidermen - the red one and the black on. It will certainly be interesting when two spidermen fight among the buildings.</div><div>&nbsp;</div><div>See more posters <a href="http://ent.163.com/07/0317/13/39PPJDN000031NJQ.html" target="_blank">here</a>.</div>]]></description>
         <link>http://www.heysky.net/archives/2007/03/spiderman_3.html</link>
         <guid>http://www.heysky.net/archives/2007/03/spiderman_3.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Hobby</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Film</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">Spiderman</category>
        
         <pubDate>Sun, 18 Mar 2007 23:20:24 +0700</pubDate>
      </item>
            <item>
         <title>ORA-01745:invalid host/bind variable name</title>
         <description><![CDATA[<p>Today I wrote a simple procedure for a friend:</p><blockquote>create or replace procedure P_QN_SERVICE is<br />&nbsp; l_table_name varchar2(100);<br />&nbsp; no_table EXCEPTION;<br />&nbsp; PRAGMA EXCEPTION_INIT(no_table, -942);<br />begin<br />&nbsp; l_table_name := &#39;v_dat_sdr_&#39; || to_char(sysdate - 1, &#39;yyyymmdd&#39;);<br />&nbsp; execute immediate &#39;insert into t_qn_service_bak(stime,service_id,cnt) &#39; ||<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;select :date,service_id,count(*) from USBOSS2.&#39; ||<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l_table_name ||<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;@usboss where service_id in (&#39;&#39;0575SXZQ&#39;&#39;,&#39;&#39;0575MiYu&#39;&#39;,&#39;&#39;0575News&#39;&#39;,&#39;&#39;0575SMS&#39;&#39;,&#39;&#39;0575Test&#39;&#39;,&#39;&#39;0575QYDT&#39;&#39;,&#39;&#39;05759004050101&#39;&#39;) group by service_id&#39;<br />&nbsp;&nbsp;&nbsp; using trunc(sysdate - 1);<br />&nbsp; commit;<br />exception<br />&nbsp; when no_table then<br />&nbsp;&nbsp;&nbsp; dbms_output.putline(&#39;The view USBOSS2.&#39; || l_table_name ||<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;does not exists!&#39;);<br />end; </blockquote><p>&nbsp;</p><p>&nbsp;Here I use a bind variable &quot;:date&quot;. But when I execute this procedure, it raise an error &quot;ORA-01745&quot;.</p><p>Here is the introduction about this error:</p><blockquote>ORA-01745: invalid host/bind variable name<br />Cause: A colon in a bind variable or INTO specification was followed by an inappropriate name, perhaps a reserved word.<br />Action: Change the variable name and retry the operation. </blockquote><p>&nbsp;</p><p>After I changed the bind variable &quot;:date&quot; to &quot;:l_date&quot;, it worked well.</p><p>Blog this case here to remind myself do not use reserved word as a bind variable. </p>]]></description>
         <link>http://www.heysky.net/archives/2007/03/ora_01745.html</link>
         <guid>http://www.heysky.net/archives/2007/03/ora_01745.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Database</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Case</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">Oracle</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">PL/SQL</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">SQL</category>
        
         <pubDate>Thu, 15 Mar 2007 22:42:54 +0700</pubDate>
      </item>
            <item>
         <title>Oracle 9i New Feature: Multitable Inserts</title>
         <description><![CDATA[<p>Today, a friend asked me on QQ whether there is a way to merge two SQL like:</p><blockquote>insert into table（a,b） values(&#39;aa&#39;,&#39;bb&#39;);<br />insert into table（a,b） values(&#39;cc&#39;,&#39;dd&#39;);</blockquote>into one SQL statement.<p>I think there&#39;s no meaning to do that. But there is a way to implement it. Is is a new feature in Oracle 9i:&nbsp; Multitable Inserts.</p><p>There are two syntaxes:<br /><br />1. Unconditional insert into ALL tables</p><blockquote>INSERT ALL<br />&nbsp; INTO sal_history VALUES(empid,hiredate,sal)<br />&nbsp; INTO mgr_history VALUES(empid,mgr,sysdate) <br />SELECT employee_id EMPID, hire_date HIREDATE, salary SAL, manager_id MGR<br />&nbsp; FROM employees WHERE employee_id &gt; 200;&nbsp;</blockquote><p>2. Conditionally insert into ALL / First tables</p><blockquote>INSERT ALL / FIRST<br />&nbsp; WHEN SAL &gt; 25000&nbsp; THEN<br />&nbsp;&nbsp;&nbsp; INTO special_sal VALUES(DEPTID,SAL)<br />&nbsp; WHEN HIREDATE like (&#39;%00%&#39;) THEN<br />&nbsp;&nbsp;&nbsp; INTO hiredate_history_00 VALUES(DEPTID,HIREDATE)<br />&nbsp; WHEN HIREDATE like (&#39;%99%&#39;) THEN <br />&nbsp;&nbsp;&nbsp; INTO hiredate_history_99 VALUES(DEPTID,HIREDATE)<br />&nbsp; ELSE<br />&nbsp;&nbsp;&nbsp; INTO hiredate_history VALUES(DEPTID, HIREDATE)<br />SELECT department_id DEPTID, SUM(salary) SAL,<br />&nbsp;&nbsp;&nbsp; MAX(hire_date) HIREDATE<br />&nbsp; FROM employees GROUP BY department_id;</blockquote><p>Semantics:<br />ALL: insert into all the table. <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; You can only use ALL keyword in Unconditional insert.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If you use ALL keyword in Conditional insert, it means insert data into all the table that meet the condition.</p><p>FIRST:&nbsp; If you use FIRST keyword in Conditional insert, it means insert data into the first table that meet the condition.</p><p>ELSE: If you use ELSE keyword, the row that don&#39;t meet any condition will be inserted into this table. Otherwise, the row will not be inserted into any table.</p><p>Now I&#39;ll give an example that resolve the issue above with multitable inserts:</p><blockquote>STSC@SBOX&gt; create table alltest (a varchar2(10), b varchar2(10));<br /><br />Table created.<br /><br />Elapsed: 00:00:00.00<br />STSC@SBOX&gt; insert all <br />&nbsp; 2&nbsp; into alltest values(a,b)<br />&nbsp; 3&nbsp; into alltest values(c,d)<br />&nbsp; 4&nbsp; select &#39;aa&#39; a,&#39;bb&#39; b,&#39;cc&#39; c,&#39;dd&#39; d from dual;<br /><br />2 rows created.<br /><br />Elapsed: 00:00:00.00<br />STSC@SBOX&gt; select * from alltest;<br /><br />A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B<br />-------------------- --------------------<br />aa&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bb<br />cc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dd<br /><br />2 rows selected.<br /><br />Elapsed: 00:00:00.00&nbsp;</blockquote><p>It&#39;s easy!!</p><p>Reference: <a href="http://www.oracle-base.com/articles/9i/SQLNewFeatures9i.php#MultitableInserts" target="_blank">SQL New Features In Oracle9i</a> &nbsp;</p>]]></description>
         <link>http://www.heysky.net/archives/2007/03/multitab_inserts.html</link>
         <guid>http://www.heysky.net/archives/2007/03/multitab_inserts.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Database</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Multitable Inserts</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">Oracle</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">SQL</category>
        
         <pubDate>Tue, 13 Mar 2007 17:13:18 +0700</pubDate>
      </item>
            <item>
         <title>Oracle SQLServer 的随机数问题</title>
         <description><![CDATA[<p>在数据库操作中经常会碰到使用随机数的问题，几天前翔哥来问我关于 <font face="Arial">SQLServer 批量产生随机数的问题，记得之前他也问过我 Oracle 下面随机数的问题，当时找到了一些资料但没来得及整理，今天正好把 Oracle 和 SQLServer 下的随机数问题整理一下。</font></p> <strong>1. 产生随机数</strong><br /> <li>Oracle<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Oracle 下随机数可以用 <font face="Arial">DBMS_RANDOM 包来实现，他调用 Oracle 内部随机数生成器来产生随机数，具体使用可以参考<a href="http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96612/d_random.htm#998102" target="_blank">文档</a>，另外 <a href="http://www.psoug.org" target="_blank">psoug</a>&nbsp;上有更详细的<a href="http://www.psoug.org/reference/dbms_random.html" target="_blank">参考</a>。</font> </li> <li>SQLServer&nbsp;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SQLServer 下可以用 <font face="Arial">RAND 函数产生随机数，不过这个函数似乎只能一次产生一个随机数，如果大批量产生随机数，都是重复的（在 Oracle 中使用 <font face="Arial">DBMS_RANDOM 产生的随机数不太会重复</font>）：<br /> </font><blockquote> <pre>SELECT TOP&nbsp;5 RAND()<br />FROM sysobjects<br /><br />0.72910389475358373<br />0.72910389475358373<br />0.72910389475358373<br />0.72910389475358373<br />0.72910389475358373</pre> </blockquote><font face="Arial"><font face="Arial"><font face="Arial"><font face="Arial"><font face="Arial"><font face="Arial"><font face="Arial"><font face="Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;之后 google 了一下，找到了<font face="Arial"><a href="http://blog.csdn.net/zjcxc/" target="_blank">邹建</a>的一篇<a href="http://blog.csdn.net/zjcxc/archive/2006/08/20/1099215.aspx" target="_blank">文章</a>，巧妙地通过 <font face="Arial">CHECKSUM(NEWID()) 产生随机数，并用 <font face="Arial">RIGHT 函数获得其中几位（我觉得用 Left 更好，这样可以防止首位为 0，从而避免插入数据时位数变少），这样不但很好地实现了批量产生随机数，效率也不错。</font></font></font></font></font></font></font></font></font></font></font> <p><strong>2. 随机从表中取数</strong></p> </li> <li>Oracle<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;之前就是在 Oracle 下碰到了这个问题才去研究随机数，发现非常有意思，方法可以概括为两大类，一类就是根据随机数来 Order by 从而将数据随机排列。这类方法又可以分为两种方法，一种就是用 <font face="Arial">dbms_random 产生随机数：<br /> </font><blockquote> <pre>select *<br />&nbsp; from (select * from t order by dbms_random.value)<br />&nbsp;where rownum &lt; 50;</pre> </blockquote><font face="Arial"><br /> 根据 <font face="Arial">jametong 所说，由于<font face="Arial">随机数发生器本身初始化需要时间，而且产生随机数的过程中会频繁读取数据库，所以这种方法效率最差。第二种方法是用 dbms_utility.get_hash_value 产生随机数：<br /> </font></font></font><blockquote> <pre>select *<br />&nbsp; from (select dbms_utility.get_hash_value(to_char(dbms_utility.get_time) ||<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tb1.col1,2,1048576) rand_num,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.*<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from tb1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; order by rand_num)<br />&nbsp;where rand_num &lt;= 50;</pre> </blockquote>这种方法效率稍好。第二类方法就是用 <font face="Arial">sample 对表做采样，这是效率最高的方法：<br /> </font><blockquote> <pre>SELECT emp FROM emp SAMPLE(10);</pre> </blockquote><font face="Arial">SAMPLE(n) 是一个很有用的方法，它随机从表中抽取 n% 的数据，但并不是一定是 n% 可能小于该值，所以如果总共 1000 行数据，要随机取 100 行，最好将 n 设得大于 10。另外，这种方法只能用于一个表，from 后不能有多个表。</font><br /> </li> <li>SQLServer&nbsp;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SQLServer 下只想到了 Order by&nbsp; 的方法，由于 <font face="Arial">rand() 产生重复，所以还是可以用 <font face="Arial">NEWID() 的方法：</font></font><blockquote> <pre>&nbsp;select top 10 * from tablename order by NEWID()</pre> </blockquote><br /> 参考：<br /> <font face="Arial"><a href="http://www.oracle.com.cn/viewthread.php?tid=20848" target="_blank">CNOUG 的帖子：随机取表中数据</a><br /> <font face="Arial"><a href="http://www.revealnet.com/newsletter-v2/randomising.htm" target="_blank">Getting a random sample of records the good the bad and the ugly&hellip;</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.heysky.net/upload/random.html">本地下载</a> <br /> <font face="Arial"><a href="http://www.heysky.net/upload/Getting%20a%20Random%20Sample%20of%20Records.mht">How do I randomly select rows from a table（本地下载）</a> </font></font></font></li>]]></description>
         <link>http://www.heysky.net/archives/2006/10/oracle_sqlserver_random.html</link>
         <guid>http://www.heysky.net/archives/2006/10/oracle_sqlserver_random.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Database</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Oracle</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">SQL</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">SQLServer</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">随机数</category>
        
         <pubDate>Mon, 16 Oct 2006 12:57:41 +0700</pubDate>
      </item>
            <item>
         <title>安装完成 EnjoyYourPosting 插件</title>
         <description><![CDATA[<p>花了两天的时间把 <font face="Arial"><a target="_blank" href="http://alogblog.com/movabletype/plugins/enjoy_your_posting/">EnjoyYourPosting</a> 插件安装完成了，其实安装并不复杂，只是在往其中添加功能时花很大的力气，本想修改原代码来完成预期的功能，但最后还是以失败告终，<a target="_blank" href="http://www.fckeditor.net/">FCKeditor</a> 的确是复杂，看了半天的原代码还是没搞清楚，最后还是通过设置样式来完成的。</font></p>
<p>我安装的是目前最新的版本 <font face="Arial">3.3.02，其中使用的 <font face="Arial">FCKeditor 版本为 2.3.1，目前感觉还算可以，还有些小瑕疵等以后慢慢完善。</font></font></p>]]></description>
         <link>http://www.heysky.net/archives/2006/10/_enjoyyourposting.html</link>
         <guid>http://www.heysky.net/archives/2006/10/_enjoyyourposting.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Web</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Movable Type</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">My Web</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">Plugin</category>
        
         <pubDate>Wed, 11 Oct 2006 14:39:58 +0700</pubDate>
      </item>
            <item>
         <title>The first Weblog</title>
         <description>Have finished the installation and configuration of Movable Type 3.32 on localhost. The next step, I&amp;#39;ll add more function to MT and beautify the web. After all the work, import the data from oblog to MT. What a big workload! Take it easy!</description>
         <link>http://www.heysky.net/archives/2006/09/first_weblog.html</link>
         <guid>http://www.heysky.net/archives/2006/09/first_weblog.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Web</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Movable Type</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">My Web</category>
        
         <pubDate>Fri, 15 Sep 2006 14:35:20 +0700</pubDate>
      </item>
            <item>
         <title>Ubuntu：所有软件都该免费</title>
         <description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;今天事情比较多，中饭吃得比较晚了，吃完上楼同事告诉我有张国际包 裹的领取单。国际包裹？大脑中飞快地扫描了一遍在国外的朋友，好像应该都不知道我公司的地址吧，再一想 不会是前段时间向微软免费索要的 VISTA Beta2 的免费测试光盘吧，于是拿着包裹单兴冲冲去了不远的邮局 ，拿来一看，一个破破烂烂的纸袋子，上面写着密密麻麻的英文小字，没仔细去看，只看到了那个大大的英文 字母&ldquo;Ubuntu&rdquo;。哈哈哈，原来是一个多月前免费索取的 ubuntu，早把这件事情忘得一干二净了，拆开一看 ，10 张包装简单但印刷漂亮的 CD，其中 5 张 for 32bit pc，3 张 for 64bit pc，2 张 for mac 的，真是丰富阿，心想这公司的老板是不是钱太多了，不但免费使用软件，还免费赠送一套光盘，甚至国际运费都是免费的，回来网上查了下关于 Ubuntu 和该公司老板的资料，会在后边引用。Ubuntu 可以说是现在最漂亮、中 文支持最好，操作最简单的 Linux 系统了。虽然以前也免费领取过微软 xp sp2 的光盘，但那毕竟只是个补丁光盘，没有正版的 xp 根本没用，因此也一直躺在我的光盘盒里，而之前免费领取的&nbsp;VISTA beta2 到现在还没有寄到，现在连 RC1 都出了，估计是没啥希望了。而 Ubuntu 是真正免费领到能用的软件了，看在该公司的慷慨，决定抽空装一下试试。</p> <p><img src="http://photo9.yupoo.com/20060912/001918_920081981_VjTjz.jpg" border="0" align="bottom" /></p> ]]></description>
         <link>http://www.heysky.net/archives/2006/09/ubuntu.html</link>
         <guid>http://www.heysky.net/archives/2006/09/ubuntu.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">OS</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Linux</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">Ubuntu</category>
        
         <pubDate>Mon, 11 Sep 2006 17:10:00 +0700</pubDate>
      </item>
            <item>
         <title>一起去看海</title>
         <description><![CDATA[<P>一起，看，蓝色的海，三亚，我们，来了！</P>
<P><img src="http://photo7.yupoo.com/20060828/230851_611172144_hEUts.jpg" border=0 onclick="javascript:window.open(this.src);" style="CURSOR: pointer" onload="javascript:if(this.width>350){this.resized=true;this.style.width=350;}"></P>
<P><img src="http://photo7.yupoo.com/20060828/230851_1601960902_coFhp.jpg" border=0 onclick="javascript:window.open(this.src);" style="CURSOR: pointer" onload="javascript:if(this.width>350){this.resized=true;this.style.width=350;}"></P>]]></description>
         <link>http://www.heysky.net/archives/2006/08/post_91.html</link>
         <guid>http://www.heysky.net/archives/2006/08/post_91.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Life</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Vivian</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">三亚</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">旅行</category>
        
         <pubDate>Mon, 28 Aug 2006 23:16:44 +0700</pubDate>
      </item>
            <item>
         <title><![CDATA[Oracle&nbsp;PL/SQL&nbsp;Programming&nbsp;读书笔记（Collections）]]></title>
         <description><![CDATA[<p><font size="5"><strong>Collections</strong></font></p> <p><br /><font size="3"><strong>Collections Overview</strong></font><br />&nbsp; <strong>Types of Collections</strong><br />&nbsp;&nbsp;&nbsp; Associative arrays<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 他是同种类型的一维、无边界的稀疏集合，只能用于 PL/SQL<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE TYPE t_name IS TABLE OF varchar2(10) INDEX BY PLS_INTEGER;&nbsp; --创建 Collection<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i_name t_name;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --创建 instance<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l_row PLS_INTEGER;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BEGIN<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i_name(202020):=&#39;aaa&#39;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i_name(-125):=&#39;bbb&#39;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i_name(88):=&#39;ccc&#39;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --赋值，row number 可以为任何整数，且可以跳跃（稀疏的），也不用按照顺序赋值，其内部最终按照 row number 排序<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l_row := i_name.FIRST;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --返回第一个 row number<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l_row := i_name.NEXT (l_row);&nbsp;&nbsp; --返回 l_row 之后的一个 row number，会自动跳过为空的行<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DBMS_OUTPUT.put_line (i_name (l_row));&nbsp; --返回指定行的值<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END;</p> ]]></description>
         <link>http://www.heysky.net/archives/2006/08/oracle_plsql_collections.html</link>
         <guid>http://www.heysky.net/archives/2006/08/oracle_plsql_collections.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Database</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Oracle</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">SQL</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">学习笔记</category>
        
         <pubDate>Tue, 22 Aug 2006 15:41:33 +0700</pubDate>
      </item>
            <item>
         <title><![CDATA[9i&nbsp;Performance&nbsp;Tuning&nbsp;Guide&nbsp;读书笔记二]]></title>
         <description><![CDATA[<p><font size="5"><strong>Optimizer Operations</strong></font></p> <p><font size="3"><strong>How the Optimizer Performs Operations</strong></font><br />&nbsp;&nbsp;&nbsp; <strong>How the CBO Evaluates IN-List Iterators</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当 IN clause 指定了特定的值，并且在该列上有索引，优化器选择 IN-list iterator。如果有多个 OR clauses 使用相同的索引，那么优化器选择更高效的 IN-list iterator，而不使用 CONCATENATION or UNION ALL。<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; <strong>How the CBO Evaluates Concatenation</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;当不同的条件使用 OR clause 连接起来，并且不同的条件都可以通过不同的索引生成较好的执行计划，那么 Concatenation 是很有用的。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;HINT：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; USE_CONCAT<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;NO_EXPAND 会禁止使用 Concatenation，他其实是阻止 QUERY 扩展为多个 QUERY<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;当一下情况时不要使用 Concatenation：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 1.OR conditions 在同一个列上，可以使用 IN-list，后者更高效。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.每一个 concatenation 都重复昂贵的步骤。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; &nbsp; <strong>How the CBO Evaluates Remote Operations</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;影响执行计划的因素：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1.Network round trips 比物理和逻辑 I/Os 昂贵几个数量级<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 2.如果远程数据库不是 Oracle 数据库，优化器无法获得远程数据库的任何 statistics<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;一般来说，优化器在访问本地表之前先访问远程表<br />&nbsp;&nbsp;&nbsp; ]]></description>
         <link>http://www.heysky.net/archives/2006/08/optimizer_operations_notes.html</link>
         <guid>http://www.heysky.net/archives/2006/08/optimizer_operations_notes.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Database</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Oracle</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">优化</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">学习笔记</category>
        
         <pubDate>Fri, 18 Aug 2006 15:55:10 +0700</pubDate>
      </item>
            <item>
         <title>[实用]穴道指压图</title>
         <description><![CDATA[<p>哪儿不舒服就按哪儿，<a href="http://photo9.yupoo.com/20061003/234946_328723697_inueoruf.jpg" target="_blank">看完整大图</a><br /><br /><img src="http://photo9.yupoo.com/20061003/234949_1082334851_uqykpfax.jpg" border="0" /></p>]]></description>
         <link>http://www.heysky.net/archives/2006/08/finger_press.html</link>
         <guid>http://www.heysky.net/archives/2006/08/finger_press.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Life</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Life</category>
        
         <pubDate>Fri, 18 Aug 2006 09:50:09 +0700</pubDate>
      </item>
            <item>
         <title><![CDATA[Oracle&nbsp;PL/SQL&nbsp;Programming&nbsp;读书笔记（Records&nbsp;in&nbsp;PL/SQL）]]></title>
         <description><![CDATA[<p><font size="5"><strong>Records in PL/SQL</strong></font></p> <p><br /><strong><font size="3">1.Declaring Records</font></strong><br />&nbsp;&nbsp;&nbsp; <strong>Table-based record</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE one_book books%ROWTYPE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; <strong>Cursor-based record</strong><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE CURSOR my_books_cur IS<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT * FROM books<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE author LIKE &#39;%FEUERSTEIN%&#39;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; one_SF_book my_books_cur%ROWTYPE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; 以上两种方法都使用了 %ROWTYPE 属性，语法为：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; record_name [schema_name.]object_name%ROWTYPE<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ DEFAULT|:= compatible_record ];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schema_name 是可选的，默认为编译该代码的 schema<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; object_name 可以是 explicit cursor, cursor variable, table, view, or synonym<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以指定一个默认值，默认值必须是和 record 相同或者兼容的类型<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用 cursor variable 的例子：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE TYPE book_rc IS REF CURSOR RETURN books%ROWTYPE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; book_cv book_rc;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; one_book book_cv%ROWTYPE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BEGIN<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...</p> ]]></description>
         <link>http://www.heysky.net/archives/2006/08/oracle_plsql_records.html</link>
         <guid>http://www.heysky.net/archives/2006/08/oracle_plsql_records.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Database</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Oracle</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">SQL</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">学习笔记</category>
        
         <pubDate>Mon, 14 Aug 2006 16:15:53 +0700</pubDate>
      </item>
            <item>
         <title>广告时间</title>
         <description><![CDATA[<p><strong>Health Work Ad.</strong></p><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="0" height="0"><param name="movie" value="http://sky1010.googlepages.com/814270875.wmv" /><param name="quality" value="high" /><param name="menu" value="false" /><param name="wmode" value="" /><embed src="http://sky1010.googlepages.com/814270875.wmv" wmode="" quality="high" menu="false" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="0" height="0"></embed></object>  <p>&nbsp;</p><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="0" height="0"><param name="movie" value="http://sky1010.googlepages.com/814262786.wmv" /><param name="quality" value="high" /><param name="menu" value="false" /><param name="wmode" value="" /><embed src="http://sky1010.googlepages.com/814262786.wmv" wmode="" quality="high" menu="false" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="0" height="0"></embed></object>  <p>&nbsp;</p>]]></description>
         <link>http://www.heysky.net/archives/2006/08/healthwork_ad.html</link>
         <guid>http://www.heysky.net/archives/2006/08/healthwork_ad.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Other</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Healthwork</category>
        
         <pubDate>Mon, 14 Aug 2006 14:17:10 +0700</pubDate>
      </item>
            <item>
         <title><![CDATA[Oracle&nbsp;PL/SQL&nbsp;Programming&nbsp;读书笔记（Dates&nbsp;and&nbsp;Timestamps）]]></title>
         <description><![CDATA[<P><FONT size=5><STRONG>Dates and Timestamps</STRONG></FONT></P>
<P><STRONG>1.Datetime Datatypes</STRONG><BR>&nbsp;&nbsp;&nbsp; <STRONG>DATE<BR></STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 存储日期、时间，没有时区，精确到秒，是 9i 之前唯一的 datetime datatype。<BR>&nbsp;&nbsp;&nbsp; <STRONG>TIMESTAMP [(precision)]</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 除了最多精确到 billionth of a second，其他和 DATE 一样。<BR>&nbsp;&nbsp;&nbsp; <STRONG>TIMESTAMP [(precision)] WITH TIME ZONE</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMESTAMP 的基础上，保存时区信息。在内部存储时，Oracle 将时间转换为 UTC 格式进行保存，比如：2002-02-06 20:00:00:00.00 -5:00。<BR>&nbsp;&nbsp;&nbsp; <STRONG>TIMESTAMP [(precision)] WITH LOCAL TIME ZONE</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不保存时区信息，但会将时间转换为数据库的时区（如果是保存到数据库表的列中）或者 session 的时区（如果保存为 PL/SQL variables）。数据在不同时区间传输时，会进行转换，但不保存时区信息。<BR>&nbsp;&nbsp;&nbsp; 其中 precision 表示秒的小数部分保留的位数，范围为：0~9。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>如何选择 Datetime Datatype</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.如果你要精确到秒的小数位，那么使用 TIMESTAMP<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.如果要保留 datetime 值的时区，那么使用 TIMESTAMP WITH TIME ZONE <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.可以用 TIMESTAMP(0) 代替 DATE，但是两者的日期算法是不同的<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.为了兼容 TIMESTAMP 出现之前的应用程序，那么使用 DATE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.PL/SQL 代码中的类型应该和数据库表中的类型相一致，比如将 TIMESTAMP WITH TIME ZONE 的类型存放到 DATE 类型的列中，时区就会丢失<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6.使用 9i 以前的版本，那么只能使用 DATE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7.将 ADD_MONTHS 这种传统操作 DATE 类型的函数应用到新的 TIMESTAMP 类型上，会产生很大的不同<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P><STRONG>2.获得现在的时间</STRONG><BR>&nbsp; Function&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Time zone&nbsp;&nbsp;&nbsp; Datatype returned<BR>&nbsp; CURRENT_DATE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATE<BR>&nbsp; CURRENT_TIMESTAMP&nbsp;&nbsp; Session&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMESTAMP WITH TIME ZONE<BR>&nbsp; LOCALTIMESTAMP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Session&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMESTAMP<BR>&nbsp; SYSDATE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Server&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATE<BR>&nbsp; SYSTIMESTAMP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Server&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMESTAMP WITH TIME ZONE</P>
<P>&nbsp; 注：返回的都是数据库服务器端的当时时间，单前三者会转换为 session 的时区，可以用 alter session set time_zone 改变<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9i 之前只有 SYSDATE<BR>&nbsp;</P>
<P><STRONG>3.Interval Datatypes</STRONG><BR>&nbsp;&nbsp;&nbsp; <STRONG>INTERVAL YEAR TO MONTH</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Allows you to define an interval of time in terms of years and months.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTERVAL YEAR [(year_precision)] TO MONTH<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; year_precision：year 的位数，范围：0~4，默认：2<BR>&nbsp;&nbsp;&nbsp; <STRONG>INTERVAL DAY TO SECOND</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Allows you to define an interval of time in terms of days, hours, minutes, and seconds (including fractional seconds).<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTERVAL DAY [(day_precision)] TO SECOND [(frac_sec_prec)]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day_precision：day 的位数，范围：0~9，默认：2<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frac_sec_prec：秒小数部分保留的位数，范围：0~9，默认：6<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; Month、hour、minute、second 的精度是不用设置的，Oracle 会保证他们的范围分别在 0~11、0~23、0~59、0~59</P>
<P><BR><STRONG>4.Datetime Conversions</STRONG><BR>&nbsp;&nbsp;&nbsp; Date 范围：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4712-01-01 B.C. —— 9999-12-31 A.D.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>From Strings to Datetimes</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 隐式：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 根据 NLS_DATE_FORMAT 的格式写 String 的值，Oracle 会隐式转换，如果和 NLS_DATE_FORMAT 不匹配，不能转换。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显式（使用内建函数）：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_DATE( string[, format_mask[, nls_language]]) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_DATE( number[, format_mask[, nls_language]])<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用数字表示 Julian date 转换为 Date 类型，此时 format_mask = 'J'，number 表示从 January 1, 4712 B.C. 开始的天数，由于 Oracle 中最大日期是 December 31, 9999 A.D.，所以 number 的范围为：1 ~ 5373484<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_TIMESTAMP( string[, format_mask[, nls_language]]) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_TIMESTAMP_TZ( string[, format_mask[, nls_language]]) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 此函数用于将 string 转换为 TIMESTAMP WITH TIME ZONE、TIMESTAMP WITH LOCAL TIME ZONE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; format_mask：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认为 NLS_DATE_FORMAT、NLS_TIMESTAMP_FORMAT、NLS_TIMESTAMP_TZ_FORMAT（分别对应 TO_DATE、TO_TIMESTAMP、TO_TIMESTAMP_TZ）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于 TIMESTAMP 类型，秒的小数部分可以用 '.FF' 或者 'XFF' 表示，比如：'mm/dd/yyyy hh:mi:ss.ff AM TZD' or 'mm/dd/yyyy hh:mi:ssxff AM TZD'，其中 'X' 由 NLS_NUMERIC_CHARACTERS 的第一个字符决定。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nls_language：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Optionally specifies the language to be used to interpret the names and abbreviations of both months and days in the string. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 几个限制：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.传给 TO_DATE 中的 string 长度不能超过 220 个字符。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.format mask 中 Julian date element (J) 和 the day of year element (DDD) 不能同时出现。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.format mask 中 date/time 的某一个部分不能重复出现，比如：'YYYY-YYY-DD-MM'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.format mask 中 HH24 不能和 am/pm 同时出现<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>From Datetimes to Strings</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用 TO_CHAR，默认格式 'DD-MON-RR'（9 位），可以用 NLS_DATE_FORMAT 覆盖。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于 TIMESTAMP 类型，秒的小数部分可以用 FF1 ~ FF9 来表示保留几位（自动四舍五入）。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不能将用于 TIMESTAMP 的 format_mask 用于 DATE 类型，否则会报 ORA-01821，反过来可以。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>Working with Time Zones</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 明确表示某一个时区，应该联合使用 TZH TZM 或者 TZR TZD<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TZH：与 UTC 之间 HOUR 的偏移<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TZM：与 UTC 之间 MINUTE 的偏移<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TZR：The time zone region<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TZD：The abbreviated time zone name<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：后两者可以查看 V$TIMEZONE_NAMES 获得<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于时区，存入的是什么信息，显示的也是什么信息，比如用 TZH：TZM 存入和 UTC 之间的偏移，就只能显示类似 +08：00 的时区偏移，而无法显示具体哪个 time zone region<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>二位数年份的处理</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用 RR/RRRR 时，Oracle 自动根据现在的年份辨别输入的二位数年份：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.如果现在是前半世纪（0~49）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果输入的是前半世纪（0~49），那么返回本世纪的年份<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果输入的是后半世纪（50~99），那么返回上世纪的年份<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.如果现在是后半世纪（50~99）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果输入的是前半世纪（0~49），那么返回下世纪的年份<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果输入的是后半世纪（50~99），那么返回本世纪的年份<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用 YY/YYYY 时，不管输入的是什么，都返回本世纪的年份<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：这种自动转换只适用于 String -&gt; Date 的转换，如果是 Date -&gt; String，那就按照 Date 存储的值来转换，此时再用 RR/RRRR 已经没有意义了，因为 Oracle 内部存储的年份是四位数的。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P><STRONG>5.Date and Timestamp Literals</STRONG><BR>&nbsp;&nbsp;&nbsp; 这是 9i 之后 引入的 ISO SQL standard 格式，格式是固定的，不能更改，也不受环境变量影响，因此可以作为常量来使用<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATE 'YYYY-MM-DD'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMESTAMP 'YYYY-MM-DD HH:MI:SS[.FFFFFFFFF] [{+|-}HH:MI]' （HH 必须是 24 小时制的，FFFFFFFFF 可选 1~9 位，也可以没有，时区也可以使用 time zone region（EST），但这只是 Oracle 提供的格式，不是 ANSI/ISO standards）<BR>&nbsp;&nbsp;&nbsp; 例子：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATE '2002-02-19'<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMESTAMP '2002-02-19 14:00:00.000000000 -5:00';<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR><STRONG>6.Interval Conversions</STRONG><BR>&nbsp;&nbsp;&nbsp; <STRONG>Numbers to Intervals</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMTOYMINTERVAL ( n , 'char_expr' )<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMTODSINTERVAL ( n , 'char_expr' )<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char_expr：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Description<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; YEAR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Some number of years, ranging from 1 through 999,999,999<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MONTH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Some number of months, ranging from 0 through 11<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DAY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Some number of days, ranging from 0 to 999,999,999<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HOUR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Some number of hours, ranging from 0 through 23<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MINUTE&nbsp;&nbsp;&nbsp;&nbsp; Some number of minutes, ranging from 0 through 59<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SECOND&nbsp;&nbsp;&nbsp;&nbsp; Some number of seconds, ranging from 0 through 59.999999999<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上不区分大小写<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>Strings to Intervals</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_YMINTERVAL('Y-M')<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_DSINTERVAL('D HH:MI:SS')<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 格式是固定的，不能缺少任何一个部分<BR>&nbsp;<BR>&nbsp;<BR><STRONG>7.Interval Literals</STRONG><BR>&nbsp;&nbsp;&nbsp; 语法： INTERVAL 'character_representation' start_element TO end_element<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; character_representation 不需要指明所有 datetime 的元素，但必须指明从 start_element 到 end_element 的所有连续元素，如果只有 start_element 只需要一个元素就行了，但 start_element 和 end_element 不能跨越 month 和 day。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：由于 bug 的问题，在 9i Releases 1 and 2 和 10g Release 1 中在 pl/sql 中指明部分元素会出错，比如 INTERVAL '1:02' HOUR TO MINUTE，但在 SQL 中不会。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Oracle 自动会将 high-end value 规格化，比如：INTERVAL '72:15' HOUR TO MINUTE 会规格化为 +03 00:15:00.000000，但 INTERVAL '72:75' HOUR TO MINUTE 会报错，只有 high-end value（这里的 HOUR）会自动转换<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR><STRONG>8.CAST and EXTRACT</STRONG><BR>&nbsp;&nbsp;&nbsp; 两者都是 standard SQL functions <BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>CAST（Oracle8 开始）</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CAST（var as type）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：在 SQL 中，type 可以指定长度，比如：varchar2(40)，但在 pl/sql 中不能指定长度<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以在 string、datetime（DATE、TIMESTAMP）之间互相转换<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于无法指定 format，所以取决于 NLS_DATE_FORMAT、NLS_TIMESTAMP_FORMAT、NLS_TIMESTAMP_TZ_FORMAT 环境变量</P>
<P>&nbsp;&nbsp;&nbsp; <STRONG>EXTRACT（Oracle9i 开始）</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语法：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EXTRACT (component_name, FROM {datetime | interval})<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; component_name（不区分大小写）：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Component name&nbsp;&nbsp;&nbsp;&nbsp; Return datatype<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; YEAR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MONTH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DAY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HOUR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MINUTE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SECOND&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMEZONE_HOUR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMEZONE_MINUTE&nbsp;&nbsp;&nbsp; NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMEZONE_REGION&nbsp;&nbsp;&nbsp; VARCHAR2<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TIMEZONE_ABBR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VARCHAR2<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于用 to_char 无法格式化 interval 的显示格式（格式是固定的），所以唯一的方法就是使用 EXTRACT 来格式化<BR>&nbsp;</P>
<P><STRONG>9.Datetime Arithmetic</STRONG><BR>&nbsp;&nbsp;&nbsp; <STRONG>Adding and Subtracting Intervals to/from Datetimes</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.和 Intervals 做 +- 操作。在和 INTERVAL DAY TO SECOND 进行运算时，不用考虑任何问题，但和 INTERVAL YEAR TO MONTH 做运算时，由于它是直接 +- 原始 datetimes 的年和月，所以可能够产生 ORA-01839 错误，应该有相关的 exception 处理语句。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.直接和 number 做 +- 操作。number 表示天数，可以用分数小数表示：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Value&nbsp;&nbsp;&nbsp; Expression&nbsp;&nbsp; Represents<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1/24&nbsp;&nbsp;&nbsp;&nbsp; 1/24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; One hour<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1/1440&nbsp;&nbsp; 1/24/60&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; One minute<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1/86400&nbsp; 1/24/60/60&nbsp;&nbsp; One second<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：不建议进行约分等操作，这样使得程序一目了然。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.使用 ADD_MONTHS 函数。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.如果输入的日期是输入月份中的最后一天，那么结果也是结果月份的最后一天<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add_months(Date '2006-02-28',1)&nbsp; --&gt; 2006-03-31<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.如果结果月份的最后一天小于输入月份的日子，那么结果日期是结果月份的最后一天<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add_months(Date '2006-03-30',-1)&nbsp; --&gt; 2006-02-28<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以构建一个自定义函数，解决 1 的问题，让他不返回月份的最后一天<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FUNCTION my_add_months (<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date_in IN DATE, months_shift IN NUMBER)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN DATE IS<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date_out DATE;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day_in NUMBER;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day_out NUMBER;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BEGIN<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date_out := ADD_MONTHS(date_in, months_shift);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day_in := TO_NUMBER(TO_CHAR(date_in,'DD'));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day_out := TO_NUMBER(TO_CHAR(date_out,'DD'));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF day_out &gt; day_in<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THEN<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date_out := date_out - (day_out - day_in);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END IF;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN date_out;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 建议：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然以上三者 DATE TIMESTAMP 都可以操作，但建议 TIMESTAMP 使用 1，DATE 可以使用 2、3<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>Computing the Interval Between Two Datetimes</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 两个 TIMESTAMP 相减返回的永远是 INTERVAL DAY TO SECOND<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 两个 DATE 相减返回的是天数，如果有小数部分，意思是 hours, minutes, and seconds 转换为天的结果<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MONTHS_BETWEEN 函数：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 定义：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FUNCTION MONTHS_BETWEEN (date1 IN DATE, date2 IN DATE)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RETURN NUMBER<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 尝试了一下也可以使用 TIMESTAMP，但还是建议不使用，不知道会出现什么问题。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.date1 &gt; date2 返回正数，小于返回负数，相等为0<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.如果在同一年的同一月中，结果的范围是 &gt; -1 and &lt; 1，1 和 -1 都是不会到达的，一月按照 31 天计算，TIME 部分也要计算<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.如果 date1 date2 分别是相应月份中的第一天或者最后一天，则返回整数，且忽略 TIME 部分的值<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.如果 date1 date2 在不同的月份中，且至少有一个不是该月的第一天或者最后一天，那么返回小数。小数是基于 31 天为一个月计算的，且要计算 TIME 部分。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>Mixing DATEs and TIMESTAMPs</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由前面可知：TIMESTAMPs 相减返回 INTERVAL DAY TO SECOND，DATEs 相减返回 numeric value<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.如果 DATEs 相减想返回 INTERVAL DAY TO SECOND 需要用 CAST 显示地将 DATEs 转换为 TIMESTAMPs<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CAST(a AS TIMESTAMP) - CAST(b AS TIMESTAMP)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.如果 DATE 和 TIMESTAMP 混合使用，Oracle 隐式地将 DATE 转换为 TIMESTAMP，因此返回的是 INTERVAL DAY TO SECOND<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>Adding and Subtracting Intervals</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTERVAL 相加减必须满足类型相同：两个 INTERVAL DAY TO SECOND 相加减，或者两个 INTERVAL YEAR TO MONTH 相加减，不能混合使用。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>Multiplying and Dividing Intervals</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DATETIMEs 是不能进行乘除运算的，但是 Intervals 可以。进行乘除运算时，每一个元素都会进行运算，如果超过该元素的范围就往上一级元素进位，如果出现小数就将小数部分转化为下一级元素，秒除外。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>Using Unconstrained INTERVAL Types</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于在函数、过程中，参数不能指定精度，因此当 INTERVAL 传入时如果精度大于默认精度：YEAR(2),DAY(2),SECOND(6)，会返回错误 ORA-01873: the leading precision of the interval is too small <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因此，引入两个特殊类型：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; YMINTERVAL_UNCONSTRAINED<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接受任何精度的 INTERVAL YEAR TO MONTH <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DSINTERVAL_UNCONSTRAINED<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接受任何精度的 INTERVAL DAY TO SECOND </P>
<P>&nbsp;<BR><STRONG>10.Date/Time Functions</STRONG><BR>&nbsp;&nbsp;&nbsp; 对于传统的 DATE 函数，比如 ADD_MONTHS 建议不要用于 TIMESTAMP，Oracle 会将他们隐式地转为 DATE，这样会丢失秒的小数部分，还会将时区修改为 SESSION 的时区。因此，对于 TIMESTAMP 应该使用 INTERVAL 来操作。</P>]]></description>
         <link>http://www.heysky.net/archives/2006/08/oracleplsqlprogrammingdatesand.html</link>
         <guid>http://www.heysky.net/archives/2006/08/oracleplsqlprogrammingdatesand.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Database</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Oracle</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">SQL</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">学习笔记</category>
        
         <pubDate>Fri, 11 Aug 2006 14:03:53 +0700</pubDate>
      </item>
            <item>
         <title><![CDATA[9i&nbsp;Performance&nbsp;Tuning&nbsp;Guide&nbsp;读书笔记一]]></title>
         <description><![CDATA[<P><FONT size=5><STRONG>Introduction to the Optimizer</STRONG></FONT></P>
<P><STRONG>Overview of SQL Processing</STRONG><BR>&nbsp; 1. parser 进行语意和语法分析<BR>&nbsp; 2. Optimizer 利用RBO,CBO等方法决定产生查询结果的最有效路径<BR>&nbsp; 3. Row Source Generator 从2中接受优化后的方案，并产生SQL的Execution Plan<BR>&nbsp; 4. SQL Execution Engine运行该执行计划，并产生查询结果</P>
<P><STRONG>Features that Require the CBO</STRONG><BR>&nbsp; 1. Partitioned tables and indexes <BR>&nbsp; 2. Index-organized tables <BR>&nbsp; 3. Reverse key indexes <BR>&nbsp; 4. Function-based indexes <BR>&nbsp; 5. SAMPLE clauses in a SELECT statement <BR>&nbsp; 6. Parallel query and parallel DML <BR>&nbsp; 7. Star transformations and star joins <BR>&nbsp; 8. Extensible optimizer <BR>&nbsp; 9. Query rewrite with materialized views <BR>&nbsp; 10. Enterprise Manager progress meter <BR>&nbsp; 11. Hash joins <BR>&nbsp; 12. Bitmap indexes and bitmap join indexes <BR>&nbsp; 13. Index skip scans<BR>&nbsp; 即使OPTIMIZER_MODE＝rule，这些features仍然会使用CBO</P>
<P><STRONG>Components of the CBO<BR></STRONG>&nbsp; <STRONG>Query Transformer</STRONG><BR>&nbsp;&nbsp;&nbsp; 数据来自于parse后的SQL,是一系列的query block。其目标是测定SQL的形式是否有利于产生好的query plan。有以下4种：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. View Merging <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SQL 中的view 被扩展到单独的query block中。Optimizer会单独分析view query block，这样通常会导致在整体优化上得不到最优的结果。因此query transformer会将大部分view和其他的query block 合并，这样可以在整体上统一优化。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. Predicate Pushing <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 针对没有被merge的view, push the relevant predicates from the containing query block into the view query block, which can be used either to access indexes or to act as filters<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. Subquery Unnesting <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 子查询是nested在主查询中的，这样很难得到好的优化结果。所以将他们unnested，变成join<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. Query Rewrite with Materialized Views <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果查询与某个物化视图符合的化，则会按照物化视图重写这个查询，因为物化视图的结果都是事先计算好的。</P>
<P><STRONG>&nbsp; Estimator</STRONG><BR>&nbsp; 产生 3 种度量标准：<BR>&nbsp;&nbsp;&nbsp; 1. Selectivity <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示有多少 rows 可以通过谓词被选择出来，大小介于 0.0~1.0，0 表示没有 row 被选择出来。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果没有 statistics，estimator 会使用一个默认的 selectivity 值，这个值根据谓词的不同而异。比如 '=' 的 selectivity 小于 '&lt;'。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果有 statistics，比如对于 last_name = 'Smith'，estimator 使用 last_name 列的 distinct 值的倒数（注：是指表中所有 last_name 的 distinct 值），作为 selectivity。<BR>如果 last_name 列上有 histogram，则使用 histogram 根据 last_name 值的分布情况产生的 selectivity 作为 selectivity。Histogram 在当列有数据倾斜时可以大大帮助 CBO 产生好的 selectivity。</P>
<P>&nbsp;&nbsp;&nbsp; 2. Cardinality <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示一个 row set 的行数。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Base cardinality：base table 的行数。如果表分析过了，则直接使用分析的统计信息。如果没有，则使用表 extents 的数量来估计。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Effective cardinality：有效行集，指从基表中选择出来的行数。是 Base cardinality 和表上所有谓词的组合 Selectivity 的乘积。如果表上没有谓词，那么 Effective cardinality = Base cardinality。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Join cardinality：两表 join 后产生的行数。是两表 cardinality 的乘积(Cartesian)乘以 Join 谓词的 selectivity。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Distinct cardinality：列上 distinct 值的行数。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Group cardinality：GROUP BY 操作之后 row set 的行数。由 grouping columns 的 distinct cardinality 和整个 row set 的行数决定。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; group cardinality lies between max ( dist. card. colx , dist. card. coly )<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;and min ( (dist. card. colx * dist. card. coly) ,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num rows in row set ) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 3. Cost <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Cost 表现了 Disk I/O, CPU usage, Memory usage 资源单位的使用数量（units of work or resource used）。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Access path 决定从 base table 获得数据所需的 units of work 的数量。也就是说Access path 决定 Cost 的值。Access path 可以是 table scan, fast full index scan, index scan。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Clustering Factor：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Index 的一种属性，表示被索引的行在数据块中的分布情况，表征表中数据的存储顺序和某索引字段顺序的符合程度。直接影响使用 rowid 找到 row 的cost。大小介于 block 数和 rownum 之间。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （以下来自biti_rainy <A href="http://blog.itpub.net/post/330/2970">http://blog.itpub.net/post/330/2970</A> ）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Oracle 按照索引块中存储的 rowid 来识别相临的索引中记录在表 block 中是否为相同块，如果索引中存在记录 rowid a,b,c,d……,若b 和 a 是同一个block，则比较 c 和 b，若这时不是同一个block，则 clustering_factor + 1 ,然后比较 d 和 c，若还不是同一个 block，则clustering_factor + 1……<BR>若 clustering_factor 接近表 block 数量，则说明表中数据具有比较好的跟索引字段一样排序顺序的存储，通过索引进行 range scan 的代价比较小（需要读取的表块可能比较少）,若 clustering_factor 接近 row 数量，则说明表中数据和索引字段排序顺序差异很大，杂乱无张。则通过索引进行 range scan 的代价比较大（需要读取的表块可能更多）。<BR>当然，在 oracle 920 开始，对于cluster_factor 比较接近表块数量的根据索引的大范围查询做了特别的处理，不再是读一个索引记录去搜索一个表记录了，而是成批处理（通过索引块一批 rowid 一次去表块中获得一批记录），这样就大大节约了读的成本（consistent gets）。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Join Cost：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;表征了做 join 的两个 row sets 分别 cost 的组合。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Nested loop join：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; outer row set 的每行遍历 inner row set 的所有行，寻找匹配的行。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cost = outer access cost + (inner access cost * outer cardinality)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sort merge join：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 做 join 的两个 row sets 根据 join keys 进行排序，如果他们不是按照 join keys 的顺序的话。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cost = outer access cost + inner access cost + sort costs (outer and inner, if sort is used)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hash join：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cost = (outer access cost * # of hash partitions) + inner access cost<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先理解 hash table 的数据结构：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以把 hash table 看做一个 2 维数组 a[200][100]，现有 1000 个无序数字用来被查询。我们考虑把这 1000 个数字除以 200，根据其余数放在 a[200][100] 中，余数就是数组的第一维下标。这样平均一个 a[i] 只放5个数字。当查询的时候，对数字除以 200（这就是一个简单的 hash 算法），根据余数 i 去 a[i] 中查找，大约遍历 5 次就能找到。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Inner row（小表）被 hash 在内存中，并且通过 join key 建立 hash table（作为第一个下标），然后 scan outer table，到 hash table 中查找 joined rows（通过 hash 算法）。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hash table 会按照 multiblock_IO 决定分成几个 partitions。如果 hash table 太大超出了 hash_area_size，则将超出部分的 partitions 放到 temporary segments 中。<BR>可以通过 10104 events 查看 hash join 的 statistics：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ALTER SESSION SET EVENTS '10104 trace name context forever, level 10'; 比如：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Total number of partitions:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of partitions which could fit in memory:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果后者大于前者，则说明一些 partitions 因为超出了 hash_area_size，要被放置到临时表空间中。</P>
<P>&nbsp; <STRONG>Plan Generator</STRONG><BR>&nbsp;&nbsp;&nbsp; 作用是尝试各种可能的执行计划，选择 cost 最低的一种。<BR>&nbsp;&nbsp;&nbsp; Plan Generator 会先为 nested subqueries and nonmerged views 产生 subplans，并且从 innermost query block 开始往外优化。<BR>&nbsp;&nbsp;&nbsp; Plan Generator 会使用 internal cutoff 来减少 plan 的尝试数量。internal cutoff 基于现有的最优计划的 cost。如果很大，那么会尝试较多的计划；如果很小，那么会很快结束尝试。<BR>&nbsp;&nbsp;&nbsp; 如果 plan generator 从一个接近最优的 initial join order 开始，那么 internal cutoff 可以很好的工作。Plan Generator 根据 join items 的 effective cardinality 来确定 initial join order，小的在前面，大的在后面。</P>
<P><STRONG>Understanding Execution Plans</STRONG><BR><STRONG>&nbsp; Execution Plan：</STRONG><BR>&nbsp; 为了执行 SQL 语句，Oracle 会执行很多步骤，这些步骤的综合叫做 execution plan，包括 access path 和 join order。</P>
<P><BR><STRONG>Understanding Access Paths for the CBO</STRONG><BR>&nbsp; <STRONG>Access paths：</STRONG><BR>&nbsp;&nbsp;&nbsp; 从数据库获得数据的方式。<BR>&nbsp; <BR>&nbsp; <STRONG>Full Table Scans</STRONG><BR>&nbsp;&nbsp;&nbsp; 表中所有在 HWM 以下的 blocks 都被扫描一遍，确定符合 where 条件的行。<BR>&nbsp;&nbsp;&nbsp; 块的读取范围从 1 到 DB_FILE_MULTIBLOCK_READ_COUNT。Multiblock reads 可以提高执行效率，当访问表中大量块时 full table scans 比 index range scans 效率高。<BR>&nbsp;&nbsp;&nbsp; 优化器选择 Full Table Scans 的情况：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Lack of Index<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Large Amount of Data<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Small Table&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --大小表的区分由 _small_table_threshold 隐含参数决定，默认为 db_cache_size 的 2%。 <A href="http://www.eygle.com/archives/2006/05/oracle_long_short_table.html">http://www.eygle.com/archives/2006/05/oracle_long_short_table.html</A><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; High Degree of Parallelism <BR>&nbsp;&nbsp;&nbsp; Full Table Scan Hints：/*+ FULL(table alias) */<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>Rowid Scans</STRONG><BR>&nbsp;&nbsp;&nbsp; 获得一行数据的最快方法。<BR>&nbsp;&nbsp;&nbsp; 一般要先通过 index scan 获得 Rowid，如果需要的列不在 index 中，再进行 Rowid Scans 获得相应的行，如果在 index 中，则不需要 Rowid Scans。<BR>&nbsp; <BR>&nbsp; <STRONG>Index Scans</STRONG><BR>&nbsp;&nbsp;&nbsp; Index Unique Scans <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最多返回一个 rowid，用于 Unique Index 且 index cols 在条件中使用“等于”。<BR>&nbsp;&nbsp;&nbsp; Index Range Scans <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回的数据按照 index columns 升序排列，index column 为同一个值的多行按照行 rowid 的升序排列。如果 order by/group by 的顺序和 Index Range Scans 返回的 row set 的顺序相同就不需要再 sort 了，否则还需要再对 row set 进行 sort。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Unique index 中的 &lt; &gt; 条件，以及 nonunique indexe 的 &lt; = &gt; 条件，都会引起 Index Range Scans。如果进行 wild-card searches，% 不能放最前面，否则不会进行 Index Range Scans。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果某列上有索引，该列有 skewed distribution，且具有 histograms，但当时用 bind variable 时，Oracle 不知道该变量具体是什么值，而无法使用 histograms，导致选择 full table scan，这种情况下可以通过使用 hints 进行调整。<BR>&nbsp;&nbsp;&nbsp; Index Range Scans Descending <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 和 Index Range Scans 相同，只是用于降序返回结果，或者返回小于某特定值的结果。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HINT：INDEX_DESC(table_alias index_name)<BR>&nbsp;&nbsp;&nbsp; Index Skip Scans <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于前导列没有出现在查询中（skiped）时使用索引。它将 composite index 拆分成若干个小的逻辑子索引。子索引的个数由前导列的 distinct 值决定。适用于前导列 distinct 值很少（子索引就少了），非前导列 distinct 值很多的情况。<BR>&nbsp;&nbsp;&nbsp; Full Scans <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 适用于：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.A predicate references one of the columns in the index. The predicate does not need to be an index driver. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.No predicate，并且：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A.查询中引用的列都在 index 中<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B.只少有一个索引列不为空。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它是先定位到索引的 root block，然后到 branch block（如果有的话），再定位到第一个 leaf block，然后根据 leaf block 的双向链表顺序读取。它所读取的块都是有顺序的，也是经过排序的。<BR>&nbsp;&nbsp;&nbsp; Fast Full Index Scans <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 和 Full Scans 适用于：查询的所有列都在索引中出现，且至少有一个索引列具有 NOT NULL 约束。区别在于 它是从段头开始，读取包含位图块，root block，所有的branch block，leaf block，读取的顺序完全有物理存储位置决定，并采取多块读，没次读取db_file_multiblock_read_count个块。（更详细的说明参见汪海的《Index Full Scan vs Index Fast Full Scan 》 <A href="http://www.dbanotes.net/Oracle/Index_full_scan_vs_index_fast_full_scan.htm">http://www.dbanotes.net/Oracle/Index_full_scan_vs_index_fast_full_scan.htm</A>）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Fast Full Index Scans 可以利用多块读和并行读，只能用于 CBO，不能在 bitmap indexes 上使用。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当需要排序时，Oracle 会使用 Full Index Scans，因为他的结果已经排好序；当不排序时，会使用 Fast Full Index Scans，因为能使用多块读，速度更快。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在 rebuild index 时使用的就是 Fast Full Index Scans，所以 rebuild index 需要排序。（参见汪海的 《Rebuild Index与 Sort》<A href="http://www.dbanotes.net/Oracle/Rebuild_Index_vs_Sort.htm">http://www.dbanotes.net/Oracle/Rebuild_Index_vs_Sort.htm</A>）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HINT：INDEX_FFS(table_alias index_name)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Fast Full Index Scan 限制：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 索引列中至少有一列有 NOT NULL 约束<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果要用并行 fast full index scan 必须在创建索引时单独指定 parallel clause，不能从索引所在的表上继承<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须分析索引，否则优化器可能不会使用它<BR>&nbsp;&nbsp;&nbsp; Index Joins <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 他是一个有若干个 indexes 组成的 hash join，包含查询中需要的所有列。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 他无法 eliminate a sort operation，必须在 CBO 中使用。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HINT：INDEX_JOIN<BR>&nbsp;&nbsp;&nbsp; Bitmap Joins <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A bitmap join uses a bitmap for key values and a mapping function that converts each bit position to a rowid. Bitmaps can efficiently merge indexes that correspond to several conditions in a WHERE clause, using Boolean operations to resolve AND and OR conditions.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 只能使用于 CBO，且需要企业版。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>Cluster Scans<BR></STRONG>&nbsp;&nbsp;&nbsp; 用于从存放于 indexed cluster 中的表中获得相同 cluster key 值的数据。具有相同 cluster key 值的所有数据存放于同一个 BLOCK。通过扫描 cluster index 获得相应的 rowid，再通过 rowid 定位到所需的行。</P>
<P>&nbsp; <STRONG>Hash Scans</STRONG><BR>&nbsp;&nbsp;&nbsp; 用于从存放于 hash cluster 中的表中获得相同 hash value 值的数据。具有相同 hash value 值的所有数据存放于同一个 BLOCK。通过将 hash function 应用于 cluster key 值上，获得 hash value，再通过 hash value 定位到所需的行上。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>Sample Table Scans</STRONG><BR>&nbsp;&nbsp;&nbsp; 从表中获得 a random sample of data。<BR>&nbsp;&nbsp;&nbsp; SAMPLE clause：从表中随机获得指定百分比的行数据。<BR>&nbsp;&nbsp;&nbsp; SAMPLE BLOCK clause：从表中随机获得指定百分比的块数据。<BR>&nbsp;&nbsp;&nbsp; 限制：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 查询不能包含 a join or a remote table<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 需要使用 CBO<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>How the CBO Chooses an Access Path</STRONG><BR>&nbsp;&nbsp;&nbsp; 1.语句所有可用的 access paths<BR>&nbsp;&nbsp;&nbsp; 2.使用每种 access paths 或者 combination of paths 时，估计的 cost 值<BR>&nbsp;&nbsp;&nbsp; 影响 CBO 的因素：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.Optimizer Hints<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hints 会覆盖可用的 access paths，除非包含 SAMPLE or SAMPLE BLOCK<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.Old Statistics<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 影响 cost 的估计<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR><STRONG>Understanding Joins</STRONG><BR>&nbsp; <STRONG>How the CBO Executes Join Statements</STRONG><BR>&nbsp;&nbsp;&nbsp; 决定一下几个参数：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Access Paths<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Join Method（nested loop, sort merge, cartesian, and hash joins）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Join Order<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>How the CBO Chooses the Join Method</STRONG><BR>&nbsp;&nbsp;&nbsp; 估计每个 join method 的 cost，选择 cost 最少的那种 join method。<BR>&nbsp;&nbsp;&nbsp; 如果 join 返回大量行（一般来说，大于 10000 行），考虑以下因素：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.nested loop join&nbsp; 是低效的，优化器不会使用它<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nested loop join cost= access cost of A + (access cost of B * number of rows from A)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.CBO 中，hash join 是最高效的<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hash join cost= (access cost of A * number of hash partitions of B) + access cost of B<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.RBO 中，merge join 是最高效的<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; merge join cost= access cost of A + access cost of B +(sort cost of A + sort cost of B)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （如果数据是预先排序好的，sort cost 为 0）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>How the CBO Chooses Execution Plans for Join Types</STRONG><BR>&nbsp;&nbsp;&nbsp; CBO，RBO 都适用的：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.优化器通过 UNIQUE and PRIMARY KEY 约束找到最多返回一行的表，如果这样的表存在，就把它放在连接顺序的第一位，再处理连接中的其他表。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.For join statements with outer join conditions, the table with the outer join operator must come after the other table in the condition in the join order. The optimizer does not consider join orders that violate this rule. <BR>&nbsp;&nbsp;&nbsp; CBO：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 估计各种 join orders, join methods, and available access paths 的 cost，选择 cost 最低的<BR>&nbsp;&nbsp;&nbsp; 其他因素：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.较小的 sort area size 会增加 sort merge join 的 cost，因为需要更多的 CPU time and I/O<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.较大的多块读相对于 nested loop join 来说，会减少 sort merge join 的 cost。<BR>&nbsp;&nbsp;&nbsp; CBO 中 join orders 的选择会被 ORDERED hint 覆盖，但如果 HINT 和 outer join 的规则冲突，那么 HINT 会被忽略。</P>
<P>&nbsp; <STRONG>Nested Loop Joins</STRONG><BR>&nbsp;&nbsp;&nbsp; 当 small subsets of data 被连接，并且 join condition 对于 inner table 来说是一种高效的访问方式时，nested loop joins 是非常有用的。<BR>&nbsp;&nbsp;&nbsp; 必须保证 inner table is driven from (dependent on) the outer table，否则性能很差，这种情况适用 hash joins 更好。<BR>&nbsp;&nbsp;&nbsp; HINT：USE_NL(table1_alias table2_alias) <BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>Hash Joins</STRONG><BR>&nbsp;&nbsp;&nbsp; Hash joins 适用于连接 large data sets。优化器选择较小的 data source 通过 join key 建立一个 hash table 存放在内存中。通过扫描大表，查询 hash table 找到所需的数据。<BR>&nbsp;&nbsp;&nbsp; 当 hash table 太大无法放到内存中，他会被拆分，一部分放到 temporary segments 中，这时 temporary extent sizes 影响 I/O 性能。这种情况下，性能很差。<BR>&nbsp;&nbsp;&nbsp; 当连接使用 equijoin，并且以下任何一种情况下，会使用 hash join：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. A large amount of data needs to be joined. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. A large fraction of the table needs to be joined. <BR>&nbsp;&nbsp;&nbsp; Execution Expain 中在上面的是先被扫描的小表，用作建立 hash table，在下的是大表。<BR>&nbsp;&nbsp;&nbsp; HINT：USE_HASH(table1_alias table2_alias) <BR>&nbsp;&nbsp;&nbsp; 当使用 Hash Joins 时碰到问题时，应该注意 HASH_AREA_SIZE and HASH_JOIN_ENABLED 参数。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>Sort Merge Joins</STRONG><BR>&nbsp;&nbsp;&nbsp; Sort Merge Join 没有驱动表的概念，他的执行步骤：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.Sort join operation: 两个表分别按照 join key 排序 （如果已经按照 join key 排序，这步省略）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.Merge join operation: 将排好序的结果 merge together. <BR>&nbsp;&nbsp;&nbsp; 性能比较：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sort Merge Join 适用于两个 independent sources。一般来说 Hash join 比 Sort Merge Join 性能好，除非以下两个条件同时满足<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.row sources 已经被排序<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.排序操作不需要再进行<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果 Sort Merge Join 选择了 slower access method，比如全表扫描，他的优势就失去了。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当两个表通过 &lt;, &lt;=, &gt;, or &gt;= 连接时，Sort merge join 是很有用的，在进行两个大 data sets 连接时，他比 nested loop join 性能好，hash join 适合用 = 连接。<BR>&nbsp;&nbsp;&nbsp; 当两个大数据量的 data sets 连接时，优化器何时选择 sort merge join 而不选择 hash join：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.连接条件不是 equi-join，而是 &lt;, &lt;=, &gt;, or &gt;= (but not a nonequality)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.OPTIMIZER_MODE is set to RULE，hash join 需要 CBO<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.HASH_JOIN_ENABLED is false. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.连接的表已经排好序<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.评估 HASH_AREA_SIZE and SORT_AREA_SIZE 大小之后，优化器认为 hash join 的 cost 较高<BR>&nbsp;&nbsp;&nbsp; HINT：USE_MERGE(table1_alias table2_alias) 可能还需要指定相应的 access path<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>Cartesian Joins</STRONG><BR>&nbsp;&nbsp;&nbsp; 当两个表连接时，没有指定连接条件，就会导致 Cartesian Join，一般是由于 poor SQL 造成的。<BR>&nbsp;&nbsp;&nbsp; HINT：ORDERED，By specifying a table before its join table is specified, the optimizer does a Cartesian join.<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>Outer Joins</STRONG><BR>&nbsp;&nbsp;&nbsp; 返回一个表满足连接条件的所有行以及另一个表的全部或者部分行，不管这些行符不符合连接条件。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; Nested Loop Outer Joins<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回 outer (preserved) table 的所有行，即使 inner (optional) table 没有符合条件的行。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Nested Loop Outer Join 时，外部表永远是驱动表，不根据 cost 来决定哪个是驱动表。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在以下条件下，优化器选择 Nested Loop Outer Join<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.外部表驱动内部表是可能的<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.数据量小到使得 nested loop 效率较高<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; Hash Join Outer Joins<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当连接的表的数据量大到使用 hash join 效率更高，或者外部表无法驱动内部表时，优化器选择 Hash Join Outer Joins。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表的连接顺序也不按照 cost 来决定，外部表先进行处理，用它构建 hash table。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; Sort Merge Outer Joins<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当外表不能驱动内表，无法使用 hash join or nested loop joins 时，那么使用 Sort Merge Outer Joins。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于数据量或者表已经经过排序操作，使得 Sort Merge Outer Joins 效率更高时，优化器选择 Sort Merge Outer Joins。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; Full Outer Joins<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Left and right outer joins 的联合。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR><STRONG>Setting Cost-Based Optimizer Parameters</STRONG><BR>&nbsp; <STRONG>Enabling CBO Features</STRONG><BR>&nbsp;&nbsp;&nbsp; OPTIMIZER_FEATURES_ENABLE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后面跟版本号，设置 Oracle 允许哪些 CBO 相关的特征被使用，只允许被设置了的版本的 CBO 特征，其他的不允许，在升级版本之后，为了执行计划的稳定性和向后兼容可以使用，否则不需要设置。<BR>&nbsp;&nbsp;&nbsp; Peeking of User-Defined Bind Variables<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在第一次 invocation of a cursor 的时候，Oracle peeks at 用户定义绑定变量的值，来决定所有 where 条件的 selectivity，即使没有使用绑定变量。在这之后的 invocations of the cursor 就不用再 peek 了，cursor 被共享，即使绑定变量的值不同。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用绑定变量假设 cursor sharing 是故意的，并且假设不同的 invocations 使用相同的执行计划，如果没有使用相同的执行计划，那么绑定变量的使用可能不正确。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp; <STRONG>Controlling the Behavior of the CBO</STRONG><BR>&nbsp;&nbsp;&nbsp; CURSOR_SHARING<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将语句中的 literal values 转为绑定变量，提高 cursor sharing 并且影响语句的执行计划，生成的执行计划将基于绑定变量而不是 actual literal values。<BR>&nbsp;&nbsp;&nbsp; DB_FILE_MULTIBLOCK_READ_COUNT<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Full table scan or index fast full scan 时，一次 I/O 读取的块数。用于估计 full table scans and index fast full scans 的 cost。大的 DB_FILE_MULTIBLOCK_READ_COUNT 值使得 full table scans 的 cost 较低，从而选择 full table scans 而不是 index scan。<BR>&nbsp;&nbsp;&nbsp; HASH_AREA_SIZE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于 hash joins 的内存大小（bytes），越大 hash join 的 cost 越低。<BR>&nbsp;&nbsp;&nbsp; HASH_JOIN_ENABLED<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是否使用 hash joins<BR>&nbsp;&nbsp;&nbsp; OPTIMIZER_INDEX_CACHING<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 控制 an index probe in conjunction with a nested loop 的 cost。范围 0~100，表明索引块在 buffer cache 中的百分比。他影响优化器对 index caching for nested loops and IN-list iterators 的假设。100 表示 100% 的索引块在 buffer cache 中能找到，这将影响优化器对 an index probe or nested loop cost 的调整。<BR>&nbsp;&nbsp;&nbsp; OPTIMIZER_INDEX_COST_ADJ<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于调整 index probe 的 cost。范围 0~10000，默认值 100，表示 indexe 是基于 normal costing model 的 access path；如果设为 10，表示 index 的 cost 是一般 index access path 的 cost 的 1/10。<BR>&nbsp;&nbsp;&nbsp; OPTIMIZER_MAX_PERMUTATIONS<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于控制 CBO 对带有连接的 SQL 语句产生的执行计划数。范围 4 to 80000，80000 相当于无限。当将他设置成小于 1000 可以保证 parse times 降到几秒甚者更少。这个参数可以用来减少多表连接语句的 parse times，但是可能会丢失最优的执行计划。<BR>&nbsp;&nbsp;&nbsp; OPTIMIZER_MODE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 设置优化器的模式：RULE, CHOOSE, ALL_ROWS, FIRST_ROWS_n, and FIRST_ROWS<BR>&nbsp;&nbsp;&nbsp; PARTITION_VIEW_ENABLED<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是否使用 partition view pruning。如果设置成 true，CBO 只扫描需要的 partitions，根据 view predicates or filters。<BR>&nbsp;&nbsp;&nbsp; QUERY_REWRITE_ENABLED<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是否使用 query rewrite 的特性。Query rewrite 是和 materialized views 一起工作的。如果设置为 true，Oracle 会考虑使用 query rewrite 来查询 materialized views 而不是原始的大表（参见 D.C.B.A 对 query rewrite 的解释 <A href="http://www.anysql.net/2005/12/queryrewrite01.html">http://www.anysql.net/2005/12/queryrewrite01.html</A>）。另外该参数还用来控制是否使用 function-based indexes。<BR>&nbsp;&nbsp;&nbsp; SORT_AREA_SIZE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行 sort 所使用的内存大小（bytes）。如果 sort 的数据超过该值，那么超过的部分会放到 temporary tablespace 中。CBO 用该值估量 sort 的 cost，包括 sort merge joins。<BR>&nbsp;&nbsp;&nbsp; STAR_TRANSFORMATION_ENABLED<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This parameter, if set to true, enables the CBO to cost a star transformation for star queries. The star transformation combines the bitmap indexes on the various fact table columns rather than using a Cartesian approach.（D.C.B.A 对该功能的测试：<A href="http://www.anysql.net/2006/03/dw_star_transform.html">http://www.anysql.net/2006/03/dw_star_transform.html</A>）</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR><STRONG>Overview of the Extensible Optimizer</STRONG><BR>&nbsp; The extensible optimizer is part of the CBO. It allows the authors of user-defined functions and domain indexes to control the three main components that the CBO uses to select an execution plan: statistics, selectivity, and cost evaluation.</P>]]></description>
         <link>http://www.heysky.net/archives/2006/08/9iperformancetuningguide.html</link>
         <guid>http://www.heysky.net/archives/2006/08/9iperformancetuningguide.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Database</category>
        
                  <category domain="http://www.sixapart.com/ns/types#tag">Oracle</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">优化</category>
                  <category domain="http://www.sixapart.com/ns/types#tag">学习笔记</category>
        
         <pubDate>Fri, 04 Aug 2006 14:56:57 +0700</pubDate>
      </item>
      
   </channel>
</rss>
