<?xml version="1.0" encoding="gb2312"?>

<!-- RSS generated by oioj.net on 4/16/2004 ; 感谢LeXRus提供 RSS 2.0 文档; 此文件可自由使用，但请保留此行信息 --> 
<!-- Source download URL: http://blogger.org.cn/blog/rss2.asp       -->
<rss version="2.0">

<channel>
<title>blakestone的博客</title>
<link>http://blogger.org.cn/blog/blog.asp?name=blakestone</link>
<description>小许的博客</description>
<copyright>blogger.org.cn</copyright>
<generator>W3CHINA Blog</generator>
<webMaster>webmaster@blogger.org.cn</webMaster>
<item>
<title><![CDATA[海量数据库的查询优化及分页算法方案（2）]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=9403</link>
<author>blakestone</author>
<pubDate>2005/10/26 9:48:03</pubDate>
<description><![CDATA[
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 黑体">四、聚集索引的重要性和如何选择聚集索引</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">在上一节的标题中，笔者写的是：<B>实现小数据量和海量数据的通用分页显示存储过程。</B>这是因为在将本存储过程应用于“办公自动化”系统的实践中时，笔者发现这第三种存储过程在小数据量的情况下，有如下现象：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">1</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、分页速度一般维持在<SPAN lang=EN-US>1</SPAN>秒和<SPAN lang=EN-US>3</SPAN>秒之间。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">2</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、在查询最后一页时，速度一般为<SPAN lang=EN-US>5</SPAN>秒至<SPAN lang=EN-US>8</SPAN>秒，哪怕分页总数只有<SPAN lang=EN-US>3</SPAN>页或<SPAN lang=EN-US>30</SPAN>万页。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">虽然在超大容量情况下，这个分页的实现过程是很快的，但在分前几页时，这个<SPAN lang=EN-US>1</SPAN>－<SPAN lang=EN-US>3</SPAN>秒的速度比起第一种甚至没有经过优化的分页方法速度还要慢，借用户的话说就是“还没有<SPAN lang=EN-US>ACCESS</SPAN>数据库速度快”，这个认识足以导致用户放弃使用您开发的系统。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">笔者就此分析了一下，原来产生这种现象的症结是如此的简单，但又如此的重要：<B>排序的字段不是聚集索引！</B></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">本篇文章的题目是：“查询优化及分页算法方案”。笔者只所以把“查询优化”和“分页算法”这两个联系不是很大的论题放在一起，就是因为二者都需要一个非常重要的东西</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 宋体">――</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">聚集索引。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">在前面的讨论中我们已经提到了，聚集索引有两个最大的优势：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.15pt"><B><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">1</SPAN></B><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、以最快的速度缩小查询范围。</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.15pt"><B><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">2</SPAN></B><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、以最快的速度进行字段排序。</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">第<SPAN lang=EN-US>1</SPAN>条多用在查询优化时，而第<SPAN lang=EN-US>2</SPAN>条多用在进行分页时的数据排序。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">而聚集索引在每个表内又只能建立一个，这使得聚集索引显得更加的重要。聚集索引的挑选可以说是实现“查询优化”和“高效分页”的最关键因素。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">但要既使聚集索引列既符合查询列的需要，又符合排序列的需要，这通常是一个矛盾。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">笔者前面“索引”的讨论中，将<SPAN lang=EN-US>fariqi</SPAN>，即用户发文日期作为了聚集索引的起始列，日期的精确度为“日”。这种作法的优点，前面已经提到了，在进行划时间段的快速查询中，比用<SPAN lang=EN-US>ID</SPAN>主键列有很大的优势。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">但在分页时，由于这个聚集索引列存在着重复记录，所以无法使用<SPAN lang=EN-US>max</SPAN>或<SPAN lang=EN-US>min</SPAN>来最为分页的参照物，进而无法实现更为高效的排序。而如果将<SPAN lang=EN-US>ID</SPAN>主键列作为聚集索引，那么聚集索引除了用以排序之外，没有任何用处，实际上是浪费了聚集索引这个宝贵的资源。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">为解决这个矛盾，笔者后来又添加了一个日期列，其默认值为<SPAN lang=EN-US>getdate()</SPAN>。用户在写入记录时，这个列自动写入当时的时间，时间精确到毫秒。即使这样，为了避免可能性很小的重合，还要在此列上创建<SPAN lang=EN-US>UNIQUE</SPAN>约束。将此日期列作为聚集索引列。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">有了这个时间型聚集索引列之后，用户就既可以用这个列查找用户在插入数据时的某个时间段的查询，又可以作为唯一列来实现<SPAN lang=EN-US>max</SPAN>或<SPAN lang=EN-US>min</SPAN>，成为分页算法的参照物。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">经过这样的优化，笔者发现，无论是大数据量的情况下还是小数据量的情况下，分页速度一般都是几十毫秒，甚至<SPAN lang=EN-US>0</SPAN>毫秒。而用日期段缩小范围的查询速度比原来也没有任何迟钝。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">聚集索引是如此的重要和珍贵，所以笔者总结了一下，一定要将聚集索引建立在：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><B><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">1</SPAN></B><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、您最频繁使用的、用以缩小查询范围的字段上；</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><B><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">2</SPAN></B><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、您最频繁使用的、需要排序的字段上。</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">结束语：</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">本篇文章汇集了笔者近段在使用数据库方面的心得，是在做“办公自动化”系统时实践经验的积累。希望这篇文章不仅能够给大家的工作带来一定的帮助，也希望能让大家能够体会到分析问题的方法；最重要的是，希望这篇文章能够抛砖引玉，掀起大家的学习和讨论的兴趣，以共同促进，共同为公安科技强警事业和金盾工程做出自己最大的努力。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">最后需要说明的是，在试验中，我发现用户在进行大数据量查询的时候，对数据库速度影响最大的不是内存大小，而是<SPAN lang=EN-US>CPU</SPAN>。在我的<SPAN lang=EN-US>P4 2.4</SPAN>机器上试验的时候，查看“资源管理器”，<SPAN lang=EN-US>CPU</SPAN>经常出现持续到<SPAN lang=EN-US>100%</SPAN>的现象，而内存用量却并没有改变或者说没有大的改变。即使在我们的<SPAN lang=EN-US>HP ML 350 G3</SPAN>服务器上试验时，<SPAN lang=EN-US>CPU</SPAN>峰值也能达到<SPAN lang=EN-US>90%</SPAN>，一般持续在<SPAN lang=EN-US>70%</SPAN>左右。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">本文的试验数据都是来自我们的<SPAN lang=EN-US>HP ML 350</SPAN>服务器。服务器配置：双<SPAN lang=EN-US>Inter Xeon </SPAN>超线程<SPAN lang=EN-US> CPU 2.4G</SPAN>，内存<SPAN lang=EN-US>1G</SPAN>，操作系统<SPAN lang=EN-US>Windows Server 2003 Enterprise Edition</SPAN>，数据库<SPAN lang=EN-US>SQL Server 2000 SP3</SPAN>。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">大家可以访问以下公安网网址或互联网网址来体验一下我们的“千万级”数据库的办公自动化（<SPAN lang=EN-US>ASP.NET</SPAN>＋<SPAN lang=EN-US>C#</SPAN>语言）。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312"><A href="http://10.59.121.11:90/">http://10.59.121.11:90</A> </SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312"><A href="http://www.xx110.net/OA">http://www.xx110.net/OA</A></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 32.25pt; TEXT-ALIGN: right" align=right><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">微软<SPAN lang=EN-US>MCSE</SPAN>系统工程师</SPAN><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312"> </SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 32.25pt; TEXT-ALIGN: right" align=right><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">微软<SPAN lang=EN-US>MCDBA</SPAN>数据库工程师</SPAN><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312"> </SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt; TEXT-ALIGN: right" align=right><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">新乡市公安局通信科 党玉龙</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">参考文献：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">[1]</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">《<SPAN lang=EN-US>SQL SERVER 7</SPAN>编程技术内幕》，（美）<SPAN lang=EN-US>John Papa,Matthew Shepker</SPAN>著，机械工业出版社</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">[2]</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">《<SPAN lang=EN-US>SQL SERVER</SPAN>数据库原理 ——设计与实现》，微软亚洲研究院著，清华大学出版社</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">[3]</SPAN><SPAN lang=EN-US> </SPAN><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312"><A href="http://community.csdn.net/Expert/topic/2987/2987172.xml?temp=9.089297E-02">http://community.csdn.net/Expert/topic/2987/2987172.xml?temp=9.089297E-02</A></SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">，邹建，<SPAN lang=EN-US>CSDN</SPAN>论坛 </SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">[4]</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">互联网</SPAN></P><BR><BR>本文引用通告地址： http://blog.csdn.net/fengyun14/services/trackbacks/143223.aspx <BR>]]></description>
</item><item>
<title><![CDATA[海量数据库的查询优化及分页算法方案（1）]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=9401</link>
<author>blakestone</author>
<pubDate>2005/10/26 9:42:28</pubDate>
<description><![CDATA[
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">随着“金盾工程”建设的逐步深入和公安信息化的高速发展，公安计算机应用系统被广泛应用在各警种、各部门。与此同时，应用系统体系的核心、系统数据的存放地</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 宋体">――</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">数据库也随着实际应用而急剧膨胀，一些大规模的系统，如人口系统的数据甚至超过了<SPAN lang=EN-US>1000</SPAN>万条，可谓海量。那么，如何实现快速地从这些超大容量的数据库中提取数据（查询）、分析、统计以及提取数据后进行数据分页已成为各地系统管理员和数据库管理员亟待解决的难题。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">在以下的文章中，我将以“办公自动化”系统为例，探讨如何在有着<SPAN lang=EN-US>1000</SPAN>万条数据的<SPAN lang=EN-US>MS SQL SERVER</SPAN>数据库中实现快速的数据提取和数据分页。以下代码说明了我们实例中数据库的“红头文件”一表的部分数据结构：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">CREATE TABLE [dbo].[TGongwen] (</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> --TGongwen</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">是红头文件表名</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> [Gid] [int] IDENTITY (1, 1) NOT NULL ,<BR>--</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">本表的<SPAN lang=EN-US>id</SPAN>号，也是主键</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> [title] [varchar] (80) COLLATE Chinese_PRC_CI_AS NULL ,</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> <BR>--</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">红头文件的标题</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> [fariqi] [datetime] NULL ,<BR>--</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">发布日期</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> [neibuYonghu] [varchar] (70) COLLATE Chinese_PRC_CI_AS NULL ,<BR>--</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">发布用户</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> [reader] [varchar] (900) COLLATE Chinese_PRC_CI_AS NULL ,</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">--</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">需要浏览的用户。每个用户中间用分隔符“<SPAN lang=EN-US>,</SPAN>”分开</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">GO</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">下面，我们来往数据库中添加<SPAN lang=EN-US>1000</SPAN>万条数据：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">declare @i int</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @i=1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">while @i&lt;=250000</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">begin</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-2-5','</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">通信科<SPAN lang=EN-US>','</SPAN>通信科<SPAN lang=EN-US>,</SPAN>办公室<SPAN lang=EN-US>,</SPAN>王局长<SPAN lang=EN-US>,</SPAN>刘局长<SPAN lang=EN-US>,</SPAN>张局长<SPAN lang=EN-US>,admin,</SPAN>刑侦支队<SPAN lang=EN-US>,</SPAN>特勤支队<SPAN lang=EN-US>,</SPAN>交巡警支队<SPAN lang=EN-US>,</SPAN>经侦支队<SPAN lang=EN-US>,</SPAN>户政科<SPAN lang=EN-US>,</SPAN>治安支队<SPAN lang=EN-US>,</SPAN>外事科<SPAN lang=EN-US>','</SPAN>这是最先的<SPAN lang=EN-US>25</SPAN>万条记录<SPAN lang=EN-US>')</SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> set @i=@i+1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">end</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">GO</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">declare @i int</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @i=1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">while @i&lt;=250000</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">begin</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-9-16','</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">办公室<SPAN lang=EN-US>','</SPAN>办公室<SPAN lang=EN-US>,</SPAN>通信科<SPAN lang=EN-US>,</SPAN>王局长<SPAN lang=EN-US>,</SPAN>刘局长<SPAN lang=EN-US>,</SPAN>张局长<SPAN lang=EN-US>,admin,</SPAN>刑侦支队<SPAN lang=EN-US>,</SPAN>特勤支队<SPAN lang=EN-US>,</SPAN>交巡警支队<SPAN lang=EN-US>,</SPAN>经侦支队<SPAN lang=EN-US>,</SPAN>户政科<SPAN lang=EN-US>,</SPAN>外事科<SPAN lang=EN-US>','</SPAN>这是中间的<SPAN lang=EN-US>25</SPAN>万条记录<SPAN lang=EN-US>')</SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> set @i=@i+1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">end</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">GO</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">declare @h int</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @h=1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">while @h&lt;=100</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">begin</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 28pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">declare @i int</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 28pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @i=2002</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 28pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">while @i&lt;=2003</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 28pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">begin</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 56pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">declare @j int</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> set @j=0</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> while @j&lt;50</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> begin</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 84pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">declare @k int</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> </SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @k=0</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> </SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">while @k&lt;50</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> begin</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> insert into Tgongwen(fariqi,neibuyonghu,reader,title) values(cast(@i as varchar(4))+'-8-15 3:'+cast(@j as varchar(2))+':'+cast(@j as varchar(2)),'</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">通信科<SPAN lang=EN-US>','</SPAN>办公室<SPAN lang=EN-US>,</SPAN>通信科<SPAN lang=EN-US>,</SPAN>王局长<SPAN lang=EN-US>,</SPAN>刘局长<SPAN lang=EN-US>,</SPAN>张局长<SPAN lang=EN-US>,admin,</SPAN>刑侦支队<SPAN lang=EN-US>,</SPAN>特勤支队<SPAN lang=EN-US>,</SPAN>交巡警支队<SPAN lang=EN-US>,</SPAN>经侦支队<SPAN lang=EN-US>,</SPAN>户政科<SPAN lang=EN-US>,</SPAN>外事科<SPAN lang=EN-US>','</SPAN>这是最后的<SPAN lang=EN-US>50</SPAN>万条记录<SPAN lang=EN-US>')</SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> set @k=@k+1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> end</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 56pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @j=@j+1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> end</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 28pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @i=@i+1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 28pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">end</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @h=@h+1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">end</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">GO</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">declare @i int</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">set @i=1</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">while @i&lt;=9000000</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">begin</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-5-5','</SPAN><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">通信科<SPAN lang=EN-US>','</SPAN>通信科<SPAN lang=EN-US>,</SPAN>办公室<SPAN lang=EN-US>,</SPAN>王局长<SPAN lang=EN-US>,</SPAN>刘局长<SPAN lang=EN-US>,</SPAN>张局长<SPAN lang=EN-US>,admin,</SPAN>刑侦支队<SPAN lang=EN-US>,</SPAN>特勤支队<SPAN lang=EN-US>,</SPAN>交巡警支队<SPAN lang=EN-US>,</SPAN>经侦支队<SPAN lang=EN-US>,</SPAN>户政科<SPAN lang=EN-US>,</SPAN>治安支队<SPAN lang=EN-US>,</SPAN>外事科<SPAN lang=EN-US>','</SPAN>这是最后添加的<SPAN lang=EN-US>900</SPAN>万条记录<SPAN lang=EN-US>')</SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312">&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312"> set @i=@i+1000000</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">end</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">GO</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">通过以上语句，我们创建了<SPAN lang=EN-US>25</SPAN>万条由通信科于<SPAN lang=EN-US>2004</SPAN>年<SPAN lang=EN-US>2</SPAN>月<SPAN lang=EN-US>5</SPAN>日发布的记录，<SPAN lang=EN-US>25</SPAN>万条由办公室于<SPAN lang=EN-US>2004</SPAN>年<SPAN lang=EN-US>9</SPAN>月<SPAN lang=EN-US>6</SPAN>日发布的记录，<SPAN lang=EN-US>2002</SPAN>年和<SPAN lang=EN-US>2003</SPAN>年各<SPAN lang=EN-US>100</SPAN>个<SPAN lang=EN-US>2500</SPAN>条相同日期、不同分秒的由通信科发布的记录（共<SPAN lang=EN-US>50</SPAN>万条），还有由通信科于<SPAN lang=EN-US>2004</SPAN>年<SPAN lang=EN-US>5</SPAN>月<SPAN lang=EN-US>5</SPAN>日发布的<SPAN lang=EN-US>900</SPAN>万条记录，合计<SPAN lang=EN-US>1000</SPAN>万条。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; mso-fareast-font-family: 仿宋_GB2312; mso-ascii-font-family: 仿宋_GB2312"></SPAN>&nbsp;</P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 黑体">一、因情制宜，建立“适当”的索引</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">建立“适当”的索引是实现查询优化的首要前提。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">索引（<SPAN lang=EN-US>index</SPAN>）是除表之外另一重要的、用户定义的存储在物理介质上的数据结构。当根据索引码的值搜索数据时，索引提供了对数据的快速访问。事实上，没有索引<SPAN lang=EN-US>,</SPAN>数据库也能根据<SPAN lang=EN-US>SELECT</SPAN>语句成功地检索到结果，但随着表变得越来越大，使用“适当”的索引的效果就越来越明显。注意，在这句话中，我们用了“适当”这个词，这是因为，如果使用索引时不认真考虑其实现过程，索引既可以提高也会破坏数据库的工作性能。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（一）深入浅出理解索引结构</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">实际上，您可以把索引理解为一种特殊的目录。微软的<SPAN lang=EN-US>SQL SERVER</SPAN>提供了两种索引：聚集索引（<SPAN lang=EN-US>clustered index</SPAN>，也称聚类索引、簇集索引）和非聚集索引（<SPAN lang=EN-US>nonclustered index</SPAN>，也称非聚类索引、非簇集索引）。下面，我们举例来说明一下聚集索引和非聚集索引的区别：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 33pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">其实，我们的汉语字典的正文本身就是一个聚集索引。比如，我们要查“安”字，就会很自然地翻开字典的前几页，因为“安”的拼音是“<SPAN lang=EN-US>an</SPAN>”，而按照拼音排序汉字的字典是以英文字母“<SPAN lang=EN-US>a</SPAN>”开头并以“<SPAN lang=EN-US>z</SPAN>”结尾的，那么“安”字就自然地排在字典的前部。如果您翻完了所有以“<SPAN lang=EN-US>a</SPAN>”开头的部分仍然找不到这个字，那么就说明您的字典中没有这个字；同样的，如果查“张”字，那您也会将您的字典翻到最后部分，因为“张”的拼音是“<SPAN lang=EN-US>zhang</SPAN>”。也就是说，字典的正文部分本身就是一个目录，您不需要再去查其他目录来找到您需要找的内容。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 33pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">我们把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 33pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">如果您认识某个字，您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字，不知道它的发音，这时候，您就不能按照刚才的方法找到您要查的字，而需要去根据“偏旁部首”查到您要找的字，然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序并不是真正的正文的排序方法，比如您查“张”字，我们可以看到在查部首之后的检字表中“张”的页码是<SPAN lang=EN-US>672</SPAN>页，检字表中“张”的上面是“驰”字，但页码却是<SPAN lang=EN-US>63</SPAN>页，“张”的下面是“弩”字，页面是<SPAN lang=EN-US>390</SPAN>页。很显然，这些字并不是真正的分别位于“张”字的上下方，现在您看到的连续的“驰、张、弩”三字实际上就是他们在非聚集索引中的排序，是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字，但它需要两个过程，先找到目录中的结果，然后再翻到您所需要的页码。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 33pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">我们把这种目录纯粹是目录，正文纯粹是正文的排序方式称为“非聚集索引”。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 33pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">通过以上例子，我们可以理解到什么是“聚集索引”和“非聚集索引”。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 33pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">进一步引申一下，我们可以很容易的理解：每个表只能有一个聚集索引，因为目录只能按照一种方法进行排序。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 33pt"><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（二）何时使用聚集索引或非聚集索引</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 33pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">下面的表总结了何时使用聚集索引或非聚集索引（<B>很重要</B>）。</SPAN></P>
<TABLE class=MsoNormalTable style="BORDER-COLLAPSE: collapse; mso-padding-alt: 0cm 0cm 0cm 0cm" cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR style="mso-yfti-irow: 0; mso-yfti-firstrow: yes">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: black 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1.5pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><B><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">动作描述</SPAN></B></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: black 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1.5pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><B><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">使用聚集索引</SPAN></B></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: black 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1.5pt solid; BACKGROUND-COLOR: transparent" vAlign=top width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><B><SPAN style="FONT-SIZE: 14pt; FONT-FAMILY: 仿宋_GB2312">使用非聚集索引</SPAN></B></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 1">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">列经常被分组排序</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 2">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">返回某范围内的数据</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">不应</SPAN></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 3">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">一个或极少不同值</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">不应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">不应</SPAN></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 4">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">小数目的不同值</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">不应</SPAN></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 5">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">大数目的不同值</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">不应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 6">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">频繁更新的列</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">不应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 7">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">外键列</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 8">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">主键列</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD></TR>
<TR style="HEIGHT: 22.7pt; mso-yfti-irow: 9; mso-yfti-lastrow: yes">
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: black 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">频繁修改索引列</SPAN></P></TD>
<TD style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">不应</SPAN></P></TD>
<TD style="BORDER-RIGHT: black 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #d4d0c8; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: black 1pt solid; HEIGHT: 22.7pt; BACKGROUND-COLOR: transparent" width=189>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 仿宋_GB2312">应</SPAN></P></TD></TR></TBODY></TABLE>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">事实上，我们可以通过前面聚集索引和非聚集索引的定义的例子来理解上表。如：返回某范围内的数据一项。比如您的某个表有一个时间列，恰好您把聚合索引建立在了该列，这时您查询<SPAN lang=EN-US>2004</SPAN>年<SPAN lang=EN-US>1</SPAN>月<SPAN lang=EN-US>1</SPAN>日至<SPAN lang=EN-US>2004</SPAN>年<SPAN lang=EN-US>10</SPAN>月<SPAN lang=EN-US>1</SPAN>日之间的全部数据时，这个速度就将是很快的，因为您的这本字典正文是按日期进行排序的，聚类索引只需要找到要检索的所有数据中的开头和结尾数据即可；而不像非聚集索引，必须先查到目录中查到每一项数据对应的页码，然后再根据页码查到具体内容。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（三）结合实际，谈索引使用的误区</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">理论的目的是应用。虽然我们刚才列出了何时应使用聚集索引或非聚集索引，但在实践中以上规则却很容易被忽视或不能根据实际情况进行综合分析。下面我们将根据在实践中遇到的实际问题来谈一下索引使用的误区，以便于大家掌握索引建立的方法。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><B><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">1</SPAN></B><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、主键就是聚集索引</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">这种想法笔者认为是极端错误的，是对聚集索引的一种浪费。虽然<SPAN lang=EN-US>SQL SERVER</SPAN>默认是在主键上建立聚集索引的。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">通常，我们会在每个表中都建立一个<SPAN lang=EN-US>ID</SPAN>列，以区分每条数据，并且这个<SPAN lang=EN-US>ID</SPAN>列是自动增大的，步长一般为<SPAN lang=EN-US>1</SPAN>。我们的这个办公自动化的实例中的列<SPAN lang=EN-US>Gid</SPAN>就是如此。此时，如果我们将这个列设为主键，<SPAN lang=EN-US>SQL SERVER</SPAN>会将此列默认为聚集索引。这样做有好处，就是可以让您的数据在数据库中按照<SPAN lang=EN-US>ID</SPAN>进行物理排序，但笔者认为这样做意义不大。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">显而易见，聚集索引的优势是很明显的，而每个表中只能有一个聚集索引的规则，这使得聚集索引变得更加珍贵。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">从我们前面谈到的聚集索引的定义我们可以看出，使用聚集索引的最大好处就是能够根据查询要求，迅速缩小查询范围，避免全表扫描。在实际应用中，因为<SPAN lang=EN-US>ID</SPAN>号是自动生成的，我们并不知道每条记录的<SPAN lang=EN-US>ID</SPAN>号，所以我们很难在实践中用<SPAN lang=EN-US>ID</SPAN>号来进行查询。这就使让<SPAN lang=EN-US>ID</SPAN>号这个主键作为聚集索引成为一种资源浪费。其次，让每个<SPAN lang=EN-US>ID</SPAN>号都不同的字段作为聚集索引也不符合“大数目的不同值情况下不应建立聚合索引”规则；当然，这种情况只是针对用户经常修改记录内容，特别是索引项的时候会负作用，但对于查询速度并没有影响。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">在办公自动化系统中，无论是系统首页显示的需要用户签收的文件、会议还是用户进行文件查询等任何情况下进行数据查询都离不开字段的是“日期”还有用户本身的“用户名”。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">通常，办公自动化的首页会显示每个用户尚未签收的文件或会议。虽然我们的<SPAN lang=EN-US>where</SPAN>语句可以仅仅限制当前用户尚未签收的情况，但如果您的系统已建立了很长时间，并且数据量很大，那么，每次每个用户打开首页的时候都进行一次全表扫描，这样做意义是不大的，绝大多数的用户<SPAN lang=EN-US>1</SPAN>个月前的文件都已经浏览过了，这样做只能徒增数据库的开销而已。事实上，我们完全可以让用户打开系统首页时，数据库仅仅查询这个用户近<SPAN lang=EN-US>3</SPAN>个月来未阅览的文件，通过“日期”这个字段来限制表扫描，提高查询速度。如果您的办公自动化系统已经建立的<SPAN lang=EN-US>2</SPAN>年，那么您的首页显示速度理论上将是原来速度<SPAN lang=EN-US>8</SPAN>倍，甚至更快。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">在这里之所以提到“理论上”三字，是因为如果您的聚集索引还是盲目地建在<SPAN lang=EN-US>ID</SPAN>这个主键上时，您的查询速度是没有这么高的，即使您在“日期”这个字段上建立的索引（非聚合索引）。下面我们就来看一下在<SPAN lang=EN-US>1000</SPAN>万条数据量的情况下各种查询的速度表现（<SPAN lang=EN-US>3</SPAN>个月内的数据为<SPAN lang=EN-US>25</SPAN>万条）：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（<SPAN lang=EN-US>1</SPAN>）仅在主键上建立聚集索引，并且不划分时间段：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">Select gid,fariqi,neibuyonghu,title from tgongwen</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">用时：<SPAN lang=EN-US>128470</SPAN>毫秒（即：<SPAN lang=EN-US>128</SPAN>秒）</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（<SPAN lang=EN-US>2</SPAN>）在主键上建立聚集索引，在<SPAN lang=EN-US>fariq</SPAN>上建立非聚集索引：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">select gid,fariqi,neibuyonghu,title from Tgongwen</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">where fariqi&gt; dateadd(day,-90,getdate())</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">用时：<SPAN lang=EN-US>53763</SPAN>毫秒（<SPAN lang=EN-US>54</SPAN>秒）</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（<SPAN lang=EN-US>3</SPAN>）将聚合索引建立在日期列（<SPAN lang=EN-US>fariqi</SPAN>）上：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">select gid,fariqi,neibuyonghu,title from Tgongwen</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">where fariqi&gt; dateadd(day,-90,getdate())</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">用时：<SPAN lang=EN-US>2423</SPAN>毫秒（<SPAN lang=EN-US>2</SPAN>秒）</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">虽然每条语句提取出来的都是<SPAN lang=EN-US>25</SPAN>万条数据，各种情况的差异却是巨大的，特别是将聚集索引建立在日期列时的差异。事实上，如果您的数据库真的有<SPAN lang=EN-US>1000</SPAN>万容量的话，把主键建立在<SPAN lang=EN-US>ID</SPAN>列上，就像以上的第<SPAN lang=EN-US>1</SPAN>、<SPAN lang=EN-US>2</SPAN>种情况，在网页上的表现就是超时，根本就无法显示。这也是我摒弃<SPAN lang=EN-US>ID</SPAN>列作为聚集索引的一个最重要的因素。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 31.9pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">得出以上速度的方法是：在各个<SPAN lang=EN-US>select</SPAN>语句前加：<SPAN lang=EN-US>declare @d datetime</SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">set @d=getdate()</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">并在<SPAN lang=EN-US>select</SPAN>语句后加：</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">select [</SPAN><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">语句执行花费时间<SPAN lang=EN-US>(</SPAN>毫秒<SPAN lang=EN-US>)]=datediff(ms,@d,getdate())</SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><B><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">2</SPAN></B><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、只要建立索引就能显著提高查询速度</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">事实上，我们可以发现上面的例子中，第<SPAN lang=EN-US>2</SPAN>、<SPAN lang=EN-US>3</SPAN>条语句完全相同，且建立索引的字段也相同；不同的仅是前者在<SPAN lang=EN-US>fariqi</SPAN>字段上建立的是非聚合索引，后者在此字段上建立的是聚合索引，但查询速度却有着天壤之别。所以，并非是在任何字段上简单地建立索引就能提高查询速度。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">从建表的语句中，我们可以看到这个有着<SPAN lang=EN-US>1000</SPAN>万数据的表中<SPAN lang=EN-US>fariqi</SPAN>字段有<SPAN lang=EN-US>5003</SPAN>个不同记录。在此字段上建立聚合索引是再合适不过了。在现实中，我们每天都会发几个文件，这几个文件的发文日期就相同，这完全符合建立聚集索引要求的：“既不能绝大多数都相同，又不能只有极少数相同”的规则。由此看来，我们建立“适当”的聚合索引对于我们提高查询速度是非常重要的。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><B><SPAN lang=EN-US style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">3</SPAN></B><B><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">、把所有需要提高查询速度的字段都加进聚集索引，以提高查询速度</SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">上面已经谈到：在进行数据查询时都离不开字段的是“日期”还有用户本身的“用户名”。既然这两个字段都是如此的重要，我们可以把他们合并起来，建立一个复合索引（<SPAN lang=EN-US>compound index</SPAN>）。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">很多人认为只要把任何字段加进聚集索引，就能提高查询速度，也有人感到迷惑：如果把复合的聚集索引字段分开查询，那么查询速度会减慢吗？带着这个问题，我们来看一下以下的查询速度（结果集都是<SPAN lang=EN-US>25</SPAN>万条数据）：（日期列<SPAN lang=EN-US>fariqi</SPAN>首先排在复合聚集索引的起始列，用户名<SPAN lang=EN-US>neibuyonghu</SPAN>排在后列）</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（<SPAN lang=EN-US>1</SPAN>）<SPAN lang=EN-US>select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi&gt;'2004-5-5' </SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">查询速度：<SPAN lang=EN-US>2513</SPAN>毫秒</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（<SPAN lang=EN-US>2</SPAN>）<SPAN lang=EN-US>select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi&gt;'2004-5-5' and neibuyonghu='</SPAN>办公室<SPAN lang=EN-US>'</SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">查询速度：<SPAN lang=EN-US>2516</SPAN>毫秒</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">（<SPAN lang=EN-US>3</SPAN>）<SPAN lang=EN-US>select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu='</SPAN>办公室<SPAN lang=EN-US>'</SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">查询速度：<SPAN lang=EN-US>60280</SPAN>毫秒</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 32.25pt"><SPAN style="FONT-SIZE: 16pt; FONT-FAMILY: 仿宋_GB2312">从以上试验中，我们可以看到如果仅用聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一样的，甚至比用上全部的复合索引列还要略快（在查询结果集数目一样的情况下）；而如果仅用复合聚集索引的非起始列作为查询条件的话，这个索引是不起任何作用的。当然，语句<SPAN lang=EN-US>1</SPAN>、<SPAN lang=EN-US>2</SPAN>的查询速度一样是因为查询的条目数一样，如果复合索引的所有列都用上，而且查询结果少的话，这样就会形成“索引覆盖”，因而性能可以达到最优。同时，请记住：无论您是否经常使用聚合索引的其他列，但其前导列一定要是使用最频繁的列。</SPAN></P>]]></description>
</item><item>
<title><![CDATA[“一网两库”负责人李亦学]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8858</link>
<author>blakestone</author>
<pubDate>2005/9/28 21:00:07</pubDate>
<description><![CDATA[在著名的欧洲分子生物学实验室（EMBL），德国同事说：“李亦学，你是不可战胜的！”在国内生物信息学圈内，知心同行说：“李亦学是一个没有‘敌人’的人。”李亦学，就是上海研发公共服务平台之“一网两库”的项目负责人。&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;自信而善于合作——李亦学说，对于自己的长处，从来都“非常清醒”。现在的关键是，如何正确发挥，直到有一天，自己带领的团队在生物信息学的某一方面能够代表国家。&nbsp;&nbsp; <BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;带着自信飞翔&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;乌鲁木齐，海德堡，上海，三个相距甚远的城市记录着李亦学的人生轨迹。自小在新疆长大的他，至今仍保留着原来的饮食习惯，比如很爱吃羊肉。考大学时，数学出人意料地遭遇“滑铁卢”，李亦学不得不放弃心仪已久的数学专业，进了新疆大学改读物理。此时，李亦学没有失落，他告诉自己：“即便在别处，我也能拔尖，我有这个自信。”&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;信心一直把李亦学送到了海德堡。在这座“最美丽”的德国小城，李亦学迈进了世界顶尖科研机构——EMBL的大门，成为实验室中屈指可数的中国人。很快，在EMBL，李亦学成了“拼命三郎”。3个月试用期过去了，李亦学和EMBL简直一见倾心。在同事看来，没他不能解决的事儿；在老板眼中，有他就吃了“定心丸”。&nbsp;&nbsp; <BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一句话找到归属感&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;就在EMBL打算与他续签又一个5年合同时，李亦学做出了惊人的决定——回国！这是他出国前就定下的主意：做完博士后就回国。出于“海德堡情结”，李亦学在烟台和苏州，两座风景秀丽的城市，找好了落脚点，准备在其中一地“安度”中年。&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可命运指引他重新选择。那年秋天，李亦学应邀回国参加某生物信息学研讨会，期间，他碰到了时任中科院上海生命科学研究院副院长的赵国屏。这位与李亦学有着相似经历的过来人深深打动了他：“在中国做事不容易，但只要有耐心，还是能成功的。”这句话让李亦学找回了渴望已久的归属感。此刻，他已情定上海。&nbsp;&nbsp; <BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;愧疚与梦想同在&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;凭着一句君子协定，李亦学回来了，来到上海组建中科院上海生命科学研究院生物信息学中心。因为舍不得招聘会上那200元的摊位费，李亦学自当“猎头”，到人才市场上去转悠，看到满意的，便主动上前与他（她）闲聊。就这样，整整一天过去了，李亦学为中心“聊”回了4个兵。&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如今，当年的新兵成了元老，可待遇却远不及国外这一行当的高薪。“好好干吧，面包会有的。”面对年轻人，李亦学总是鼓励，可没人知道他内心的愧疚与压力。&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;同事们说，无论是清晨6点还是晚上10点，亦或是星光点点的子夜，李亦学都可能出现在上班路上。李亦学明白，不管对于上海还是中国，现在都是一个前所未有的机遇，如果不抓住这天赐良机，我们就再也不能怨天尤人，该怨的只能是自己。&nbsp;&nbsp; <BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;李亦学，49岁，德国海德堡大学理论物理博士，欧洲分子生物学实验室生物物理博士后。现任上海生物信息技术研究中心主任、国家高技术发展计划生物与现代农业领域主题专家组组长。&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2000年，刚刚回国的他在几乎没有完整生物信息学研究队伍的上海，一手创建了中科院上海生命科学研究院生物信息学中心，并通过协同合作，使上海生物信息学研究后来居上。2002年，他又联合沪上11家单位组建上海生物信息技术研究中心。短短2年，中心已成为国家生物信息技术研究的支撑基地。&nbsp;&nbsp; <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如今，他再次执起帅印，带领团队为上海科教兴市主战略搭建科技资源共享平台。3年内，这个被称为“一网两库”的公共服务平台将汇集科学仪器超过千台，构建8到10个领域数据中心、主体数据库和文献标准库，引进链接国内外公共数据库逾万个，培育3到5个市场化的科技条件资源、数据和信息服务供应商，年营业额将超千万元。]]></description>
</item><item>
<title><![CDATA[MockObjects的选择：EasyMock与JMock的比较]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8690</link>
<author>blakestone</author>
<pubDate>2005/9/19 9:48:20</pubDate>
<description><![CDATA[
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体">本文假设读者已经了解了</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">MockObjects</SPAN><SPAN style="FONT-FAMILY: 宋体">的使用目的和基本方式，不对</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">MockTest</SPAN><SPAN style="FONT-FAMILY: 宋体">之类的技术作过多解释。仅提醒一句：</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">“</SPAN><SPAN style="FONT-FAMILY: 宋体">不要测试你的</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">MockObjects”</SPAN><SPAN style="FONT-FAMILY: 宋体">。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体">本文作为一个评测结果的同时，也可以作为</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">EasyMock</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">的简短教程。他们本身都很易用，可惜带的示例过于复杂，都用了过多的模式。看过本文的例子，相信就可以从容的在项目中使用了。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">Java</SPAN><SPAN style="FONT-FAMILY: 宋体">中常用的</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">MockObjects</SPAN><SPAN style="FONT-FAMILY: 宋体">有</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">EasyMock</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">等。其中</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">EasyMock</SPAN><SPAN style="FONT-FAMILY: 宋体">开发较早，已经出了</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">1.1</SPAN><SPAN style="FONT-FAMILY: 宋体">版本，而</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">前几天才刚推出了</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">1.0 final</SPAN><SPAN style="FONT-FAMILY: 宋体">。作为刚成熟的小弟弟，</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">有什么竞争实力呢？</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体">本比较针对于以下几个方面，代码请见附件。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">1 </SPAN><SPAN style="FONT-FAMILY: 宋体">是否能够对具体类进行模拟（当然，对接口模拟是基本功能）</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">2 </SPAN><SPAN style="FONT-FAMILY: 宋体">是否能够对方法名，参数，返回值进行动态控制</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">3 </SPAN><SPAN style="FONT-FAMILY: 宋体">基本代码行数</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">4 </SPAN><SPAN style="FONT-FAMILY: 宋体">是否能够对具有构造参数的具体类模拟</SPAN></P>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="FONT-FAMILY: 宋体">现在比较开始了。首先制作若干测试文件，很简单。要模拟的有一个接口和一个具体类，叫做</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">TheInterfaceToMock</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">TheClassToMock</SPAN><SPAN style="FONT-FAMILY: 宋体">，另外，提供方法</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">SampleReturn sampleMethod(Parameter p);</SPAN><SPAN style="FONT-FAMILY: 宋体">以及同名无参数方法。</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="FONT-FAMILY: 宋体">第一个测试是针对</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">TheInterfaceToMock</SPAN><SPAN style="FONT-FAMILY: 宋体">，提供</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">ParameterImpl</SPAN><SPAN style="FONT-FAMILY: 宋体">和</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">SampleReturnImpl</SPAN><SPAN style="FONT-FAMILY: 宋体">作为期待的参数和返回值。</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">代码如下：</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">&nbsp;&nbsp; </SPAN></P>
<P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=568>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><B><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">public</SPAN></B><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <B><SPAN style="COLOR: #7f0055">class</SPAN></B> <SPAN style="COLOR: black">JMockUsage</SPAN> <B><SPAN style="COLOR: #7f0055">extends</SPAN></B> <SPAN style="COLOR: black">MockObjectTestCase</SPAN> <SPAN style="COLOR: black">{</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; <B><SPAN style="COLOR: #7f0055">public</SPAN></B> <B><SPAN style="COLOR: #7f0055">void</SPAN></B> <SPAN style="COLOR: black">testReturnValueWithParemeter(){</SPAN></SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">构造</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">Mock</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">控制器</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">Mock</SPAN> <SPAN style="COLOR: black">m</SPAN> <SPAN style="COLOR: black">=</SPAN> <B><SPAN style="COLOR: #7f0055">new</SPAN></B> <SPAN style="COLOR: black">Mock(TheInterfaceToMock.</SPAN><B><SPAN style="COLOR: #7f0055">class</SPAN></B><SPAN style="COLOR: black">);</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">这是要测试</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">MockObject</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">TheInterfaceToMock</SPAN> <SPAN style="COLOR: black">mock</SPAN> <SPAN style="COLOR: black">=</SPAN> <SPAN style="COLOR: black">(TheInterfaceToMock)</SPAN> <SPAN style="COLOR: black">m.proxy();</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">期待的返回值</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">SampleReturn</SPAN> <SPAN style="COLOR: black">sr</SPAN> <SPAN style="COLOR: black">=</SPAN> <B><SPAN style="COLOR: #7f0055">new</SPAN></B> <SPAN style="COLOR: black">SampleReturnImpl();</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">期待的参数</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">Parameter</SPAN> <SPAN style="COLOR: black">p</SPAN> <SPAN style="COLOR: black">=</SPAN> <B><SPAN style="COLOR: #7f0055">new</SPAN></B> <SPAN style="COLOR: black">ParameterImpl();</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"><SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">控制器，期待一次，方法</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">sampleMethod</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">，参数等于</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">p(equals)</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">，将返回</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">sr</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">m.expects(once()).method(</SPAN><SPAN style="COLOR: #2a00ff">"sampleMethod"</SPAN><SPAN style="COLOR: black">)</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 54pt; TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 'Courier New'">.with(eq(p)).will(returnValue(sr));</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">正式执行</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">mockobject</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">SampleReturn</SPAN> <SPAN style="COLOR: black">ret</SPAN> <SPAN style="COLOR: black">=</SPAN> <SPAN style="COLOR: black">mock.sampleMethod(</SPAN><B><SPAN style="COLOR: #7f0055">new</SPAN></B> <SPAN style="COLOR: black">ParameterImpl());</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">确定返回值是相同的</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">assertSame(sr,ret);</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">}</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"><SPAN style="COLOR: black"></SPAN></SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 'Courier New'">}</SPAN></P></TD></TR></TBODY></TABLE></P>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'"></SPAN>&nbsp;<SPAN style="FONT-FAMILY: 宋体">相同功能的</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">easyMcok</SPAN><SPAN style="FONT-FAMILY: 宋体">代码如下：</SPAN></P>
<P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=568>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><B><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">public</SPAN></B><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <B><SPAN style="COLOR: #7f0055">class</SPAN></B> <SPAN style="COLOR: black">EasyMockUsage</SPAN> <B><SPAN style="COLOR: #7f0055">extends</SPAN></B> <SPAN style="COLOR: black">TestCase</SPAN> <SPAN style="COLOR: black">{</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; <B><SPAN style="COLOR: #7f0055">public</SPAN></B> <B><SPAN style="COLOR: #7f0055">void</SPAN></B> <SPAN style="COLOR: black">testReturnValueWithParameter(){</SPAN></SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">构造</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">mock</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">控制器</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">MockControl</SPAN> <SPAN style="COLOR: black">control</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 54pt; TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;<SPAN style="COLOR: black">=</SPAN> <SPAN style="COLOR: black">MockControl.createControl(TheInterfaceToMock.</SPAN><B><SPAN style="COLOR: #7f0055">class</SPAN></B><SPAN style="COLOR: black">);</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">这是要测试的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">MockObject</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">TheInterfaceToMock</SPAN> <SPAN style="COLOR: black">mock</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 54pt; TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;<SPAN style="COLOR: black">=</SPAN> <SPAN style="COLOR: black">(TheInterfaceToMock)</SPAN> <SPAN style="COLOR: black">control.getMock();</SPAN> </SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">这是要返回的值</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'"> </SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">SampleReturn</SPAN> <SPAN style="COLOR: black">sr</SPAN> <SPAN style="COLOR: black">=</SPAN> <B><SPAN style="COLOR: #7f0055">new</SPAN></B> <SPAN style="COLOR: black">SampleReturnImpl();</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">这是要传入的参数</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">Parameter</SPAN> <SPAN style="COLOR: black">p</SPAN> <SPAN style="COLOR: black">=</SPAN> <B><SPAN style="COLOR: #7f0055">new</SPAN></B> <SPAN style="COLOR: black">ParameterImpl();</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"><SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">恢复到记录</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">(record)</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">状态</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">control.reset();</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">首先记录</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">sampleMethod</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">方法</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">mock.sampleMethod(p);</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">设定该方法的返回值</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">control.setReturnValue(sr);</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">切换状态为回复</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">(reply)</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">control.replay();</SPAN></SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">正式执行</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">mock object</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">的方法，明显的，参数值是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">equals</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">而不是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">same</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">SampleReturn</SPAN> <SPAN style="COLOR: black">ret</SPAN> <SPAN style="COLOR: black">=</SPAN> <SPAN style="COLOR: black">mock.sampleMethod(</SPAN><B><SPAN style="COLOR: #7f0055">new</SPAN></B> <SPAN style="COLOR: black">ParameterImpl());</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: #3f7f5f">// </SPAN></SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">确定返回值是需要的值</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">assertSame(sr,ret);</SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></P>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: black">}</SPAN></SPAN></P></TD></TR></TBODY></TABLE></P>
<P class=MsoNormal><SPAN style="FONT-FAMILY: 宋体">&nbsp;&nbsp;&nbsp; 从上面的代码可以看到，同样的功能，二者的行数相差</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">3</SPAN><SPAN style="FONT-FAMILY: 宋体">行。其主要原因，就是</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">easyMcok</SPAN><SPAN style="FONT-FAMILY: 宋体">的</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">Mock</SPAN><SPAN style="FONT-FAMILY: 宋体">机制是基于状态，首先是录制状态，记录下来待测的方法和参数，返回值等，然后切换为回复状态。而</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">没有切换这一步，直接将参数返回值用一句话写出来。确实是一句话：</SPAN><SPAN style="COLOR: #333399; FONT-FAMILY: 宋体">期待一次，方法</SPAN><SPAN lang=EN-US style="COLOR: #333399; FONT-FAMILY: 'Courier New'">sampleMethod</SPAN><SPAN style="COLOR: #333399; FONT-FAMILY: 宋体">，参数等于</SPAN><SPAN lang=EN-US style="COLOR: #333399; FONT-FAMILY: 'Courier New'">p(equals)</SPAN><SPAN style="COLOR: #333399; FONT-FAMILY: 宋体">，将返回</SPAN><SPAN lang=EN-US style="COLOR: #333399; FONT-FAMILY: 'Courier New'">sr</SPAN><SPAN style="FONT-FAMILY: 宋体">。其中的一些辅助函数，例如</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">returnValue,eq</SPAN><SPAN style="FONT-FAMILY: 宋体">等等，位于父类</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">MockTestCase</SPAN><SPAN style="FONT-FAMILY: 宋体">。</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><B><SPAN style="COLOR: #333399; FONT-FAMILY: 宋体">结论</SPAN></B><SPAN style="FONT-FAMILY: 宋体">：</SPAN></P>
<P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=568>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"></SPAN>&nbsp;<SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp; 1 </SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">如果不能提供</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">MockTestCase</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">作为父类，请使用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">EasyMock</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; 2 </SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">如果需要批量或动态生成测试，请使用更规则的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">jMock</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; 3 </SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">如果喜欢看起来行数少一些，请用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">jMock</SPAN></P>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; 4 </SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">如果对状态切换看不顺眼，请用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">Mock</SPAN></P></TD></TR></TBODY></TABLE></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="FONT-FAMILY: 宋体">下面进行具体类测试，<SPAN style="COLOR: black">一个共同的点是，二者均使用了</SPAN></SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">CGLIB</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">作为增强器，因此效率差别几乎没有。</SPAN><SPAN style="FONT-FAMILY: 宋体">将上面的测试稍稍修改，将</SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">TheInterfaceToMock</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">改为</SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">TheClassToMock</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">。发生了以下变化。</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">用</SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">，需要将</SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">import</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">替换为新的</SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">import</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">，代码中其他部分完全不变！</SPAN></P>
<P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=568>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">原来</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><B><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">import</SPAN></B><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <SPAN style="COLOR: black">org.jmock.Mock;</SPAN></SPAN></P>
<P class=MsoNormal><B><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">import</SPAN></B><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <SPAN style="COLOR: black">org.jmock.MockObjectTestCase;</SPAN></SPAN></P>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">改为：</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><B><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">import</SPAN></B><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <SPAN style="COLOR: black">org.jmock.cglib.Mock;</SPAN></SPAN></P>
<P class=MsoNormal><B><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">import</SPAN></B><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <SPAN style="COLOR: black">org.jmock.cglib.MockObjectTestCase;</SPAN></SPAN></P></TD></TR></TBODY></TABLE></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">这是个相当体贴的设计，保证了接口的一致性。对于一套</SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">API</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">来说，同样的类却有不同的使用方法是个噩梦。</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">用</SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">easyMock</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">，需要新增加一个</SPAN><SPAN lang=EN-US style="COLOR: black; FONT-FAMILY: 'Courier New'">import</SPAN><SPAN style="COLOR: black; FONT-FAMILY: 宋体">。并且修改一些声明的地方。</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; </SPAN></P>
<P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=568>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体">原来</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><B><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">import</SPAN></B><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <SPAN style="COLOR: black">org.easymock.MockControl;</SPAN></SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">增加</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><B><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #7f0055; FONT-FAMILY: 'Courier New'">import</SPAN></B><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <SPAN style="COLOR: black">org.easymock.classextension.MockClassControl;</SPAN></SPAN></P></TD></TR></TBODY></TABLE></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'"></SPAN>&nbsp;</P>
<P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR style="HEIGHT: 34.2pt">
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 34.2pt" vAlign=top width=568>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'"></SPAN>&nbsp;<SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 'Courier New'">// mock</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #3f7f5f; FONT-FAMILY: 宋体">控制器</SPAN></P>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 'Courier New'">MockControl</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"> <SPAN style="COLOR: black">control</SPAN> <SPAN style="COLOR: black">=</SPAN> <SPAN style="COLOR: black">MockClassControl.createControl(TheClassToMock.</SPAN><B><SPAN style="COLOR: #7f0055">class</SPAN></B><SPAN style="COLOR: black">);</SPAN></SPAN></P></TD></TR></TBODY></TABLE></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体">其他部分不需要变化。虽然这有些变化，但是变化带来了其他的好处，就是：<SPAN style="COLOR: #333399">能够支持带有构造参数的具体类</SPAN>，而</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">不支持。这对于大量使用了</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">PicoContainer</SPAN><SPAN style="FONT-FAMILY: 宋体">的代码来说不啻是一个福音。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><B><SPAN style="COLOR: #333399; FONT-FAMILY: 宋体">结论</SPAN></B><SPAN style="FONT-FAMILY: 宋体">：</SPAN></P>
<P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 426.1pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=568>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"></SPAN>&nbsp;</P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; 5 </SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">如果需要构造参数，只能使用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">easyMock</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; 6 </SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">如果喜欢用相同的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">API</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">操作并且不在乎构造参数，请用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">jMock</SPAN></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">&nbsp;&nbsp;&nbsp; 7 </SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">如果愿意等待下一版本的</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">提供构造参数支持，请用</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">jMock</SPAN></P>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'"></SPAN>&nbsp;</P></TD></TR></TBODY></TABLE></P>
<P class=MsoNormal style="TEXT-ALIGN: left" align=left><SPAN style="FONT-FAMILY: 宋体">参考比较表：</SPAN></P>
<P>
<TABLE class=MsoTableGrid style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 border=1>
<TBODY>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'"></SPAN>&nbsp;</P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">EasyMock</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">jMock</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">通过接口模拟</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">控制方法有效次数</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">定制参数匹配</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">不需要状态转换</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">否</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">具体类模拟</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'"> </SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">具体类可有构造参数</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">否</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">接口统一</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">否</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">条件代码在一行中完成</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">否</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">支持其他参数规则，如</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'">not</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">否</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR>
<TR>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 142pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">自验证</SPAN><SPAN lang=EN-US style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 'Courier New'"> verify()</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD>
<TD style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; BACKGROUND: #f3f3f3; PADDING-BOTTOM: 0cm; BORDER-LEFT: medium none; WIDTH: 142.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid" vAlign=top width=189>
<P class=MsoNormal><SPAN style="FONT-SIZE: 9pt; COLOR: #333399; FONT-FAMILY: 宋体">是</SPAN></P></TD></TR></TBODY></TABLE></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体">综上，我选择了</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">。不过想想看，</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">easyMock</SPAN><SPAN style="FONT-FAMILY: 宋体">用</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">3</SPAN><SPAN style="FONT-FAMILY: 宋体">个类实现了大多数常用功能，很不简单啊。而</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">，如果能够提供对</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">Constructor injection</SPAN><SPAN style="FONT-FAMILY: 宋体">的支持就完美了。遗憾。不过从设计上看，</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock</SPAN><SPAN style="FONT-FAMILY: 宋体">里的模式使用堪称典范，很好看哦。</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体"></SPAN><SPAN style="FONT-FAMILY: 宋体">下载地址：</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'"><A href="http://www.jmock.org/">http://www.jmock.org</A></SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'"><A href="http://www.easymock.org/">http://www.easymock.org</A></SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体">比较代码：</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'"><A href="http://icecloud.51.net/data/mockobjects.zip">http://icecloud.51.net/data/mockobjects.zip</A></SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN style="FONT-FAMILY: 宋体">需要：</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">JUnit3.8.1</SPAN><SPAN style="FONT-FAMILY: 宋体">，</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">Cglib2</SPAN><SPAN style="FONT-FAMILY: 宋体">，</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">jMock1.0</SPAN><SPAN style="FONT-FAMILY: 宋体">，</SPAN><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">EasyMock1.1</SPAN></P>
<P class=MsoNormal style="TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 'Courier New'">本技术贴的引用位置：<A href="http://cdown.net/info/10100.html">http://cdown.net/info/10100.html</A></SPAN></P>]]></description>
</item><item>
<title><![CDATA[ORACLE数据库管理员职责]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8570</link>
<author>blakestone</author>
<pubDate>2005/9/13 13:38:27</pubDate>
<description><![CDATA[ORACLE数据库管理员应按如下方式对ORACLE数据库系统做定期监控：&nbsp;&nbsp;<BR>(1). 每天对ORACLE数据库的运行状态,日志文件,备份情况,数据&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>库的空间使用情况,系统资源的使用情况进行检查,发现并解决&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>问题。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(2). 每周对数据库对象的空间扩展情况,数据的增长情况进行监控,对数据库做健康检查,对数据库对象的状态做检查。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(3). 每月对表和索引等进行Analyze,检查表空间碎片,寻找数据库&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>性能调整的机会,进行数据库性能调整,提出下一步空间管理&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>计划。对ORACLE数据库状态进行一次全面检查。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>每天的工作&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(1).确认所有的INSTANCE状态正常&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>登陆到所有数据库或例程,检测ORACLE后台进程:&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>$ps –ef|grep ora&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(2). 检查文件系统的使用（剩余空间）。如果文件系统的剩余空间小于20%，需删除不用的文件以释放空间。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>$df –k&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(3). 检查日志文件和trace文件记录alert和trace文件中的错误。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>连接到每个需管理的系统&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>? 使用’telnet’&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>? 对每个数据库,cd 到bdump目录,通常是$ORACLE_BASE/&lt;SID&gt;/bdump&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>? 使用 Unix ‘tail’命令来查看alert_&lt;SID&gt;.log文件&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>? 如果发现任何新的ORA- 错误,记录并解决&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(4). 检查数据库当日备份的有效性。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>对RMAN备份方式:&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>检查第三方备份工具的备份日志以确定备份是否成功&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>对EXPORT备份方式:&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>检查exp日志文件以确定备份是否成功&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>对其他备份方式:&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>检查相应的日志文件&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(5). 检查数据文件的状态记录状态不是“online”的数据文件，并做恢复。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>Select file_name from dba_data_files where status=’OFFLINE’&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(6). 检查表空间的使用情况&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT tablespace_name, max_m, count_blocks free_blk_cnt, sum_free_m,to_char(100*sum_free_m/sum_m, '99.99') || '%' AS pct_free&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM ( SELECT tablespace_name,sum(bytes)/1024/1024 AS sum_m FROM dba_data_files GROUP BY tablespace_name),&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>( SELECT tablespace_name AS fs_ts_name, max(bytes)/1024/1024 AS max_m, count(blocks) AS count_blocks, sum(bytes/1024/1024) AS sum_free_m FROM dba_free_space GROUP BY tablespace_name )&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE tablespace_name = fs_ts_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(7). 检查剩余表空间&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT tablespace_name, sum ( blocks ) as free_blk ,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>trunc ( sum ( bytes ) /(1024*1024) ) as free_m,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>max ( bytes ) / (1024) as big_chunk_k, count (*) as num_chunks&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_free_space GROUP BY tablespace_name;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(8). 监控数据库性能&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>运行bstat/estat生成系统报告&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>或者使用statspack收集统计数据&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(9). 检查数据库性能，记录数据库的cpu使用、IO、buffer命中率等等&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>使用vmstat,iostat,glance,top等命令&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(10). 日常出现问题的处理。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>每周的工作&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(1). 控数据库对象的空间扩展情况&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>根据本周每天的检查情况找到空间扩展很快的数据库对象,并采取相&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>应的措施&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 删除历史数据&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--- 扩表空间&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>alter tablespace &lt;name&gt; add datafile ‘&lt;file&gt;’ size &lt;size&gt;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--- 调整数据对象的存储参数&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>next extent&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>pct_increase&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(2). 监控数据量的增长情况&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>根据本周每天的检查情况找到记录数量增长很快的数据库对象,并采&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>取相应的措施&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 删除历史数据&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--- 扩表空间&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>alter tablespace &lt;name&gt; add datafile ‘&lt;file&gt;’ size &lt;size&gt;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(3). 系统健康检查&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>检查以下内容:&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>init&lt;sid&gt;.ora&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>controlfile&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>redo log file&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>archiving&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>sort area size&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>tablespace(system,temporary,tablespace fragment)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>datafiles(autoextend,location)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>object(number of extent,next extent,index)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>rollback segment&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>logging &amp;tracing(alert.log,max_dump_file_size,sqlnet)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(4). 检查无效的数据库对象&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT owner, object_name, object_type FROM dba_objects&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE status=’INVALID’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(5). 检查不起作用的约束&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT owner, constraint_name, table_name,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>constraint_type, status&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_constraints&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE status = 'DISABLED’ AND constraint_type = 'P'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(6). 检查无效的trigger&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT owner, trigger_name, table_name, status&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_triggers&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE status = 'DISABLED’&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>每月的工作&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(1). Analyze Tables/Indexes/Cluster&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>analyze table &lt;name&gt; estimate statistics sample 50 percent;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(2). 检查表空间碎片&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>根据本月每周的检查分析数据库碎片情况,找到相应的解决方法&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(3). 寻找数据库性能调整的机会&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>比较每天对数据库性能的监控报告,确定是否有必要对数据库性能进 行调整&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(4). 数据库性能调整&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>如有必要,进行性能调整&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(5). 提出下一步空间管理计划&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>根据每周的监控,提出空间管理的改进方法&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>Oracle DBA 日常管理&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>目的：这篇文档有很详细的资料记录着对一个甚至更多的ORACLE 数据库每天的，每月的，&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>每年的运行的状态的结果及检查的结果，在文档的附录中你将会看到所有检查，修改的SQL&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>和PL/SQL 代码。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>目录&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1.日常维护程序&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A． 检查已起的所有实例&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B． 查找一些新的警告日志&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>C． 检查DBSNMP 是否在运行&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>D． 检查数据库备份是否正确&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>E． 检查备份到磁带中的文件是否正确&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>F． 检查数据库的性能是否正常合理，是否有足够的空间和资源&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>G． 将文档日志复制到备份的数据库中&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>H． 要常看DBA 用户手册&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2.晚间维护程序&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A．收集VOLUMETRIC 的数据&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3.每周维护工作&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A． 查找那些破坏规则的OBJECT&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B． 查找是否有违反安全策略的问题&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>C． 查看错误地方的SQL*NET 日志&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>D． 将所有的警告日志存档&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>E． 经常访问供应商的主页&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>4.月维护程序&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A． 查看对数据库会产生危害的增长速度&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B． 回顾以前数据库优化性能的调整&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>C． 查看I/O 的屏颈问题&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>D． 回顾FRAGMENTATION&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>E． 将来的执行计划&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>F． 查看调整点和维护&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>5.附录&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A． 月维护过程&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B． 晚间维护过程&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>C． 周维护过程&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>6.参考文献&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>----------------------------------------------------------------&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>一．日维护过程&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A．查看所有的实例是否已起&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>确定数据库是可用的，把每个实例写入日志并且运行日报告或是运行测试&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>文件。当然有一些操作我们是希望它能自动运行的。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>可选择执行：用ORACLE 管理器中的‘PROBE’事件来查看&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B．查找新的警告日志文件&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 联接每一个操作管理系统&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. 使用‘TELNET’或是可比较程序&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3. 对每一个管理实例，经常的执行$ORACLE_BASE/&lt;SID&gt;/bdump 操&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>作，并使其能回退到控制数据库的SID。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>4. 在提示下，使用UNIX 中的‘TAIL’命令查看alert_&lt;SID&gt;.log，或是&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>用其他方式检查文件中最近时期的警告日志&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>5. 如果以前出现过的一些ORA_ERRORS 又出现，将它记录到数据库&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>恢复日志中并且仔细的研究它们，这个数据库恢复日志在〈FILE〉中&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>C．查看DBSNMP 的运行情况&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>检查每个被管理机器的‘DBSNMP’进程并将它们记录到日志中。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>在UNIX 中，在命令行中，键入ps –ef | grep dbsnmp,将回看到2 个&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>DBSNMP 进程在运行。如果没有，重启DBSNMP。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>D．查数据库备份是否成功&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>E．检查备份的磁带文档是否成功&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>F．检查对合理的性能来说是否有足够的资源&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 检查在表空间中有没有剩余空间。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>对每一个实例来说，检查在表空间中是否存在有剩余空间来满足当天&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>的预期的需要。当数据库中已有的数据是稳定的，数据日增长的平均&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>数也是可以计算出来，最小的剩余空间至少要能满足每天数据的增 长。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A） 运行‘FREE.SQL’来检查表空间的剩余空间。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B） 运行‘SPACE.SQL’来检查表空间中的剩余空间百分率&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. 检查回滚段&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>回滚段的状态一般是在线的，除了一些为复杂工作准备的专用 段，它一般状态是离线的。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>a) 每个数据库都有一个回滚段名字的列表。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>b) 你可以用V$ROLLSTAT 来查询在线或是离线的回滚段的现在状 态.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>c) 对于所有回滚段的存储参数及名字， 可用&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>DBA_ROLLBACK_SEGS 来查询。但是它不如V$ROLLSTAT 准确。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3. 识别出一些过分的增长&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>查看数据库中超出资源或是增长速度过大的段，这些段的存储参 数需要调整。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>a） 收集日数据大小的信息， 可以用&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>‘ANALYZE5PCT.SQL’。如果你收集的是每晚的信息， 则可跳过这一步。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>b） 检查当前的范围，可用‘NR.EXTENTS.SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>c） 查询当前表的大小信息。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>d） 查询当前索引大小的信息。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>e） 查询增长趋势。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>4. 确定空间的范围。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>如果范围空间对象的NEXT_EXTENT 比表空间所能提供的最大范&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>围还要大，那么这将影响数据库的运行。如果我们找到了这个目标，可&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>以用‘ALTER TABLESPACE COALESCE’调查它的位置，或加另外 的数据文件。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A）运行‘SPACEBOUND.SQL’。如果都是正常的，将不返回任何行。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>5. 回顾CPU，内存，网络，硬件资源论点的过程&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A）检查CPU的利用情况，进到x:.htm =&gt;system&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>metrics=&gt;CPU 利用页，CPU 的最大限度为400，当CPU 的占用保持&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>在350 以上有一段时间的话，我们就需要查看及研究出现的问题。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>G．将存档日志复制到备用数据库中&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>如果有一个备用数据库，将适当的存档日志复制到备用数据库的期望&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>位置，备用数据库中保存最近期的数据。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>H. 经常查阅DBA 用户手册&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>如果有可能的话，要广泛的阅读，包括DBA 手册，行业杂志，新闻 组或是邮件列表。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-------------------------------------------------------------&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>二．晚间维护过程&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>大部分的数据库产品将受益于每晚确定的检查进程的运行。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A. 收集VOLUMETRIC 数据&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 分析计划和收集数据&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>更准确的分析计算并保存结果。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>a） 如果你现在没有作这些的话，用‘MK VOLFACT.SQL’来创建测定体积的 表。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>b） 收集晚间数据大小的信息，用‘ANALYZE COMP.SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>c） 收集统计结果，用‘POP VOL.SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>d） 在空闲的时候检查数据，可能的话，每周或每个月进行。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>我是用MS EXCEL 和ODBC 的联接来检查数据和图表的增长&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-------------------------------------------------------------&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>三．每周维护过程&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A． 查找被破坏的目标&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 对于每个给定表空间的对象来说，NEXT_EXTENT 的大小是相同的，如&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>12/14/98，缺省的NEXT_EXTENT 的DATAHI 为1G，DATALO 为500MB，&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>INDEXES 为256MB。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A） 检查NEXT_EXTENT 的设置，可用‘NEXTEXT。SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B） 检查已有的EXTENTS，可用‘EXISTEXT。SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. 所有的表都应该有唯一的主键&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>a） 查看那些表没有主键，可用‘NO_PK.SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>b） 查找那些主键是没有发挥作用的，可用‘DIS_PK.SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>c） 所有作索引的主键都要是唯一的，可用‘ NONUPK。SQL’来检 查。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3. 所有的索引都要放到索引表空间中。运行‘MKREBUILD_IDX。SQL’&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>4. 不同的环境之间的计划应该是同样的，特别是测试环境和成品环境之间的 计划应该相同。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>a） 检查不同的2 个运行环境中的数据类型是否一致，可用&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>‘DATATYPE.SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>b） 在2 个不同的实例中寻找对象的不同点， 可用&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>‘OBJ_COORD.SQL’。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>c） 更好的做法是，使用一种工具，象寻求软件的计划管理器那样的 工具。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B． 查看是否有危害到安全策略的问题。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>C． 查看报错的SQL*NET 日志。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 客户端的日志。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. 服务器端的日志。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>D．.将所有的警告日志存档&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>E．.供应商的主页&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. ORACLE 供应商&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>http://www.oracle.com&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>http://technet.oracle.com&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>http://www.oracle.com/support&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>http://www.oramag.com&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. Quest Software&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>http://www.quests.com&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3. Sun Microsystems&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>http://www.sun.com&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>----------------------------------------------------------------&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>四．月维护过程&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A．查看对数据库会产生危害的增长速度&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 从以前的记录或报告中回顾段增长的变化以此来确定段增长带来危害&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B． 回顾以前数据库优化性能的调整&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 回顾一般ORACLE 数据库的调整点，比较以前的报告来确定有害的发展 趋势。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>C． 查看I/O 的屏颈问题&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 查看前期数据库文件的活动性，比较以前的输出来判断有可能导致屏颈 问题的趋势。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>D． 回顾FRAGMENTATION&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>E． 计划数据库将来的性能&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. 比较ORACLE 和操作系统的CPU，内存，网络，及硬盘的利用率以此&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>来确定在近期将会有的一些资源争夺的趋势&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. 当系统将超出范围时要把性能趋势当作服务水平的协议来看&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>F． 完成调整和维护工作&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1.使修改满足避免系统资源的争夺的需要，这里面包括增加新资源或使预期 的停工。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>----------------------------------------------------------------&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>五．附录&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>A. 日常程序&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- free.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--To verify free space in tablespaces&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--Minimum amount of free space&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--document your thresholds:&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&lt;tablespace_name&gt; = &lt;amount&gt; m&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT tablespace_name, sum ( blocks ) as free_blk , trunc ( sum ( bytes ) /&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>(1024*1024) ) as free_m, max ( bytes ) / (1024) as big_chunk_k, count (*) as num_chunks&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_free_space GROUP BY tablespace_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. Space.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- space.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To check free, pct_free, and allocated space within a tablespace&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/24/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT tablespace_name, largest_free_chunk&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, nr_free_chunks, sum_alloc_blocks, sum_free_blocks&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, to_char(100*sum_free_blocks/sum_alloc_blocks, '09.99') || '%'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AS pct_free&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM ( SELECT tablespace_name , sum(blocks) AS sum_alloc_blocks&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_data_files GROUP BY tablespace_name )&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, ( SELECT tablespace_name AS fs_ts_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, max(blocks) AS largest_free_chunk&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, count(blocks) AS nr_free_chunks&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, sum(blocks) AS sum_free_blocks FROM dba_free_space&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>GROUP BY tablespace_name ) WHERE tablespace_name = fs_ts_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. analyze5pct.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- analyze5pct.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To analyze tables and indexes quickly, using a 5% sample size&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- (do not use this script if you are performing the overnight&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- collection of volumetric data)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/30/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>BEGIN&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>dbms_utility.analyze_schema ( '[$OWNER', 'ESTIMATE', NULL, 5 ) ]&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>END ;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>/&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3. nr_extents.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- nr_extents.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To find out any object reaching &lt;threshold&gt;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- extents, and manually upgrade it to allow unlimited&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- max_extents (thus only objects we *expect* to be big&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- are allowed to become big)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/30/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT e.owner, e.segment_type , e.segment_name , count(*) as nr_extents ,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>s.max_extents&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, to_char ( sum ( e.bytes ) / ( 1024 * 1024 ) , '999,999.90') as MB&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_extents e , dba_segments s&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE e.segment_name = s.segment_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>GROUP BY e.owner, e.segment_type , e.segment_name , s.max_extents&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>HAVING count(*) &gt; &amp;THRESHOLD&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>OR ( ( s.max_extents - count(*) ) &lt; &amp;&amp;THRESHOLD )&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>ORDER BY count(*) desc&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>4. spacebound.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- spacebound.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To identify space-bound objects. If all is well, no rows are returned.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- If any space-bound objects are found, look at value of NEXT extent&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- size to figure out what happened.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- Then use coalesce (alter tablespace &lt;foo&gt; coalesce .&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- Lastly, add another datafile to the tablespace if needed.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/30/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT a.table_name, a.next_extent, a.tablespace_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_tables a,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>( SELECT tablespace_name, max(bytes) as big_chunk&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_free_space&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>GROUP BY tablespace_name ) f&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE f.tablespace_name = a.tablespace_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AND a.next_extent &gt; f.big_chunk&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>B. 每晚处理程序&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. mk_volfact.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- mk_volfact.sql (only run this once to set it up; do not run it nightly!)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- -- Table UTL_VOL_FACTS&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>CREATE TABLE utl_vol_facts (&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>table_name VARCHAR2(30),&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>num_rows NUMBER,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>meas_dt DATE )&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>TABLESPACE platab&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>STORAGE (&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>INITIAL 128k&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>NEXT 128k&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>PCTINCREASE 0&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>MINEXTENTS 1&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>MAXEXTENTS unlimited&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>/&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- Public Synonym&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>CREATE PUBLIC SYNONYM utl_vol_facts FOR &amp;OWNER..utl_vol_facts&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>/&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- Grants for UTL_VOL_FACTS&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>GRANT SELECT ON utl_vol_facts TO public&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>/&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. analyze_comp.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- analyze_comp.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>BEGIN&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>sys.dbms_utility.analyze_schema ( '[$OWNER','COMPUTE')]&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>END ;&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>/&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3. pop_vol.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- pop_vol.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>insert into utl_vol_facts&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>select table_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, NVL ( num_rows, 0) as num_rows&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, trunc ( last_analyzed ) as meas_dt&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>from all_tables -- or just user_tables&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>where owner in ('&amp;OWNER') -- or a comma-separated list of owners&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>/&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>commit&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>/ <BR>&nbsp;&nbsp;<BR>　 <BR>&nbsp;&nbsp;<BR>C. 每周处理程序&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. nextext.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- nextext.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To find tables that don't match the tablespace default for NEXT extent.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- The implicit rule here is that every table in a given tablespace should&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- use the exact same value for NEXT, which should also be the tablespace's&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- default value for NEXT.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- This tells us what the setting for NEXT is for these objects today.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/30/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT segment_name, segment_type, ds.next_extent as Actual_Next&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, dt.tablespace_name, dt.next_extent as Default_Next&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_tablespaces dt, dba_segments ds&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE dt.tablespace_name = ds.tablespace_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AND dt.next_extent !=ds.next_extent&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AND ds.owner = UPPER ( '&amp;OWNER' )&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>ORDER BY tablespace_name, segment_type, segment_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. existext.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- existext.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To check existing extents&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- This tells us how many of each object's extents differ in size from&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- the tablespace's default size. If this report shows a lot of different&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- sized extents, your free space is likely to become fragmented. If so,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- this tablespace is a candidate for reorganizing.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 12/15/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT segment_name, segment_type&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, count(*) as nr_exts&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, sum ( DECODE ( dx.bytes,dt.next_extent,0,1) ) as nr_illsized_exts&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, dt.tablespace_name, dt.next_extent as dflt_ext_size&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM dba_tablespaces dt, dba_extents dx&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE dt.tablespace_name = dx.tablespace_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AND dx.owner = '&amp;OWNER'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>GROUP BY segment_name, segment_type, dt.tablespace_name, dt.next_extent&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3. No_pk.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- no_pk.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To find tables without PK constraint&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/2/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT table_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_tables&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE owner = '&amp;OWNER'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>MINUS&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT table_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_constraints&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE owner = '&amp;&amp;OWNER'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AND constraint_type = 'P'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>4. disPK.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- disPK.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To find out which primary keys are disabled&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/30/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT owner, constraint_name, table_name, status&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_constraints&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE owner = '&amp;OWNER' AND status = 'DISABLED’ AND constraint_type = 'P'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>5. nonuPK.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- nonuPK.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To find tables with nonunique PK indexes. Requires that PK names&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- follow a naming convention. An alternative query follows that&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- does not have this requirement, but runs more slowly.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/2/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT index_name, table_name, uniqueness&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_indexes&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE index_name like '&amp;PKNAME%'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AND owner = '&amp;OWNER' AND uniqueness = 'NONUNIQUE'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT c.constraint_name, i.tablespace_name, i.uniqueness&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_constraints c , all_indexes i&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE c.owner = UPPER ( '&amp;OWNER' ) AND i.uniqueness = 'NONUNIQUE'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AND c.constraint_type = 'P' AND i.index_name = c.constraint_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>6. mkrebuild_idx.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- mkrebuild_idx.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- Rebuild indexes to have correct storage parameters&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/2/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT 'alter index ' || index_name || ' rebuild '&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>, 'tablespace INDEXES storage '&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>|| ' ( initial 256 K next 256 K pctincrease 0 ) ; '&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_indexes&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE ( tablespace_name != 'INDEXES'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>OR next_extent != ( 256 * 1024 )&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>AND owner = '&amp;OWNER'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>/&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>7. datatype.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- datatype.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To check datatype consistency between two environments&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 11/30/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>table_name,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>column_name,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>data_type,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>data_length,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>data_precision,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>data_scale,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>nullable&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_tab_columns -- first environment&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE owner = '&amp;OWNER'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>MINUS&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>table_name,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>column_name,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>data_type,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>data_length,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>data_precision,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>data_scale,&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>nullable&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM all_tab_columns@&amp;my_db_link -- second environment&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>WHERE owner = '&amp;OWNER2'&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>order by table_name, column_name&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>8. obj_coord.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- obj_coord.sql&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- To find out any difference in objects between two instances&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>--&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>-- 12/08/98&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT object_name, object_type&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM user_objects&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>MINUS&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SELECT object_name, object_type&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>FROM user_objects@&amp;my_db_link&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>六. 参考文献&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>1. Loney, Kevin Oracle8 DBA Handbook&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>2. Cook, David Database Management from Crisis to Confidence&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>[http://www.orapub.com/]&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>3. Cox, Thomas B. The Database Administration Maturity Model]]></description>
</item><item>
<title><![CDATA[NULL 使用详解]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8555</link>
<author>blakestone</author>
<pubDate>2005/9/12 21:41:31</pubDate>
<description><![CDATA[软件环境：&nbsp;&nbsp;<BR>1、Windows NT4.0+ORACLE 8.0.4 <BR>2、ORACLE安装路径为：C:\ORANT <BR>&nbsp;&nbsp;<BR>含义解释：&nbsp;&nbsp;<BR>问：什么是NULL？ <BR>答：在我们不知道具体有什么数据的时候，也即未知，可以用NULL，我们称它为空，ORACLE中，含有空值的表列长度为零。 <BR>ORACLE允许任何一种数据类型的字段为空，除了以下两种情况： <BR>1、主键字段（primary key）， <BR>2、定义时已经加了NOT NULL限制条件的字段 <BR>&nbsp;&nbsp;<BR>说明： <BR>1、等价于没有任何值、是未知数。 <BR>2、NULL与0、空字符串、空格都不同。 <BR>3、对空值做加、减、乘、除等运算操作，结果仍为空。 <BR>4、NULL的处理使用NVL函数。 <BR>5、比较时使用关键字用“is null”和“is not null”。 <BR>6、空值不能被索引，所以查询时有些符合条件的数据可能查不出来，count(*)中，用nvl(列名,0)处理后再查。 <BR>7、排序时比其他数据都大（索引默认是降序排列，小→大），所以NULL值总是排在最后。 <BR>&nbsp;&nbsp;<BR>使用方法：&nbsp;&nbsp;<BR>SQL&gt; select 1 from dual where null=null; <BR>&nbsp;&nbsp;<BR>没有查到记录 <BR>&nbsp;&nbsp;<BR>SQL&gt; select 1 from dual where null=''; <BR>&nbsp;&nbsp;<BR>没有查到记录 <BR>&nbsp;&nbsp;<BR>SQL&gt; select 1 from dual where ''='';&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>没有查到记录 <BR>&nbsp;&nbsp;<BR>SQL&gt; select 1 from dual where null is null; <BR>&nbsp;&nbsp;<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 <BR>--------- <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 <BR>&nbsp;&nbsp;<BR>SQL&gt; select 1 from dual where nvl(null,0)=nvl(null,0); <BR>&nbsp;&nbsp;<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 <BR>--------- <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1 <BR>&nbsp;&nbsp;<BR>对空值做加、减、乘、除等运算操作，结果仍为空。 <BR>SQL&gt; select 1+null from dual; <BR>SQL&gt; select 1-null from dual; <BR>SQL&gt; select 1*null from dual; <BR>SQL&gt; select 1/null from dual; <BR>&nbsp;&nbsp;<BR>查询到一个记录. <BR>&nbsp;&nbsp;<BR>注：这个记录就是SQL语句中的那个null <BR>&nbsp;&nbsp;<BR>设置某些列为空值 <BR>update table1 set 列1=NULL where 列1 is not null; <BR>&nbsp;&nbsp;<BR>现有一个商品销售表sale，表结构为： <BR>month　　　 char(6)　　　　　 --月份 <BR>sell　　　　number(10,2)　　　--月销售金额 <BR>&nbsp;&nbsp;<BR>create table sale (month char(6),sell number); <BR>insert into sale values('200001',1000); <BR>insert into sale values('200002',1100); <BR>insert into sale values('200003',1200); <BR>insert into sale values('200004',1300); <BR>insert into sale values('200005',1400); <BR>insert into sale values('200006',1500); <BR>insert into sale values('200007',1600); <BR>insert into sale values('200101',1100); <BR>insert into sale values('200202',1200); <BR>insert into sale values('200301',1300); <BR>insert into sale values('200008',1000); <BR>insert into sale(month) values('200009');（注意：这条记录的sell值为空） <BR>commit; <BR>共输入12条记录 <BR>&nbsp;&nbsp;<BR>SQL&gt; select * from sale where sell like '%'; <BR>&nbsp;&nbsp;<BR>MONTH&nbsp; &nbsp;&nbsp; &nbsp; SELL <BR>------ --------- <BR>200001&nbsp; &nbsp;&nbsp; &nbsp;1000 <BR>200002&nbsp; &nbsp;&nbsp; &nbsp;1100 <BR>200003&nbsp; &nbsp;&nbsp; &nbsp;1200 <BR>200004&nbsp; &nbsp;&nbsp; &nbsp;1300 <BR>200005&nbsp; &nbsp;&nbsp; &nbsp;1400 <BR>200006&nbsp; &nbsp;&nbsp; &nbsp;1500 <BR>200007&nbsp; &nbsp;&nbsp; &nbsp;1600 <BR>200101&nbsp; &nbsp;&nbsp; &nbsp;1100 <BR>200202&nbsp; &nbsp;&nbsp; &nbsp;1200 <BR>200301&nbsp; &nbsp;&nbsp; &nbsp;1300 <BR>200008&nbsp; &nbsp;&nbsp; &nbsp;1000 <BR>&nbsp;&nbsp;<BR>查询到11记录. <BR>&nbsp;&nbsp;<BR>结果说明： <BR>查询结果说明此SQL语句查询不出列值为NULL的字段 <BR>此时需对字段为NULL的情况另外处理。 <BR>SQL&gt; select * from sale where sell like '%' or sell is null; <BR>SQL&gt; select * from sale where nvl(sell,0) like '%'; <BR>&nbsp;&nbsp;<BR>MONTH&nbsp; &nbsp;&nbsp; &nbsp; SELL <BR>------ --------- <BR>200001&nbsp; &nbsp;&nbsp; &nbsp;1000 <BR>200002&nbsp; &nbsp;&nbsp; &nbsp;1100 <BR>200003&nbsp; &nbsp;&nbsp; &nbsp;1200 <BR>200004&nbsp; &nbsp;&nbsp; &nbsp;1300 <BR>200005&nbsp; &nbsp;&nbsp; &nbsp;1400 <BR>200006&nbsp; &nbsp;&nbsp; &nbsp;1500 <BR>200007&nbsp; &nbsp;&nbsp; &nbsp;1600 <BR>200101&nbsp; &nbsp;&nbsp; &nbsp;1100 <BR>200202&nbsp; &nbsp;&nbsp; &nbsp;1200 <BR>200301&nbsp; &nbsp;&nbsp; &nbsp;1300 <BR>200008&nbsp; &nbsp;&nbsp; &nbsp;1000 <BR>200009 <BR>&nbsp;&nbsp;<BR>查询到12记录. <BR>&nbsp;&nbsp;<BR>Oracle的空值就是这么的用法，我们最好熟悉它的约定，以防查出的结果不正确。 <BR>]]></description>
</item><item>
<title><![CDATA[SQL*PLUS命令的使用大全]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8554</link>
<author>blakestone</author>
<pubDate>2005/9/12 21:40:04</pubDate>
<description><![CDATA[Oracle的sql*plus是与oracle进行交互的客户端工具。在sql*plus中，可以运行sql*plus命令与sql*plus语句。 <BR>&nbsp; &nbsp;我们通常所说的DML、DDL、DCL语句都是sql*plus语句，它们执行完后，都可以保存在一个被称为sql buffer的内存区域中，并且只能保存一条最近执行的sql语句，我们可以对保存在sql buffer中的sql 语句进行修改，然后再次执行，sql*plus一般都与数据库打交道。 <BR>&nbsp; &nbsp;除了sql*plus语句，在sql*plus中执行的其它语句我们称之为sql*plus命令。它们执行完后，不保存在sql buffer的内存区域中，它们一般用来对输出的结果进行格式化显示，以便于制作报表。 <BR>&nbsp; &nbsp;下面就介绍一下一些常用的sql*plus命令： <BR>&nbsp;&nbsp;<BR>1. 执行一个SQL脚本文件 <BR>SQL&gt;start file_name <BR>SQL&gt;@ file_name <BR>我们可以将多条sql语句保存在一个文本文件中，这样当要执行这个文件中的所有的sql语句时，用上面的任一命令即可，这类似于dos中的批处理。 <BR>&nbsp;&nbsp;<BR>2. 对当前的输入进行编辑 <BR>SQL&gt;edit <BR>&nbsp;&nbsp;<BR>3. 重新运行上一次运行的sql语句 <BR>SQL&gt;/ <BR>&nbsp;&nbsp;<BR>4. 将显示的内容输出到指定文件 <BR>SQL&gt; SPOOL file_name <BR>&nbsp; &nbsp;在屏幕上的所有内容都包含在该文件中，包括你输入的sql语句。 <BR>&nbsp;&nbsp;<BR>5. 关闭spool输出 <BR>SQL&gt; SPOOL OFF <BR>&nbsp; &nbsp;只有关闭spool输出，才会在输出文件中看到输出的内容。 <BR>&nbsp;&nbsp;<BR>6．显示一个表的结构 <BR>SQL&gt; desc table_name <BR>&nbsp;&nbsp;<BR>7. COL命令： <BR>主要格式化列的显示形式。 <BR>该命令有许多选项，具体如下： <BR>COL[UMN] [{ column|expr} [ option ...]] <BR>Option选项可以是如下的子句: <BR>ALI[AS] alias <BR>CLE[AR] <BR>FOLD_A[FTER] <BR>FOLD_B[EFORE] <BR>FOR[MAT] format <BR>HEA[DING] text <BR>JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]} <BR>LIKE { expr|alias} <BR>NEWL[INE] <BR>NEW_V[ALUE] variable <BR>NOPRI[NT]|PRI[NT] <BR>NUL[L] text <BR>OLD_V[ALUE] variable <BR>ON|OFF <BR>WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED] <BR>&nbsp;&nbsp;<BR>1). 改变缺省的列标题 <BR>COLUMN column_name HEADING column_heading <BR>For example: <BR>Sql&gt;select * from dept; <BR>&nbsp; &nbsp;&nbsp;&nbsp;DEPTNO DNAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;LOC <BR>---------- ---------------------------- --------- <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;10 ACCOUNTING&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; NEW YORK <BR>sql&gt;col&nbsp;&nbsp;LOC heading location <BR>sql&gt;select * from dept; <BR>&nbsp; &nbsp; DEPTNO DNAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;location <BR>--------- ---------------------------- ----------- <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;10 ACCOUNTING&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; NEW YORK <BR>&nbsp;&nbsp;<BR>2). 将列名ENAME改为新列名EMPLOYEE NAME并将新列名放在两行上： <BR>Sql&gt;select * from emp <BR>Department&nbsp;&nbsp;name&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Salary <BR>---------- ---------- ---------- <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;10 aaa&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 11&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<BR>SQL&gt; COLUMN ENAME HEADING ’Employee|Name’ <BR>Sql&gt;select * from emp <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Employee <BR>Department&nbsp;&nbsp;name&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Salary <BR>---------- ---------- ----------&nbsp;&nbsp;<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;10 aaa&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 11 <BR>note: the col heading turn into two lines from one line. <BR>&nbsp;&nbsp;<BR>3). 改变列的显示长度： <BR>FOR[MAT] format <BR>Sql&gt;select empno,ename,job from emp; <BR>&nbsp; &nbsp;&nbsp; &nbsp;EMPNO ENAME&nbsp; &nbsp;&nbsp; &nbsp;JOB&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<BR>---------- ----------&nbsp; &nbsp;&nbsp;&nbsp;--------- <BR>&nbsp; &nbsp;&nbsp; &nbsp; 7369 SMITH&nbsp; &nbsp;&nbsp; &nbsp;CLERK&nbsp; &nbsp;&nbsp; &nbsp;<BR>&nbsp; &nbsp;&nbsp; &nbsp; 7499 ALLEN&nbsp; &nbsp;&nbsp; &nbsp;SALESMAN&nbsp; &nbsp;<BR>7521 WARD&nbsp; &nbsp;&nbsp; &nbsp; SALESMAN&nbsp; &nbsp;<BR>Sql&gt; col ename format a40 <BR>&nbsp; &nbsp;&nbsp; &nbsp;EMPNO ENAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;JOB <BR>----------&nbsp; &nbsp;----------------------------------------&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;--------- <BR>&nbsp; &nbsp;&nbsp; &nbsp; 7369 SMITH&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;CLERK <BR>&nbsp; &nbsp;&nbsp; &nbsp; 7499 ALLEN&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALESMAN <BR>&nbsp; &nbsp;&nbsp; &nbsp; 7521 WARD&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALESMAN <BR>&nbsp;&nbsp;<BR>4). 设置列标题的对齐方式 <BR>JUS[TIFY] {L[EFT]|C[ENTER]|C[ENTRE]|R[IGHT]} <BR>SQL&gt; col ename justify center <BR>SQL&gt; / <BR>&nbsp; &nbsp;&nbsp; &nbsp;EMPNO&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;ENAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; JOB <BR>----------&nbsp; &nbsp;----------------------------------------&nbsp; &nbsp;&nbsp; &nbsp; --------- <BR>&nbsp; &nbsp;&nbsp; &nbsp; 7369 SMITH&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;CLERK <BR>&nbsp; &nbsp;&nbsp; &nbsp; 7499 ALLEN&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALESMAN <BR>7521 WARD&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; SALESMAN <BR>对于NUMBER型的列，列标题缺省在右边，其它类型的列标题缺省在左边 <BR>&nbsp;&nbsp;<BR>5). 不让一个列显示在屏幕上 <BR>NOPRI[NT]|PRI[NT] <BR>SQL&gt; col job noprint <BR>SQL&gt; / <BR>&nbsp; &nbsp;&nbsp; &nbsp;EMPNO&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;ENAME <BR>----------&nbsp; &nbsp;&nbsp;&nbsp;---------------------------------------- <BR>&nbsp; &nbsp;&nbsp; &nbsp; 7369 SMITH <BR>&nbsp; &nbsp;&nbsp; &nbsp; 7499 ALLEN <BR>7521 WARD <BR>&nbsp;&nbsp;<BR>6). 格式化NUMBER类型列的显示： <BR>SQL&gt; COLUMN SAL FORMAT $99,990 <BR>SQL&gt; / <BR>Employee <BR>Department Name&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Salary&nbsp; &nbsp; Commission <BR>---------- ---------- --------- ---------- <BR>30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; ALLEN&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;$1,600&nbsp; &nbsp; 300 <BR>&nbsp;&nbsp;<BR>7). 显示列值时，如果列值为NULL值，用text值代替NULL值 <BR>COMM NUL[L] text <BR>SQL&gt;COL COMM NUL[L] text <BR>&nbsp;&nbsp;<BR>8). 设置一个列的回绕方式 <BR>WRA[PPED]|WOR[D_WRAPPED]|TRU[NCATED] <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;COL1 <BR>-------------------- <BR>HOW ARE YOU? <BR>&nbsp;&nbsp;<BR>SQL&gt;COL COL1 FORMAT A5 <BR>SQL&gt;COL COL1 WRAPPED <BR>COL1 <BR>----- <BR>HOW A <BR>RE YO <BR>U? <BR>&nbsp;&nbsp;<BR>SQL&gt; COL COL1 WORD_WRAPPED <BR>COL1 <BR>----- <BR>HOW <BR>ARE <BR>YOU? <BR>&nbsp;&nbsp;<BR>SQL&gt; COL COL1 WORD_WRAPPED <BR>COL1 <BR>----- <BR>HOW A <BR>&nbsp;&nbsp;<BR>9). 显示列的当前的显示属性值 <BR>SQL&gt; COLUMN column_name <BR>&nbsp;&nbsp;<BR>10). 将所有列的显示属性设为缺省值 <BR>SQL&gt; CLEAR COLUMNS <BR>&nbsp;&nbsp;<BR>8. 屏蔽掉一个列中显示的相同的值 <BR>BREAK ON break_column <BR>SQL&gt; BREAK ON DEPTNO <BR>SQL&gt; SELECT DEPTNO, ENAME, SAL <BR>FROM EMP <BR>&nbsp;&nbsp;WHERE SAL &lt; 2500 <BR>&nbsp;&nbsp;ORDER BY DEPTNO; <BR>DEPTNO&nbsp; &nbsp;&nbsp; &nbsp;ENAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SAL <BR>---------- ----------- --------- <BR>10&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;CLARK&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2450 <BR>MILLER&nbsp; &nbsp;&nbsp; &nbsp;1300 <BR>20&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SMITH&nbsp; &nbsp;&nbsp; &nbsp; 800 <BR>ADAMS&nbsp; &nbsp;&nbsp; &nbsp; 1100 <BR>&nbsp;&nbsp;<BR>9. 在上面屏蔽掉一个列中显示的相同的值的显示中，每当列值变化时在值变化之前插入n个空行。 <BR>BREAK ON break_column SKIP n <BR>&nbsp;&nbsp;<BR>SQL&gt; BREAK ON DEPTNO SKIP 1 <BR>SQL&gt; / <BR>DEPTNO ENAME SAL <BR>---------- ----------- --------- <BR>10 CLARK 2450 <BR>MILLER 1300 <BR>&nbsp;&nbsp;<BR>20 SMITH 800 <BR>ADAMS 1100 <BR>&nbsp;&nbsp;<BR>10. 显示对BREAK的设置 <BR>SQL&gt; BREAK <BR>&nbsp;&nbsp;<BR>11. 删除6、7的设置 <BR>SQL&gt; CLEAR BREAKS <BR>&nbsp;&nbsp;<BR>12. Set 命令： <BR>该命令包含许多子命令： <BR>SET system_variable value <BR>system_variable value 可以是如下的子句之一： <BR>APPI[NFO]{ON|OFF|text} <BR>ARRAY[SIZE] {15|n} <BR>AUTO[COMMIT]{ON|OFF|IMM[EDIATE]|n} <BR>AUTOP[RINT] {ON|OFF} <BR>AUTORECOVERY [ON|OFF] <BR>AUTOT[RACE] {ON|OFF|TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]] <BR>BLO[CKTERMINATOR] {.|c} <BR>CMDS[EP] {;|c|ON|OFF} <BR>COLSEP {_|text} <BR>COM[PATIBILITY]{V7|V8|NATIVE} <BR>CON[CAT] {.|c|ON|OFF} <BR>COPYC[OMMIT] {0|n} <BR>COPYTYPECHECK {ON|OFF} <BR>DEF[INE] {&amp;|c|ON|OFF} <BR>DESCRIBE [DEPTH {1|n|ALL}][LINENUM {ON|OFF}][INDENT {ON|OFF}] <BR>ECHO {ON|OFF} <BR>EDITF[ILE] file_name[.ext] <BR>EMB[EDDED] {ON|OFF} <BR>ESC[APE] {\|c|ON|OFF} <BR>FEED[BACK] {6|n|ON|OFF} <BR>FLAGGER {OFF|ENTRY |INTERMED[IATE]|FULL} <BR>FLU[SH] {ON|OFF} <BR>HEA[DING] {ON|OFF} <BR>HEADS[EP] {||c|ON|OFF} <BR>INSTANCE [instance_path|LOCAL] <BR>LIN[ESIZE] {80|n} <BR>LOBOF[FSET] {n|1} <BR>LOGSOURCE [pathname] <BR>LONG {80|n} <BR>LONGC[HUNKSIZE] {80|n} <BR>MARK[UP] HTML [ON|OFF] [HEAD text] [BODY text] [ENTMAP {ON|OFF}] [SPOOL <BR>{ON|OFF}] [PRE[FORMAT] {ON|OFF}] <BR>NEWP[AGE] {1|n|NONE} <BR>NULL text <BR>NUMF[ORMAT] format <BR>NUM[WIDTH] {10|n} <BR>PAGES[IZE] {24|n} <BR>PAU[SE] {ON|OFF|text} <BR>RECSEP {WR[APPED]|EA[CH]|OFF} <BR>RECSEPCHAR {_|c} <BR>SERVEROUT[PUT] {ON|OFF} [SIZE n] [FOR[MAT] {WRA[PPED]|WOR[D_ <BR>WRAPPED]|TRU[NCATED]}] <BR>SHIFT[INOUT] {VIS[IBLE]|INV[ISIBLE]} <BR>SHOW[MODE] {ON|OFF} <BR>SQLBL[ANKLINES] {ON|OFF} <BR>SQLC[ASE] {MIX[ED]|LO[WER]|UP[PER]} <BR>SQLCO[NTINUE] {&gt; |text} <BR>SQLN[UMBER] {ON|OFF} <BR>SQLPRE[FIX] {#|c} <BR>SQLP[ROMPT] {SQL&gt;|text} <BR>SQLT[ERMINATOR] {;|c|ON|OFF} <BR>SUF[FIX] {SQL|text} <BR>TAB {ON|OFF} <BR>TERM[OUT] {ON|OFF} <BR>TI[ME] {ON|OFF} <BR>TIMI[NG] {ON|OFF} <BR>TRIM[OUT] {ON|OFF} <BR>TRIMS[POOL] {ON|OFF} <BR>UND[ERLINE] {-|c|ON|OFF} <BR>VER[IFY] {ON|OFF} <BR>WRA[P] {ON|OFF} <BR>&nbsp;&nbsp;<BR>1). 设置当前session是否对修改的数据进行自动提交 <BR>SQL&gt;SET AUTO[COMMIT] {ON|OFF|IMM[EDIATE]| n} <BR>&nbsp;&nbsp;<BR>2)．在用start命令执行一个sql脚本时，是否显示脚本中正在执行的SQL语句 <BR>SQL&gt; SET ECHO {ON|OFF} <BR>&nbsp;&nbsp;<BR>3).是否显示当前sql语句查询或修改的行数 <BR>SQL&gt; SET FEED[BACK] {6|n|ON|OFF} <BR>&nbsp; &nbsp;默认只有结果大于6行时才显示结果的行数。如果set feedback 1 ，则不管查询到多少行都返回。当为off 时，一律不显示查询的行数 <BR>&nbsp;&nbsp;<BR>4).是否显示列标题 <BR>SQL&gt; SET HEA[DING] {ON|OFF} <BR>当set heading off 时，在每页的上面不显示列标题，而是以空白行代替 <BR>&nbsp;&nbsp;<BR>5).设置一行可以容纳的字符数 <BR>SQL&gt; SET LIN[ESIZE] {80|n} <BR>&nbsp; &nbsp;如果一行的输出内容大于设置的一行可容纳的字符数，则折行显示。 <BR>&nbsp;&nbsp;<BR>6).设置页与页之间的分隔 <BR>SQL&gt; SET NEWP[AGE] {1|n|NONE} <BR>当set newpage 0 时，会在每页的开头有一个小的黑方框。 <BR>当set newpage n 时，会在页和页之间隔着n个空行。 <BR>当set newpage none 时，会在页和页之间没有任何间隔。 <BR>&nbsp;&nbsp;<BR>7).显示时，用text值代替NULL值 <BR>SQL&gt; SET NULL text <BR>&nbsp;&nbsp;<BR>8).设置一页有多少行数 <BR>SQL&gt; SET PAGES[IZE] {24|n} <BR>如果设为0，则所有的输出内容为一页并且不显示列标题 <BR>&nbsp;&nbsp;<BR>9).是否显示用DBMS_OUTPUT.PUT_LINE包进行输出的信息。 <BR>SQL&gt; SET SERVEROUT[PUT] {ON|OFF}&nbsp;&nbsp;<BR>在编写存储过程时，我们有时会用dbms_output.put_line将必要的信息输出，以便对存储过程进行调试，只有将serveroutput变量设为on后，信息才能显示在屏幕上。 <BR>&nbsp;&nbsp;<BR>10).当SQL语句的长度大于LINESIZE时，是否在显示时截取SQL语句。 <BR>SQL&gt; SET WRA[P] {ON|OFF} <BR>&nbsp; &nbsp;当输出的行的长度大于设置的行的长度时（用set linesize n命令设置），当set wrap on时，输出行的多于的字符会另起一行显示，否则，会将输出行的多于字符切除，不予显示。 <BR>&nbsp;&nbsp;<BR>11).是否在屏幕上显示输出的内容，主要用与SPOOL结合使用。 <BR>SQL&gt; SET TERM[OUT] {ON|OFF} <BR>&nbsp; &nbsp;在用spool命令将一个大表中的内容输出到一个文件中时，将内容输出在屏幕上会耗费大量的时间，设置set termspool off后，则输出的内容只会保存在输出文件中，不会显示在屏幕上，极大的提高了spool的速度。 <BR>&nbsp;&nbsp;<BR>12).将SPOOL输出中每行后面多余的空格去掉 <BR>SQL&gt; SET TRIMS[OUT] {ON|OFF}&nbsp;&nbsp;<BR>&nbsp; &nbsp; <BR>13)显示每个sql语句花费的执行时间 <BR>set TIMING&nbsp;&nbsp;{ON|OFF} <BR>&nbsp;&nbsp;<BR>14．修改sql buffer中的当前行中，第一个出现的字符串 <BR>C[HANGE] /old_value/new_value <BR>SQL&gt; l <BR>&nbsp; &nbsp;1* select * from dept <BR>SQL&gt; c/dept/emp <BR>&nbsp; &nbsp;1* select * from emp <BR>&nbsp;&nbsp;<BR>15．编辑sql buffer中的sql语句 <BR>EDI[T] <BR>&nbsp;&nbsp;<BR>16．显示sql buffer中的sql语句，list n显示sql buffer中的第n行，并使第n行成为当前行 <BR>L[IST] [n] <BR>&nbsp;&nbsp;<BR>17．在sql buffer的当前行下面加一行或多行 <BR>I[NPUT] <BR>&nbsp;&nbsp;<BR>18．将指定的文本加到sql buffer的当前行后面 <BR>A[PPEND] <BR>SQL&gt; select deptno, <BR>&nbsp; &nbsp;2&nbsp;&nbsp;dname <BR>&nbsp; &nbsp;3&nbsp;&nbsp;from dept; <BR>&nbsp; &nbsp;&nbsp;&nbsp;DEPTNO DNAME <BR>---------- -------------- <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;10 ACCOUNTING <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20 RESEARCH <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30 SALES <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;40 OPERATIONS <BR>&nbsp;&nbsp;<BR>SQL&gt; L 2 <BR>&nbsp; &nbsp;2* dname <BR>SQL&gt; a ,loc <BR>&nbsp; &nbsp;2* dname,loc <BR>SQL&gt; L <BR>&nbsp; &nbsp;1&nbsp;&nbsp;select deptno, <BR>&nbsp; &nbsp;2&nbsp;&nbsp;dname,loc <BR>&nbsp; &nbsp;3* from dept <BR>SQL&gt; / <BR>&nbsp;&nbsp;<BR>&nbsp; &nbsp;&nbsp;&nbsp;DEPTNO DNAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; LOC <BR>---------- -------------- ------------- <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;10 ACCOUNTING&nbsp; &nbsp;&nbsp;&nbsp;NEW YORK <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;20 RESEARCH&nbsp; &nbsp;&nbsp; &nbsp; DALLAS <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30 SALES&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; CHICAGO <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;40 OPERATIONS&nbsp; &nbsp;&nbsp;&nbsp;BOSTON <BR>&nbsp;&nbsp;<BR>19．将sql buffer中的sql语句保存到一个文件中 <BR>SAVE file_name <BR>&nbsp;&nbsp;<BR>20．将一个文件中的sql语句导入到sql buffer中 <BR>GET file_name <BR>&nbsp;&nbsp;<BR>21．再次执行刚才已经执行的sql语句 <BR>RUN <BR>or <BR>/ <BR>&nbsp;&nbsp;<BR>22．执行一个存储过程 <BR>EXECUTE procedure_name <BR>&nbsp;&nbsp;<BR>23．在sql*plus中连接到指定的数据库 <BR>CONNECT user_name/passwd@db_alias <BR>&nbsp;&nbsp;<BR>24．设置每个报表的顶部标题 <BR>TTITLE <BR>&nbsp;&nbsp;<BR>25．设置每个报表的尾部标题 <BR>BTITLE <BR>&nbsp;&nbsp;<BR>26．写一个注释 <BR>REMARK [text] <BR>&nbsp;&nbsp;<BR>27．将指定的信息或一个空行输出到屏幕上 <BR>PROMPT [text] <BR>&nbsp;&nbsp;<BR>28．将执行的过程暂停，等待用户响应后继续执行 <BR>PAUSE [text] <BR>&nbsp;&nbsp;<BR>Sql&gt;PAUSE Adjust paper and press RETURN to continue. <BR>&nbsp;&nbsp;<BR>29．将一个数据库中的一些数据拷贝到另外一个数据库（如将一个表的数据拷贝到另一个数据库） <BR>COPY {FROM database | TO database | FROM database TO database} <BR>{APPEND|CREATE|INSERT|REPLACE} destination_table <BR>[(column, column, column, ...)] USING query <BR>&nbsp;&nbsp;<BR>sql&gt;COPY FROM SCOTT/TIGER@HQ TO JOHN/CHROME@WEST&nbsp;&nbsp;<BR>create emp_temp <BR>USING SELECT * FROM EMP <BR>&nbsp;&nbsp;<BR>30．不退出sql*plus，在sql*plus中执行一个操作系统命令： <BR>HOST <BR>&nbsp;&nbsp;<BR>Sql&gt; host hostname <BR>该命令在windows下可能被支持。 <BR>&nbsp;&nbsp;<BR>31．在sql*plus中，切换到操作系统命令提示符下，运行操作系统命令后，可以再次切换回sql*plus： <BR>! <BR>&nbsp;&nbsp;<BR>sql&gt;! <BR>$hostname <BR>$exit <BR>sql&gt; <BR>&nbsp;&nbsp;<BR>该命令在windows下不被支持。 <BR>&nbsp;&nbsp;<BR>32．显示sql*plus命令的帮助 <BR>HELP <BR>如何安装帮助文件： <BR>Sql&gt;@ ?\sqlplus\admin\help\hlpbld.sql ?\sqlplus\admin\help\helpus.sql <BR>Sql&gt;help index <BR>&nbsp;&nbsp;<BR>33．显示sql*plus系统变量的值或sql*plus环境变量的值 <BR>Syntax <BR>SHO[W] option <BR>where option represents one of the following terms or clauses: <BR>system_variable <BR>ALL <BR>BTI[TLE] <BR>ERR[ORS] [{FUNCTION|PROCEDURE|PACKAGE|PACKAGE BODY| <BR>TRIGGER|VIEW|TYPE|TYPE BODY} [schema.]name] <BR>LNO <BR>PARAMETERS [parameter_name] <BR>PNO <BR>REL[EASE] <BR>REPF[OOTER] <BR>REPH[EADER] <BR>SGA <BR>SPOO[L] <BR>SQLCODE <BR>TTI[TLE] <BR>USER <BR>&nbsp;&nbsp;<BR>1) . 显示当前环境变量的值： <BR>Show all <BR>&nbsp;&nbsp;<BR>2) . 显示当前在创建函数、存储过程、触发器、包等对象的错误信息 <BR>Show error <BR>当创建一个函数、存储过程等出错时，变可以用该命令查看在那个地方出错及相应的出错信息，进行修改后再次进行编译。 <BR>&nbsp;&nbsp;<BR>3) . 显示初始化参数的值： <BR>show PARAMETERS [parameter_name] <BR>&nbsp;&nbsp;<BR>4) . 显示数据库的版本： <BR>show REL[EASE] <BR>&nbsp;&nbsp;<BR>5) . 显示SGA的大小 <BR>show SGA <BR>&nbsp;&nbsp;<BR>6). 显示当前的用户名 <BR>show user]]></description>
</item><item>
<title><![CDATA[Oracle数据库字符集问题解决方案]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8544</link>
<author>blakestone</author>
<pubDate>2005/9/12 16:52:03</pubDate>
<description><![CDATA[在国内外大中型数据库管理系统中，把ORACLE作为数据库管理平台的用户比 <BR>较多。ORACLE 不论是数据库管理能力还是安全性都是无可非议的，但是，它在汉 <BR>字信息的显示方面着实给中国用户带来不少麻烦，笔者多年从事ORACLE数据库管 <BR>理，经常收到周围用户和外地用户反映有关ORACLE数据库汉字显示问题的求援信， <BR>主要现象是把汉字显示为不可识别的乱码，造成原来大量信息无法使用。本文将就 <BR>这一问题产生的原因和解决办法进行一些探讨，供存在这方面问题的用户朋友参 <BR>考。&nbsp;&nbsp;<BR>---- 1、原因分析&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 通过对用户反映情况的分析，发现字符集的设置不当是影响ORACLE数据库汉 <BR>字显示的关键问题。那么字符集是怎么一会事呢？字符集是ORACLE 为适应不同语 <BR>言文字显示而设定的。用于汉字显示的字符集主要有ZHS16CGB231280， <BR>US7ASCII，WE8ISO8859P1等。字符集不仅需在服务器端存在，而且客户端也必须 <BR>有字符集注册。服务器端，字符集是在安装ORACLE时指定的，字符集登记信息存储 <BR>在ORACLE数据库字典的V$NLS_PARAMETERS表中；客户端，字符集分两种情况，一 <BR>种情况是sql*net 2.0以下版本，字符集是在windows的系统目录下的oracle.ini <BR>文件中登记的；另一种情况是sql*net 2.0以上（即32位）版本，字符集是在&nbsp;&nbsp;<BR>windows的系统注册表中登记的。要在客户端正确显示ORACLE 数据库汉字信息，首 <BR>先必须使服务器端的字符集与客户端的字符集一致；其次是加载到ORACLE数据库的 <BR>数据字符集必须与服务器指定字符集一致。因此，把用户存在的问题归纳分类，产 <BR>生汉字显示异常的原因大致有以下几种：&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 1. 1服务器指定字符集与客户字符集不同，而与加载数据字符集一致。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 这种情况是最常见的，只要把客户端的字符集设置正确即可，解决办法见 <BR>2.1。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 1. 2服务器指定字符集与客户字符集相同,与加载数据字符集不一致。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 这类问题一般发生在ORACLE版本升级或重新安装系统时选择了与原来服务器 <BR>端不同的字符集，而恢复加载的备份数据仍是按原字符集卸出的场合,以及加载从其 <BR>它使用不同字符集的ORACLE数据库卸出的数据的情况。这两种情况中，不管服务器 <BR>端和客户端字符集是否一致都无法显示汉字。解决办法见2.2。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 1.3服务器指定字符集与客户字符集不同,与输入数据字符集不一致。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 这种情况是在客户端与服务器端字符集不一致时，从客户端输入了汉字信 <BR>息。输入的这些信息即便是把客户端字符集更改正确，也无法显示汉字。解决办法 <BR>见2.3。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 2．解决办法&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 下面将分别对上述三种情况给出解决办法。为了叙述方便，假设客户端使用 <BR>WINDOWS95/98环境，并已成功地配置了TCP/IP协议，安装了ORACLE的sql*net， <BR>sql*pluse产品。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 2.1 设置客户端字符集与服务器端字符集一致&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 假设当前服务器端使用US7ASCII字符集。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- （1）查看服务器端字符集&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 通过客户端或服务器端的sql*plus登录ORACLE的一个合法用户，执行下列 <BR>SQL语句：&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SQL &gt; select * from V$NLS_PARAMETERS&nbsp;&nbsp;<BR>parameter value <BR>NLS_LANGUAGE AMERICAN <BR>NLS_TERRITORY AMERICA <BR>…. …. <BR>NLS_CHARACTERSET US7ASCII <BR>NLS_SORT BINARY <BR>NLS_NCHAR_CHARACTERSET US7ASCII <BR>&nbsp;&nbsp;<BR>---- 从上述列表信息中可看出服务器端ORACLE数据库的字符集为'US7ASCII'。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- （2）按照服务器端字符集对客户端进行配置&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 配置方法有两种：&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>安装ORACLE的客户端软件时指定&nbsp;&nbsp;<BR>---- 在安装ORACLE的客户端产品软件时，选择与ORACLE服务端一致的字符集（本 <BR>例为US7ASCII）即可。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>修改注册信息的方法&nbsp;&nbsp;<BR>---- 根据ORACLE 客户端所选sql*net 的版本分为下列两种情况：&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- a. 客户端为 sql*net 2.0 以下版本&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 进入Windows的系统目录，编辑oracle.ini文件，用US7ASCII替换原字符 <BR>集，重新启动计算机，设置生效。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- b. 客户端为 sql*net 2.0 以上版本&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 在WIN98 下 运 行REGEDIT,第一步选HKEY_LOCAL_MACHINE,第二步选择 <BR>SOFTWARE， 第三步选择 ORACLE， 第四步选择 NLS_LANG， 键 入 与服 务 器&nbsp;&nbsp;<BR>端 相 同 的 字 符 集（本例为：AMERICAN_AMERICAN.US7ASCII）。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 2.2 强制加载数据字符集与服务器端字符集一致&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 假设要加载数据从原ORACLE数据库卸出时的字符集为US7ASCII，当前ORACLE <BR>服务器字符集为WE8ISO8859P1。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 下面提供三种解决方法：&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- （1） 服务器端重新安装ORACLE&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 在重新安装ORACLE 时选择与原卸出数据一致的字符集（本例为 <BR>US7ASCII）。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 加载原卸出的数据。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 这种情况仅仅使用于空库和具有同一种字符集的数据。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- （2）强行修改服务器端ORACLE当前字符集&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 在用imp命令加载数据前，先在客户端用sql*plus登录system DBA用户，执 <BR>行下列SQL语句进行当前ORACLE数据库字符集修改：&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>SQL &gt; create database character set US7ASCII <BR>* create database character set US7ASCII <BR>ERROR at line 1: <BR>ORA-01031: insufficient privileges <BR>&nbsp;&nbsp;<BR>---- 你会发现语句执行过程中，出现上述错误提示信息，此时不用理会，实际上 <BR>ORACLE数据库的字符集已被强行修改为US7ASCII，接着用imp命令装载数据。等数 <BR>据装载完成以后，shutdown 数据库，再startup 数据库，用合法用户登录ORACLE <BR>数据库，在sql&gt;命令提示符下，运行select * from V$NLS_PARAMETERS，可以看 <BR>到ORACLE数据库字符集已复原，这时再查看有汉字字符数据的表时，汉字已能被正 <BR>确显示。&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- （3）利用数据格式转储，避开字符集限制&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 这种方法主要用于加载外来ORACLE数据库的不同字符集数据。其方法如下：&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 先将数据加载到具有相同字符集的服务器上，然后用转换工具卸出为 <BR>foxbase 格式或access格式数据库，再用转换工具转入到不同字符集的ORACLE数 <BR>据库中，这样就避免了ORACLE字符集的困扰。目前数据库格式转换的工具很多,象 <BR>power builder5.0以上版本提供的pipeline，Microsoft Access数据库提供的数 <BR>据导入/导出功能等。转换方法参见有关资料说明。.&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 2.3匹配字符集替换汉字&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>---- 对于1.3提到的情况，没有很好的办法，只能先把客户端与服务器端字符集匹&nbsp;&nbsp;<BR>配一致后，根据原输入汉字的特征码替换汉字字符部分。 <BR>]]></description>
</item><item>
<title><![CDATA[Oracle经典书籍介绍]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8541</link>
<author>blakestone</author>
<pubDate>2005/9/12 14:42:54</pubDate>
<description><![CDATA[很多网友询问如何选择入门书籍，学Oracle有什么好书，这里给出一些常见书籍的介绍。首先声明，本文只涉及国外作品，因为国内的作品好的极少，大多是拼凑之作。 <BR>提到入门学习，我又得搬Tom(Thomas Kyte)出来了。他在Ask Tom和他最新的书里都介绍了他认为比较好的学习途径和阅读资料。他推荐的资料都是Oracle的官方文档，有个网友在版上也提出是不是通读文档就可以了。可以肯定地说，如果你通读了文档，记住了其中的50%，那你已经很牛了，我的有生之年估计不会有可能通读——对于9iR2一共48篇文档共计46000+页！Tom给出了必读文档和顺序，我简要说明如下： <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 所有人员 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; Concepts <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;| <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;New Features <BR>&nbsp; &nbsp;&nbsp; &nbsp;__________|____________ <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>Developer&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; DBA <BR>Application&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; Backup &amp; Recovery <BR>Dev Guide(Fundamentals)&nbsp; &nbsp;&nbsp; &nbsp; Concepts <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>PL/SQL User Guide&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; Recovery Reference <BR>&amp; References&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; | <BR>&nbsp; &nbsp;&nbsp;&nbsp;|&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;| <BR>Performance&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Administrators' Guide&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; <BR>Planning <BR>&nbsp; &nbsp;&nbsp;&nbsp;|______________________|&nbsp; &nbsp;&nbsp; &nbsp;<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;<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Performance <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &amp; Tunning Guide <BR>&nbsp;&nbsp;<BR>下面来谈谈书籍。 <BR>&nbsp; &nbsp;&nbsp;&nbsp;国内比较畅销的当属机械工业出版社黑色那套了，其中精品很多。入门的《Oracle 9i初学者指南》浅显易懂，是入门的好帮手。开发方面《Oracle 9i PL/SQL程序设计》，DBA方面《Oracle 9i DBA手册》，调优方面《Oracle 9i性能调优指南》都是经典的书，根据需要选择吧。我觉得其中《Oracle 9i 参考手册》是不错的书，比较全面实用，各方面涉及就不深入了。 <BR>&nbsp; &nbsp;&nbsp;&nbsp;其他经典书籍又不能绕过Tom了，他的《Oracle专家高级编程》（Expert one-by-on Oracle）是绝对的经典，可惜中文版被翻译糟蹋了，我正在看，其中的翻译有的术语很怪异，有的不知所云，确实有点累，但内容深入，涉及到Oracle内部结构、锁机制、导入导出的使用、性能调优等等等等很多的方面。主要基于Oracle 8.1.7，但是用他的原话来说99%的可以毫无变动的用到9i上。他还基于这本书写了另一本新书《Effective Oracle by Design》（2003），国内尚没有翻译版，要买的话只有Amazon了，目前倒是降价中。内容主要是关于开发的一整套，比如团队开发中的分工、开发的原则、性能调优等等。这两本书的内容介绍和目录大家可以到asktom.oracle.com看到，总体来说都是大师之作。 <BR>&nbsp; &nbsp;&nbsp;&nbsp;其实上面这些书已经是很充足了，加起来上万页也有了。不过要考OCP的话，还是看Student Guide咯（地球人都知道？:)），我刚看完007和031的vol.1，总体感觉是讲解还算详细，内容不是很深，但真的很全面。另外它是作为教程的形式的，所以很多东西的编排考虑到了难度等等，而不是一般参考手册那样一次就把一个数据对象、类型讲透。看这个文档的同时大家可以结合上面提到的官方文档、书籍一起阅读。 <BR>]]></description>
</item><item>
<title><![CDATA[Oracle 9i 分析函数参考手册]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8469</link>
<author>blakestone</author>
<pubDate>2005/9/11 9:55:06</pubDate>
<description><![CDATA[Oracle从8.1.6开始提供分析函数，分析函数用于计算基于组的某种聚合值，它和聚合函数的不同之处是对于每个组返回多行，而聚合函数对于每个组只返回一行。<BR>下面例子中使用的表来自Oracle自带的HR用户下的表，如果没有安装该用户，可以在SYS用户下运行$ORACLE_HOME/demo/schema/human_resources/hr_main.sql来创建。<BR>&nbsp; &nbsp; &nbsp; &nbsp; 少数几个例子需要访问SH用户下的表，如果没有安装该用户，可以在SYS用户下运行$ORACLE_HOME/demo/schema/sales_history/sh_main.sql来创建。<BR>&nbsp; &nbsp; &nbsp; &nbsp; 如果未指明缺省是在HR用户下运行例子。<BR>&nbsp; &nbsp; &nbsp; &nbsp; 开窗函数的的理解：<BR>&nbsp; &nbsp; &nbsp; &nbsp; 开窗函数指定了分析函数工作的数据窗口大小，这个数据窗口大小可能会随着行的变化而变化，举例如下：<BR>over（order by salary） 按照salary排序进行累计，order by是个默认的开窗函数<BR>over（partition by deptno）按照部门分区<BR>over（order by salary range between 50 preceding and 150 following）<BR>每行对应的数据窗口是之前行幅度值不超过50，之后行幅度值不超过150<BR>over（order by salary rows between 50 preceding and 150 following）<BR>每行对应的数据窗口是之前50行，之后150行<BR>over（order by salary rows between unbounded preceding and unbounded following）<BR>每行对应的数据窗口是从第一行到最后一行，等效：<BR>over（order by salary range between unbounded preceding and unbounded following）<BR><BR>主要参考资料：《expert one-on-one》 Tom Kyte&nbsp;&nbsp;《Oracle9i SQL Reference》第6章<BR><BR><BR>AVG <BR>功能描述：用于计算一个组和数据窗口内表达式的平均值。<BR>SAMPLE：下面的例子中列c_mavg计算员工表中每个员工的平均薪水报告，该平均值由当前员工和与之具有相同经理的前一个和后一个三者的平均数得来；<BR><BR>SELECT manager_id, last_name, hire_date, salary,<BR>&nbsp; &nbsp;AVG(salary) OVER (PARTITION BY manager_id ORDER BY hire_date <BR>&nbsp; &nbsp;ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS c_mavg<BR>&nbsp; &nbsp;FROM employees;<BR><BR>MANAGER_ID LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;HIRE_DATE&nbsp; &nbsp;&nbsp;&nbsp;SALARY&nbsp; &nbsp;&nbsp;&nbsp;C_MAVG<BR>---------- ------------------------- --------- ---------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp; 100 Kochhar&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 21-SEP-89&nbsp; &nbsp;&nbsp; &nbsp;17000&nbsp; &nbsp;&nbsp; &nbsp;17000<BR>&nbsp; &nbsp;&nbsp; &nbsp; 100 De Haan&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 13-JAN-93&nbsp; &nbsp;&nbsp; &nbsp;17000&nbsp; &nbsp;&nbsp; &nbsp;15000<BR>&nbsp; &nbsp;&nbsp; &nbsp; 100 Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;07-DEC-94&nbsp; &nbsp;&nbsp; &nbsp;11000 11966.6667<BR>&nbsp; &nbsp;&nbsp; &nbsp; 100 Kaufling&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;01-MAY-95&nbsp; &nbsp;&nbsp; &nbsp; 7900 10633.3333<BR>&nbsp; &nbsp;&nbsp; &nbsp; 100 Hartstein&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;17-FEB-96&nbsp; &nbsp;&nbsp; &nbsp;13000 9633.33333<BR>&nbsp; &nbsp;&nbsp; &nbsp; 100 Weiss&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;18-JUL-96&nbsp; &nbsp;&nbsp; &nbsp; 8000 11666.6667<BR>&nbsp; &nbsp;&nbsp; &nbsp; 100 Russell&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 01-OCT-96&nbsp; &nbsp;&nbsp; &nbsp;14000 11833.3333<BR>.<BR>.<BR>.<BR><BR><BR>CORR <BR>功能描述：返回一对表达式的相关系数，它是如下的缩写：<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; COVAR_POP(expr1,expr2)/STDDEV_POP(expr1)*STDDEV_POP(expr2))<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 从统计上讲，相关性是变量之间关联的强度，变量之间的关联意味着在某种程度<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 上一个变量的值可由其它的值进行预测。通过返回一个-1~1之间的一个数, 相关<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 系数给出了关联的强度，0表示不相关。<BR>SAMPLE：下例返回1998年月销售收入和月单位销售的关系的累积系数（本例在SH用户下运行）<BR><BR>SELECT t.calendar_month_number,<BR>&nbsp; &nbsp;&nbsp; &nbsp; CORR (SUM(s.amount_sold), SUM(s.quantity_sold))<BR>&nbsp; &nbsp;&nbsp; &nbsp; OVER (ORDER BY t.calendar_month_number) as CUM_CORR<BR>&nbsp;&nbsp;FROM sales s, times t<BR>WHERE s.time_id = t.time_id AND calendar_year = 1998<BR>GROUP BY t.calendar_month_number<BR>ORDER BY t.calendar_month_number;<BR><BR>CALENDAR_MONTH_NUMBER&nbsp; &nbsp;CUM_CORR<BR>--------------------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;3 .994309382<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4 .852040875<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;5 .846652204<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6 .871250628<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;7 .910029803<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;8 .917556399<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;9 .920154356<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 10&nbsp;&nbsp;.86720251<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 11 .844864765<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 12 .903542662<BR><BR><BR>COVAR_POP&nbsp;&nbsp;<BR>功能描述：返回一对表达式的总体协方差。<BR>SAMPLE：下例CUM_COVP返回定价和最小产品价格的累积总体协方差<BR><BR>SELECT product_id, supplier_id,<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;COVAR_POP(list_price, min_price) <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; OVER (ORDER BY product_id, supplier_id) AS CUM_COVP,<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;COVAR_SAMP(list_price, min_price)<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; OVER (ORDER BY product_id, supplier_id) AS CUM_COVS <BR>&nbsp;&nbsp;FROM product_information p<BR>WHERE category_id = 29<BR>ORDER BY product_id, supplier_id;<BR><BR>PRODUCT_ID SUPPLIER_ID&nbsp; &nbsp;CUM_COVP&nbsp; &nbsp;CUM_COVS<BR>---------- ----------- ---------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp;1774&nbsp; &nbsp;&nbsp; &nbsp;103088&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0<BR>&nbsp; &nbsp;&nbsp; &nbsp;1775&nbsp; &nbsp;&nbsp; &nbsp;103087&nbsp; &nbsp; 1473.25&nbsp; &nbsp;&nbsp;&nbsp;2946.5<BR>&nbsp; &nbsp;&nbsp; &nbsp;1794&nbsp; &nbsp;&nbsp; &nbsp;103096 1702.77778 2554.16667<BR>&nbsp; &nbsp;&nbsp; &nbsp;1825&nbsp; &nbsp;&nbsp; &nbsp;103093&nbsp; &nbsp; 1926.25 2568.33333<BR>&nbsp; &nbsp;&nbsp; &nbsp;2004&nbsp; &nbsp;&nbsp; &nbsp;103086&nbsp; &nbsp;&nbsp;&nbsp;1591.4&nbsp; &nbsp; 1989.25<BR>&nbsp; &nbsp;&nbsp; &nbsp;2005&nbsp; &nbsp;&nbsp; &nbsp;103086&nbsp; &nbsp;&nbsp;&nbsp;1512.5&nbsp; &nbsp;&nbsp; &nbsp; 1815<BR>&nbsp; &nbsp;&nbsp; &nbsp;2416&nbsp; &nbsp;&nbsp; &nbsp;103088 1475.97959 1721.97619<BR>.<BR>.<BR><BR><BR>COVAR_SAMP&nbsp;&nbsp;<BR>功能描述：返回一对表达式的样本协方差<BR>SAMPLE：下例CUM_COVS返回定价和最小产品价格的累积样本协方差<BR><BR>SELECT product_id, supplier_id,<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;COVAR_POP(list_price, min_price) <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; OVER (ORDER BY product_id, supplier_id) AS CUM_COVP,<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;COVAR_SAMP(list_price, min_price)<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; OVER (ORDER BY product_id, supplier_id) AS CUM_COVS <BR>&nbsp;&nbsp;FROM product_information p<BR>WHERE category_id = 29<BR>ORDER BY product_id, supplier_id;<BR><BR>PRODUCT_ID SUPPLIER_ID&nbsp; &nbsp;CUM_COVP&nbsp; &nbsp;CUM_COVS<BR>---------- ----------- ---------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp;1774&nbsp; &nbsp;&nbsp; &nbsp;103088&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0<BR>&nbsp; &nbsp;&nbsp; &nbsp;1775&nbsp; &nbsp;&nbsp; &nbsp;103087&nbsp; &nbsp; 1473.25&nbsp; &nbsp;&nbsp;&nbsp;2946.5<BR>&nbsp; &nbsp;&nbsp; &nbsp;1794&nbsp; &nbsp;&nbsp; &nbsp;103096 1702.77778 2554.16667<BR>&nbsp; &nbsp;&nbsp; &nbsp;1825&nbsp; &nbsp;&nbsp; &nbsp;103093&nbsp; &nbsp; 1926.25 2568.33333<BR>&nbsp; &nbsp;&nbsp; &nbsp;2004&nbsp; &nbsp;&nbsp; &nbsp;103086&nbsp; &nbsp;&nbsp;&nbsp;1591.4&nbsp; &nbsp; 1989.25<BR>&nbsp; &nbsp;&nbsp; &nbsp;2005&nbsp; &nbsp;&nbsp; &nbsp;103086&nbsp; &nbsp;&nbsp;&nbsp;1512.5&nbsp; &nbsp;&nbsp; &nbsp; 1815<BR>&nbsp; &nbsp;&nbsp; &nbsp;2416&nbsp; &nbsp;&nbsp; &nbsp;103088 1475.97959 1721.97619<BR>.<BR>.<BR><BR><BR>COUNT <BR>功能描述：对一组内发生的事情进行累积计数，如果指定*或一些非空常数，count将对所有行计数，如果指定一个表达式，count返回表达式非空赋值的计数，当有相同值出现时，这些相等的值都会被纳入被计算的值；可以使用DISTINCT来记录去掉一组中完全相同的数据后出现的行数。<BR>SAMPLE：下面例子中计算每个员工在按薪水排序中当前行附近薪水在[n-50,n+150]之间的行数，n表示当前行的薪水<BR>例如，Philtanker的薪水2200，排在他之前的行中薪水大于等于2200-50的有1行，排在他之后的行中薪水小于等于2200＋150的行没有，所以count计数值cnt3为2（包括自己当前行）；cnt2值相当于小于等于当前行的SALARY值的所有行数<BR><BR>SELECT last_name, salary, COUNT(*) OVER () AS cnt1,<BR>&nbsp; &nbsp;&nbsp; &nbsp; COUNT(*) OVER (ORDER BY salary) AS cnt2,<BR>&nbsp; &nbsp;&nbsp; &nbsp; COUNT(*) OVER (ORDER BY salary RANGE BETWEEN 50 PRECEDING<BR>&nbsp; &nbsp;&nbsp; &nbsp; AND 150 FOLLOWING) AS cnt3 FROM employees;<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;&nbsp; &nbsp; CNT1&nbsp; &nbsp;&nbsp; &nbsp; CNT2&nbsp; &nbsp;&nbsp; &nbsp; CNT3<BR>------------------------- ---------- ---------- ---------- ----------<BR>Olson&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2100&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;107&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3<BR>Markle&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2200&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;107&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR>Philtanker&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2200&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;107&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR>Landry&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2400&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;107&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 5&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 8<BR>Gee&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2400&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;107&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 5&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 8<BR>Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;107&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;11&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;10<BR>Patel&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2500&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;107&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;11&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;10<BR>.<BR>.<BR><BR><BR>CUME_DIST <BR>功能描述：计算一行在组中的相对位置，CUME_DIST总是返回大于0、小于或等于1的数，该数表示该行在N行中的位置。例如，在一个3行的组中，返回的累计分布值为1/3、2/3、3/3<BR>SAMPLE：下例中计算每个工种的员工按薪水排序依次累积出现的分布百分比<BR><BR>SELECT job_id, last_name, salary, CUME_DIST() <BR>&nbsp; &nbsp;&nbsp; &nbsp; OVER (PARTITION BY job_id ORDER BY salary) AS cume_dist<BR>&nbsp;&nbsp;FROM employees&nbsp;&nbsp;WHERE job_id LIKE 'PU%';<BR><BR>JOB_ID&nbsp; &nbsp;&nbsp;&nbsp;LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp;&nbsp;CUME_DIST<BR>---------- ------------------------- ---------- ----------<BR>PU_CLERK&nbsp; &nbsp;Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.2<BR>PU_CLERK&nbsp; &nbsp;Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.4<BR>PU_CLERK&nbsp; &nbsp;Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.6<BR>PU_CLERK&nbsp; &nbsp;Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.8<BR>PU_CLERK&nbsp; &nbsp;Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>PU_MAN&nbsp; &nbsp;&nbsp;&nbsp;Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR><BR><BR>DENSE_RANK <BR>功能描述：根据ORDER BY子句中表达式的值，从查询返回的每一行，计算它们与其它行的相对位置。组内的数据按ORDER BY子句排序，然后给每一行赋一个号，从而形成一个序列，该序列从1开始，往后累加。每次ORDER BY表达式的值发生变化时，该序列也随之增加。有同样值的行得到同样的数字序号（认为null时相等的）。密集的序列返回的时没有间隔的数<BR>SAMPLE：下例中计算每个员工按部门分区再按薪水排序，依次出现的序列号（注意与RANK函数的区别）<BR><BR>SELECT d.department_id , e.last_name, e.salary, DENSE_RANK() <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;OVER (PARTITION BY e.department_id ORDER BY e.salary) as drank<BR>&nbsp;&nbsp;FROM employees e, departments d<BR>WHERE e.department_id = d.department_id<BR>&nbsp; &nbsp;AND d.department_id IN ('60', '90'); <BR><BR>DEPARTMENT_ID LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;&nbsp; &nbsp;DRANK<BR>------------- ------------------------- ---------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Lorentz&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 4200&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Austin&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Pataballa&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Ernst&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Hunold&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;9000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 4<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;90 Kochhar&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;17000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;90 De Haan&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;17000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;90 King&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;24000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR><BR><BR>FIRST <BR>功能描述：从DENSE_RANK返回的集合中取出排在最前面的一个值的行（可能多行，因为值可能相等），因此完整的语法需要在开始处加上一个集合函数以从中取出记录<BR>SAMPLE：下面例子中DENSE_RANK按部门分区，再按佣金commission_pct排序，FIRST取出佣金最低的对应的所有行，然后前面的MAX函数从这个集合中取出薪水最低的值；LAST取出佣金最高的对应的所有行，然后前面的MIN函数从这个集合中取出薪水最高的值<BR>SELECT last_name, department_id, salary,<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct)<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;OVER (PARTITION BY department_id) "Worst",<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct)<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;OVER (PARTITION BY department_id) "Best"<BR>&nbsp;&nbsp;FROM employees <BR>WHERE department_id in (20,80) <BR>ORDER BY department_id, salary;<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DEPARTMENT_ID&nbsp; &nbsp;&nbsp;&nbsp;SALARY&nbsp; &nbsp;&nbsp; &nbsp;Worst&nbsp; &nbsp;&nbsp; &nbsp; Best<BR>------------------------- ------------- ---------- ---------- ----------<BR>Fay&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 20&nbsp; &nbsp;&nbsp; &nbsp; 6000&nbsp; &nbsp;&nbsp; &nbsp; 6000&nbsp; &nbsp;&nbsp; &nbsp;13000<BR>Hartstein&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 20&nbsp; &nbsp;&nbsp; &nbsp;13000&nbsp; &nbsp;&nbsp; &nbsp; 6000&nbsp; &nbsp;&nbsp; &nbsp;13000<BR>Kumar&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Banda&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 6200&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Johnson&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 6200&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Ande&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 6400&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Lee&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 80&nbsp; &nbsp;&nbsp; &nbsp; 6800&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Tuvault&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 7000&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Sewall&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 80&nbsp; &nbsp;&nbsp; &nbsp; 7000&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Marvins&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 7200&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Bates&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 7300&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>.<BR>.<BR>.<BR><BR><BR>FIRST_VALUE&nbsp;&nbsp;<BR>功能描述：返回组中数据窗口的第一个值。<BR>SAMPLE：下面例子计算按部门分区按薪水排序的数据窗口的第一个值对应的名字，如果薪水的第一个值有多个，则从多个对应的名字中取缺省排序的第一个名字<BR><BR>SELECT department_id, last_name, salary, FIRST_VALUE(last_name)<BR>&nbsp;&nbsp;OVER (PARTITION BY department_id ORDER BY salary ASC ) AS lowest_sal<BR>&nbsp;&nbsp;FROM employees <BR>WHERE department_id in(20,30);<BR><BR>DEPARTMENT_ID LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY LOWEST_SAL<BR>------------- ------------------------- ---------- --------------<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Fay&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6000 Fay<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Hartstein&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 13000 Fay<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500 Colmenares<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600 Colmenares<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800 Colmenares<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900 Colmenares<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100 Colmenares<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11000 Colmenares<BR><BR><BR>LAG <BR>功能描述：可以访问结果集中的其它行而不用进行自连接。它允许去处理游标，就好像游标是一个数组一样。在给定组中可参考当前行之前的行，这样就可以从组中与当前行一起选择以前的行。Offset是一个正整数，其默认值为1，若索引超出窗口的范围，就返回默认值（默认返回的是组中第一行），其相反的函数是LEAD<BR>SAMPLE：下面的例子中列prev_sal返回按hire_date排序的前1行的salary值<BR><BR>SELECT last_name, hire_date, salary,<BR>&nbsp; &nbsp;&nbsp; &nbsp; LAG(salary, 1, 0) OVER (ORDER BY hire_date) AS prev_sal<BR>&nbsp;&nbsp;FROM employees<BR>WHERE job_id = 'PU_CLERK';<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;HIRE_DATE&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;PREV_SAL<BR>------------------------- ---------- ---------- ----------<BR>Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 18-5月 -95&nbsp; &nbsp;&nbsp; &nbsp; 3100&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0<BR>Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;24-7月 -97&nbsp; &nbsp;&nbsp; &nbsp; 2800&nbsp; &nbsp;&nbsp; &nbsp; 3100<BR>Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;24-12月-97&nbsp; &nbsp;&nbsp; &nbsp; 2900&nbsp; &nbsp;&nbsp; &nbsp; 2800<BR>Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;15-11月-98&nbsp; &nbsp;&nbsp; &nbsp; 2600&nbsp; &nbsp;&nbsp; &nbsp; 2900<BR>Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 10-8月 -99&nbsp; &nbsp;&nbsp; &nbsp; 2500&nbsp; &nbsp;&nbsp; &nbsp; 2600<BR><BR><BR>LAST <BR>功能描述：从DENSE_RANK返回的集合中取出排在最后面的一个值的行（可能多行，因为值可能相等），因此完整的语法需要在开始处加上一个集合函数以从中取出记录<BR>SAMPLE：下面例子中DENSE_RANK按部门分区，再按佣金commission_pct排序，FIRST取出佣金最低的对应的所有行，然后前面的MAX函数从这个集合中取出薪水最低的值；LAST取出佣金最高的对应的所有行，然后前面的MIN函数从这个集合中取出薪水最高的值<BR>SELECT last_name, department_id, salary,<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct)<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;OVER (PARTITION BY department_id) "Worst",<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct)<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;OVER (PARTITION BY department_id) "Best"<BR>&nbsp;&nbsp;FROM employees <BR>WHERE department_id in (20,80) <BR>ORDER BY department_id, salary;<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DEPARTMENT_ID&nbsp; &nbsp;&nbsp;&nbsp;SALARY&nbsp; &nbsp;&nbsp; &nbsp;Worst&nbsp; &nbsp;&nbsp; &nbsp; Best<BR>------------------------- ------------- ---------- ---------- ----------<BR>Fay&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 20&nbsp; &nbsp;&nbsp; &nbsp; 6000&nbsp; &nbsp;&nbsp; &nbsp; 6000&nbsp; &nbsp;&nbsp; &nbsp;13000<BR>Hartstein&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 20&nbsp; &nbsp;&nbsp; &nbsp;13000&nbsp; &nbsp;&nbsp; &nbsp; 6000&nbsp; &nbsp;&nbsp; &nbsp;13000<BR>Kumar&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Banda&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 6200&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Johnson&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 6200&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Ande&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 6400&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Lee&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 80&nbsp; &nbsp;&nbsp; &nbsp; 6800&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Tuvault&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 7000&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Sewall&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 80&nbsp; &nbsp;&nbsp; &nbsp; 7000&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Marvins&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 7200&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>Bates&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;80&nbsp; &nbsp;&nbsp; &nbsp; 7300&nbsp; &nbsp;&nbsp; &nbsp; 6100&nbsp; &nbsp;&nbsp; &nbsp;14000<BR>.<BR>.<BR>.<BR><BR><BR>LAST_VALUE <BR>功能描述：返回组中数据窗口的最后一个值。<BR>SAMPLE：下面例子计算按部门分区按薪水排序的数据窗口的最后一个值对应的名字，如果薪水的最后一个值有多个，则从多个对应的名字中取缺省排序的最后一个名字<BR>SELECT department_id, last_name, salary, LAST_VALUE(last_name)<BR>&nbsp; &nbsp; OVER(PARTITION BY department_id ORDER BY salary) AS highest_sal<BR>&nbsp;&nbsp;FROM employees <BR>WHERE department_id in(20,30);<BR><BR>DEPARTMENT_ID LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY HIGHEST_SAL<BR>------------- ------------------------- ---------- ------------<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Fay&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6000 Fay<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Hartstein&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 13000 Hartstein<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500 Colmenares<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600 Himuro<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800 Tobias<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900 Baida<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100 Khoo<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11000 Raphaely<BR><BR><BR>LEAD <BR>功能描述：LEAD与LAG相反，LEAD可以访问组中当前行之后的行。Offset是一个正整数，其默认值为1，若索引超出窗口的范围，就返回默认值（默认返回的是组中第一行）<BR>SAMPLE：下面的例子中每行的"NextHired"返回按hire_date排序的下一行的hire_date值<BR><BR>SELECT last_name, hire_date, <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;LEAD(hire_date, 1) OVER (ORDER BY hire_date) AS "NextHired" <BR>&nbsp;&nbsp;FROM employees WHERE department_id = 30;<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;HIRE_DATE NextHired<BR>------------------------- --------- ---------<BR>Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;07-DEC-94 18-MAY-95<BR>Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 18-MAY-95 24-JUL-97<BR>Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;24-JUL-97 24-DEC-97<BR>Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;24-DEC-97 15-NOV-98<BR>Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;15-NOV-98 10-AUG-99<BR>Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 10-AUG-99<BR><BR><BR>MAX <BR>功能描述：在一个组中的数据窗口中查找表达式的最大值。<BR>SAMPLE：下面例子中dept_max返回当前行所在部门的最大薪水值<BR><BR>SELECT department_id, last_name, salary, <BR>&nbsp; &nbsp;MAX(salary) OVER (PARTITION BY department_id) AS dept_max<BR>&nbsp; &nbsp;FROM employees WHERE department_id in (10,20,30);<BR><BR>DEPARTMENT_ID LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;DEPT_MAX<BR>------------- ------------------------- ---------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;10 Whalen&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4400&nbsp; &nbsp;&nbsp; &nbsp; 4400<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Hartstein&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 13000&nbsp; &nbsp;&nbsp; &nbsp;13000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Fay&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;13000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11000&nbsp; &nbsp;&nbsp; &nbsp;11000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100&nbsp; &nbsp;&nbsp; &nbsp;11000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900&nbsp; &nbsp;&nbsp; &nbsp;11000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800&nbsp; &nbsp;&nbsp; &nbsp;11000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600&nbsp; &nbsp;&nbsp; &nbsp;11000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500&nbsp; &nbsp;&nbsp; &nbsp;11000<BR><BR><BR>MIN <BR>功能描述：在一个组中的数据窗口中查找表达式的最小值。<BR>SAMPLE：下面例子中dept_min返回当前行所在部门的最小薪水值<BR><BR>SELECT department_id, last_name, salary, <BR>&nbsp; &nbsp;MIN(salary) OVER (PARTITION BY department_id) AS dept_min<BR>&nbsp; &nbsp;FROM employees WHERE department_id in (10,20,30);<BR><BR>DEPARTMENT_ID LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;DEPT_MIN<BR>------------- ------------------------- ---------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;10 Whalen&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4400&nbsp; &nbsp;&nbsp; &nbsp; 4400<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Hartstein&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 13000&nbsp; &nbsp;&nbsp; &nbsp; 6000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Fay&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp; 6000<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11000&nbsp; &nbsp;&nbsp; &nbsp; 2500<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100&nbsp; &nbsp;&nbsp; &nbsp; 2500<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900&nbsp; &nbsp;&nbsp; &nbsp; 2500<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800&nbsp; &nbsp;&nbsp; &nbsp; 2500<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600&nbsp; &nbsp;&nbsp; &nbsp; 2500<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500&nbsp; &nbsp;&nbsp; &nbsp; 2500<BR><BR><BR>NTILE <BR>功能描述：将一个组分为"表达式"的散列表示，例如，如果表达式=4，则给组中的每一行分配一个数（从1到4），如果组中有20行，则给前5行分配1，给下5行分配2等等。如果组的基数不能由表达式值平均分开，则对这些行进行分配时，组中就没有任何percentile的行数比其它percentile的行数超过一行，最低的percentile是那些拥有额外行的percentile。例如，若表达式=4，行数=21，则percentile=1的有5行，percentile=2的有5行等等。<BR>SAMPLE：下例中把6行数据分为4份<BR><BR>SELECT last_name, salary, <BR>&nbsp; &nbsp;&nbsp; &nbsp; NTILE(4) OVER (ORDER BY salary DESC) AS quartile FROM employees<BR>WHERE department_id = 100;<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;QUARTILE<BR>------------------------- ---------- ----------<BR>Greenberg&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 12000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>Faviet&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;9000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>Chen&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 8200&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR>Urman&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;7800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR>Sciarra&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 7700&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3<BR>Popp&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 6900&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 4<BR><BR><BR>PERCENT_RANK <BR>功能描述：和CUME_DIST（累积分配）函数类似，对于一个组中给定的行来说，在计算那行的序号时，先减1，然后除以n-1（n为组中所有的行数）。该函数总是返回0～1（包括1）之间的数。<BR>SAMPLE：下例中如果Khoo的salary为2900，则pr值为0.6，因为RANK函数对于等值的返回序列值是一样的<BR><BR>SELECT department_id, last_name, salary, <BR>&nbsp; &nbsp;&nbsp; &nbsp; PERCENT_RANK() <BR>&nbsp; &nbsp;&nbsp; &nbsp; OVER (PARTITION BY department_id ORDER BY salary) AS pr<BR>&nbsp;&nbsp;FROM employees<BR>WHERE department_id &lt; 50<BR>&nbsp;&nbsp;ORDER BY department_id,salary;<BR><BR>DEPARTMENT_ID LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;PR<BR>------------- ------------------------- ---------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;10 Whalen&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4400&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Fay&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;20 Hartstein&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 13000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;0.2<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;0.4<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;0.6<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;0.8<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;30 Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;40 Mavris&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6500&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0<BR><BR><BR>PERCENTILE_CONT <BR>功能描述：返回一个与输入的分布百分比值相对应的数据值，分布百分比的计算方法见函数PERCENT_RANK，如果没有正好对应的数据值，就通过下面算法来得到值：<BR>&nbsp; &nbsp; &nbsp; &nbsp; RN = 1+ (P*(N-1)) 其中P是输入的分布百分比值，N是组内的行数<BR>&nbsp; &nbsp; &nbsp; &nbsp; CRN = CEIL(RN)&nbsp;&nbsp;FRN = FLOOR(RN)<BR>if (CRN = FRN = RN) then <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (value of expression from row at RN)<BR>&nbsp; &nbsp; &nbsp; &nbsp; else<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (CRN - RN) * (value of expression for row at FRN) +<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (RN - FRN) * (value of expression for row at CRN)<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 注意：本函数与PERCENTILE_DISC的区别在找不到对应的分布值时返回的替代值的计算方法不同<BR><BR>SAMPLE：在下例中，对于部门60的Percentile_Cont值计算如下：<BR>&nbsp; &nbsp; &nbsp; &nbsp; P=0.7&nbsp;&nbsp;N=5 RN =1+ (P*(N-1)=1+(0.7*(5-1))=3.8 CRN = CEIL(3.8)=4&nbsp;&nbsp;<BR>FRN = FLOOR(3.8)=3 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; （4 - 3.8）* 4800 + (3.8 - 3) * 6000 = 5760<BR><BR>SELECT last_name, salary, department_id,<BR>&nbsp; &nbsp;&nbsp; &nbsp; PERCENTILE_CONT(0.7) WITHIN GROUP (ORDER BY salary) <BR>&nbsp; &nbsp;&nbsp; &nbsp; OVER (PARTITION BY department_id) "Percentile_Cont",<BR>&nbsp; &nbsp;&nbsp; &nbsp; PERCENT_RANK() <BR>&nbsp; &nbsp;&nbsp; &nbsp; OVER (PARTITION BY department_id ORDER BY salary) "Percent_Rank"<BR>&nbsp;&nbsp;FROM employees WHERE department_id IN (30, 60);<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY DEPARTMENT_ID Percentile_Cont Percent_Rank<BR>------------------------- ---------- ------------- --------------- ------------<BR>Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;0<BR>Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0.2<BR>Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0.4<BR>Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0.6<BR>Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 0.8<BR>Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1<BR>Lorentz&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 4200&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;5760&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;0<BR>Austin&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;5760&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;0.25<BR>Pataballa&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;5760&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;0.25<BR>Ernst&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;5760&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;0.75<BR>Hunold&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;9000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;5760&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;1<BR><BR><BR>PERCENTILE_DISC <BR>功能描述：返回一个与输入的分布百分比值相对应的数据值，分布百分比的计算方法见函数CUME_DIST，如果没有正好对应的数据值，就取大于该分布值的下一个值。<BR>注意：本函数与PERCENTILE_CONT的区别在找不到对应的分布值时返回的替代值的计算方法不同<BR><BR>SAMPLE：下例中0.7的分布值在部门30中没有对应的Cume_Dist值，所以就取下一个分布值0.83333333所对应的SALARY来替代<BR><BR>SELECT last_name, salary, department_id,<BR>&nbsp; &nbsp;&nbsp; &nbsp; PERCENTILE_DISC(0.7) WITHIN GROUP (ORDER BY salary )<BR>&nbsp; &nbsp;&nbsp; &nbsp; OVER (PARTITION BY department_id) "Percentile_Disc",<BR>&nbsp; &nbsp;&nbsp; &nbsp; CUME_DIST() OVER (PARTITION BY department_id ORDER BY salary)&nbsp; &nbsp;&nbsp; &nbsp;"Cume_Dist"<BR>&nbsp;&nbsp;FROM employees <BR>WHERE department_id in (30, 60);<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY DEPARTMENT_ID Percentile_Disc&nbsp;&nbsp;Cume_Dist<BR>------------------------- ---------- ------------- --------------- ----------<BR>Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3100 .166666667<BR>Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3100 .333333333<BR>Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3100&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.5<BR>Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3100 .666666667<BR>Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3100 .833333333<BR>Raphaely&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;11000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;30&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;3100&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>Lorentz&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 4200&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.2<BR>Austin&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.6<BR>Pataballa&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.6<BR>Ernst&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;.8<BR>Hunold&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;9000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;60&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR><BR><BR>RANK <BR>功能描述：根据ORDER BY子句中表达式的值，从查询返回的每一行，计算它们与其它行的相对位置。组内的数据按ORDER BY子句排序，然后给每一行赋一个号，从而形成一个序列，该序列从1开始，往后累加。每次ORDER BY表达式的值发生变化时，该序列也随之增加。有同样值的行得到同样的数字序号（认为null时相等的）。然而，如果两行的确得到同样的排序，则序数将随后跳跃。若两行序数为1，则没有序数2，序列将给组中的下一行分配值3，DENSE_RANK则没有任何跳跃。<BR>SAMPLE：下例中计算每个员工按部门分区再按薪水排序，依次出现的序列号（注意与DENSE_RANK函数的区别）<BR><BR>SELECT d.department_id , e.last_name, e.salary, RANK() <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;OVER (PARTITION BY e.department_id ORDER BY e.salary) as drank<BR>&nbsp;&nbsp;FROM employees e, departments d<BR>WHERE e.department_id = d.department_id<BR>&nbsp; &nbsp;AND d.department_id IN ('60', '90');<BR><BR>DEPARTMENT_ID LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;&nbsp; &nbsp;DRANK<BR>------------- ------------------------- ---------- ----------<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Lorentz&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 4200&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Austin&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Pataballa&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4800&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Ernst&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;6000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 4<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;60 Hunold&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;9000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 5<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;90 Kochhar&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;17000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;90 De Haan&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;17000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 1<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;90 King&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;24000&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3<BR><BR><BR>RATIO_TO_REPORT <BR>功能描述：该函数计算expression/(sum(expression))的值，它给出相对于总数的百分比，即当前行对sum(expression)的贡献。<BR>SAMPLE：下例计算每个员工的工资占该类员工总工资的百分比<BR><BR>SELECT last_name, salary, RATIO_TO_REPORT(salary) OVER () AS rr<BR>&nbsp;&nbsp;FROM employees<BR>WHERE job_id = 'PU_CLERK';<BR><BR>LAST_NAME&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;SALARY&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;RR<BR>------------------------- ---------- ----------<BR>Khoo&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3100 .223021583<BR>Baida&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;2900 .208633094<BR>Tobias&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2800 .201438849<BR>Himuro&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2600&nbsp;&nbsp;.18705036<BR>Colmenares&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 2500 .179856115<BR><BR><BR>REGR_ (Linear Regression) Functions <BR>功能描述：这些线性回归函数适合最小二乘法回归线，有9个不同的回归函数可使用。<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; REGR_SLOPE：返回斜率，等于COVAR_POP(expr1, expr2) / VAR_POP(expr2)<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; REGR_INTERCEPT：返回回归线的y截距，等于<BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp]]></description>
</item><item>
<title><![CDATA[UNIX与Windows 2000上Oracle的差异]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8441</link>
<author>blakestone</author>
<pubDate>2005/9/9 12:21:55</pubDate>
<description><![CDATA[作者：Ian Adam &amp; David Stien, SAIC Ltd <BR>日期：19-Dec-2003　<BR>出处：http://www.dbanotes.net<BR>翻译：Fenng<BR>
<HR>
<BR>
<H2>摘要</H2>
<P>ORACLE Database是广为人知的Unix硬件平台上的领先的数据库系统。ORACLE 用户和管理员因此熟悉 Unix平台上的 ORACLE 架构以及它上面的工具和技巧，并从他们的数据库得到最大的收益。相反，Windows上的 ORACLE 架构就不那么的被广为了解。这篇文章从一个 DBA 的角度考察了两个操作系统之间的关键的异同点。 </P>
<H2>简介</H2>
<P>在看了几本令人失望的这方面的图书之后，我们写了这篇文章。那些书的通病是试图做太多的事情--在细节上论述 Windows 和 ORACLE 。我们的这篇文章假定读者熟悉 Unix 平台上的ORACLE DBA 的工作。因此本文将分析两个平台上的 ORACLE 的关键的差异而不是从头教你 ORACLE 的技巧。我们不想把它作为你的一份详尽的指导或者是手册的替代品，事实上本文会鼓励你阅读一些手册。作为数据库服务器平台，它只会涉及一些 Unix 和 Windows 上相关的优点，这就是本文的目的。 </P>
<H2>范例</H2>
<P>这个例子使用 Linux 上的ORACLE 8i ，实例名字叫作 eighti 。Windows 2000 上面的 ORACLE 8i 的实例名字叫作 atei 。 </P>
<H2>客户端对 ORACLE 的访问 </H2>
<P>当客户端连接到 ORACLE 时，通常的来说ORACLE 服务器平台与客户端的应用无关。这实际上很难说清。ORACLE DBA和系统管理人员更关心操作系统平台，他们有的时候会基于需求（如运行时间和可扩展性）选择平台。更通常的情况下，他们接受（或是接手）给定的平台并学习从中得到最大收益。 </P>
<H2>关于 WINDOWS 2000 </H2>
<P>值得一提的是 Windows 2000 是从 Windows NT 升级而来。在这两个操作系统之间有很多的相似点， Windows 2000 也有些新的特性。微软从 NT4.0 的升级途径见下表。 </P>
<P>两个系统间有很多相似点：</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD><STRONG>NT 4.0</STRONG></TD>
<TD><STRONG>Windows 2000</STRONG></TD></TR>
<TR>
<TD>NT 4.0 Workstation</TD>
<TD>Windows 2000 Professional</TD></TR>
<TR>
<TD>NT 4.0 Server</TD>
<TD>Windows 2000 Server</TD></TR>
<TR>
<TD>NT 4.0 Enterprise Edition</TD>
<TD>Windows 2000 Advanced server</TD></TR>
<TR>
<TD>Unix</TD>
<TD>Windows 2000 Datacenter server </TD></TR></TBODY></TABLE></BLOCKQUOTE>
<H2>ORACLE 后台进程</H2>
<P>下面这句话对于用过 ORACLE 的人来说是会很熟悉的： </P>
<BLOCKQUOTE>每一个运行着的 ORACLE 数据库都对应一个 ORACLE 实例，当一个数据库在数据库服务器(不考虑机器的类型) 上启动的时候，ORACLE 分配一块叫做 System Global Area (SGA) 的内存区域并启动一个或者多个ORACLE 进程。SGA 和 ORACLE 进程合起来称作 ORACLE 实例。<BR>--摘自 ORACLE 8i Concepts [4 L Leverenz, 1999] 。 </BLOCKQUOTE>
<P>处理后台进程是放在首位的，也是不同的操作系统之间最明显的差异。 </P>
<H2>ORACLE 在 UNIX 上的后台进程</H2>
<P>任何连接到 UNIX 的用户都可以很容易的察看 ORACLE 的后台进程： </P>
<BLOCKQUOTE><PRE>% ps -ef|grep eighti|grep -v grep 

oracle8 18451 1 0 16:37:18 ? 0:00 ora_pmon_eighti 
oracle8 18453 1 0 16:37:19 ? 0:00 ora_dbw0_eighti 
oracle8 18457 1 0 16:37:19 ? 0:04 ora_ckpt_eighti 
oracle8 18461 1 0 16:37:19 ? 0:00 ora_reco_eighti 
oracle8 18455 1 0 16:37:19 ? 0:02 ora_lgwr_eighti 
oracle8 18459 1 0 16:37:19 ? 0:01 ora_smon_eighti
oracle8 19168 19167 0 16:43:46 ? 0:00 oracleeighti 
(DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq))) 
</PRE></BLOCKQUOTE>
<P>最后一行的 ORACLE 进程与一个SQL*Plus 会话相关，其他的进程都是后台进程。在 ORACLE 中我们可以通过输入 SQL*Plus 会话察看这些进程： </P>
<BLOCKQUOTE><PRE>SELECT SID, spid, osuser, s.program
  FROM v$process p, v$session s
 WHERE p.addr = s.paddr; 

SID SPID OSUSER PROGRAM 
------------------------------------------------------------------- 
1 18451 oracle8 oracle@saic02 (PMON) 
2 18453 oracle8 oracle@saic02 (DBW0) 
3 18455 oracle8 oracle@saic02 (LGWR) 
4 18457 oracle8 oracle@saic02 (CKPT) 
5 18459 oracle8 oracle@saic02 (SMON) 
6 18461 oracle8 oracle@saic02 (RECO) 
7 19168 oracle8 sqlplus@saic02(TNS V1-V3) 

7 rows selected. 
</PRE></BLOCKQUOTE>
<P>每一个后台进程都有一行，还有一行信息是与 SQL*Plus 会话相关的， SPID 对应相应的 UNIX 进程号。 </P>
<H2>在 WINDOWS2000 上的 ORACLE 后台进程 </H2>
<P>回到 WINDOWS 上，从操作系统中察看后台进程有些困难。从任务管理器中可能会看到运行着的应用（任务管理器的察看方法：在任务栏点击右键选择 " 任务管理器 " ）。在服务器上 ORACLE 可以是可用的，运行着的应用却是不可见的。进程表的确显示一个进程叫做 ORACLE.EXE ，察看 alert log 显示 ORACLE 的所有后台进程都是启动的： </P>
<BLOCKQUOTE><PRE>PMON started with pid=2 
DBW0 started with pid=3 
LGWR started with pid=4 
CKPT started with pid=5 
SMON started with pid=6 
RECO started with pid=7 
</PRE></BLOCKQUOTE>
<P>要看实际的后台进程，需要运行额外的软件，例如，进程察看器。该软件可以从 Windows 2000 CD 中得到（如果是 Windows NT 的话可以从资源包中得到）。 </P>
<P>在 Windows 2000 上， ORACLE 实例是作为一个单一的 Windows 2000 进程（ORACLE.EXE ）实现的。这个进程包括实例所需要实现的每个任务的线程。 </P>
<P>因此一个线程对应每个 ORACLE 后台进程。 ORACLE.EXE进程作为一个服务运行，可以从控制面板的服务中察看到 ORACLEServiceSID 。其他的服务也可以这样控制。 </P>
<P>这允许 ORACLE 在没有用户登录服务器的时候也持续的运行。对于共享主处理器资源的所有的进程来说， ORACLE 能够达到高速、低负荷的上下文切换。 </P>
<P>在 Unix 下显示 ORACLE 中的进程，我们也可以通过输入简单的 SQL 语句来达到。为了显示 PID 列， SQL 语句做了些轻微的改动。要注意 PID 匹配警告日志中报告的值。 </P>
<BLOCKQUOTE><PRE>SELECT s.SID, p.pid, p.spid signaled, s.osuser, s.program
  FROM v$process p, v$session s
 WHERE p.addr = s.paddr;

SID PID THREADID OSUSER PROGRAM 
---- ------- --------- --------------- --------------------
1 2 1088 SYSTEM ORACLE.EXE 
2 3 1172 SYSTEM ORACLE.EXE 
3 4 1180 SYSTEM ORACLE.EXE 
4 5 1192 SYSTEM ORACLE.EXE 
5 6 1212 SYSTEM ORACLE.EXE 
6 7 1220 SYSTEM ORACLE.EXE 
7 8 1200 Administrator SQLPLUSW.EXE 

7 rows selected. 
</PRE></BLOCKQUOTE>
<P>每一个后台进程都有一行，还有一行信息是与 SQL*Plus会话相关。程序名字并没有指明后台进程的名字，和在 Unix 中一样，这些名字可以通过和 v$bgprocess 连接得到。 </P>
<BLOCKQUOTE><PRE>SELECT s.SID SID, p.spid threadid, p.program processname, bg.NAME NAME
  FROM v$process p, v$session s, v$bgprocess bg
 WHERE p.addr = s.paddr AND p.addr = bg.paddr AND bg.paddr &lt;&gt; '00';

SID THREADID PROCESSNAME NAME 
---------- --------- --------------- ------------- 
1 1088 ORACLE.EXE PMON 
2 1172 ORACLE.EXE DBW0 
3 1180 ORACLE.EXE LGWR 
4 1192 ORACLE.EXE CKPT 
5 1212 ORACLE.EXE SMON 
6 1220 ORACLE.EXE RECO 

6 rows selected. 
</PRE></BLOCKQUOTE>
<H2>断开会话 </H2>
<P>提交 SQL 命令 ALTER SYSTEM DISCONNECT SESSION 可以断开会话。有的时候需要在操作系统级别断开会话，在 UNIX 上，通过 kill 命令实现，前面例子中的 SQL 会话可以通过输入 UNIX 命令断开： </P>
<BLOCKQUOTE><PRE>kill -9 19168 
</PRE></BLOCKQUOTE>
<P>在 Windows 2000 上可以用 orakill 断开一个会话。 orakill 是 Windows 平台上的 ORACLE 的一个特定命令，默认安装在 $ORACLE_HOME\bin 下。在命令行下输入 orakill 可以察看它的用法。前面例子中的 SQL*Plus 会话可以通过输入如下的命令断开： </P>
<BLOCKQUOTE><PRE>orakill atei 1200 
Kill of thread id 1200 in instance atei successfully signaled. 
</PRE></BLOCKQUOTE>
<P>在 Windows 2000 中，如果一个断开的会话标记为 "marked for kill" 但是没被删除， orakill 会终止它。不过要记住Kill一个后台进程总不是个好主意，尤其是 Windows 上，会导致进程崩溃，甚至导致数据库不可用。 </P>
<H2>Windows 2000 注册表</H2>
<P>和其他的 Windows 2000 中的应用那样， ORACLE 的大多数的设定都在注册表中。 你应该看看注册表中的 HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE 下面都有什么。这些参数中的一部分在后面会详细讨论。和 ORACLE 服务相关的参数和其他的服务一样存贮在同样的位置： HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services 。 </P>
<H2>环境变量</H2>
<P>在 Unix 中两个最重要的变量是 ORACLE_HOME 和 ORACLE_SID 。一旦这些变量设定的话，应用就可以运行并联接到本地数据库。 通常也把 $ORACLE_HOME/bin包含在 $PATH中以便在使用 ORACLE 工具（如： Sql*Plus ）的时候免去输入全路径的麻烦。 </P>
<P>Windows 2000 中可以打开命令行设定 ORACLE_SID 变量再联接到本地数据库。其他的值可以从注册表中得到。 </P>
<H2>MULTIPLE ORACLE HOMES </H2>
<P>Windows 2000 全面支持多个 ORACLE home 。以前在 Windows NT 上这是个主要的问题， 一直到 ORACLE 8.0.4 以后才开始支持。最初得对这一点的支持很差劲。 ORACLE Home Selector, ORACLE8i 的一个新的应用工具，改变环境路径，使选择的 ORACLE home 路径作为主的 home 。只是简单的改变系统路径，把 ORACLE 选择的 BIN 目录放在启动路径中。 </P>
<P>每一个 BIN 目录都有一个 ORACLE.KEY 文件，指明在注册表中 ORACLE 程序在哪里可以找 ORACLE_HOME 和其他的环境变量。如果在服务器上面只有一个数据库，通常在注册表中设定 ORACLE_SID 。不过，不要设定 ORACLE_HOME ，对于 ORACLE 产品来说根本不需要，可能会导致问题。 </P>
<H2>文件系统 </H2>
<P>多 ORACLE home 的支持允许在 Windows 上面实现 Unix 的 OFA 标准。这极大的简化了从 Unix 的过渡。 OFA 目录树的顶层的名字有差异，不过主要的子目录和文件名字在两种操作系统中都是一致的。 </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD>&nbsp; </TD>
<TD><STRONG>Unix </STRONG></TD>
<TD><STRONG>NT </STRONG></TD></TR>
<TR>
<TD>ORACLE_BASE </TD>
<TD>/oracle/app/oracle </TD>
<TD>D:\Oracle</TD></TR>
<TR>
<TD>ORACLE_HOME </TD>
<TD>/oracle/app/oracle/product/8.1.7</TD>
<TD>D:\Oracle\Ora817 </TD></TR>
<TR>
<TD>Admin directories </TD>
<TD>/oracle/app/oracle/admin </TD>
<TD>D:\Oracle\Admin </TD></TR>
<TR>
<TD>Database files </TD>
<TD>/db01/oradata/SID </TD>
<TD>D:\Oracle\Oradata\SID </TD></TR>
<TR>
<TD>&nbsp; </TD>
<TD>/db02/oradata/SID </TD>
<TD>F:\Oracle\Oradata\SID </TD></TR>
<TR>
<TD>&nbsp; </TD>
<TD>/db03/oradata/SID </TD>
<TD>G:\Oracle\Oradata\SID </TD></TR></TBODY></TABLE></BLOCKQUOTE>
<H2>服务管理器</H2>
<P>从 ORACLE 8i 开始，服务管理器的名字在不同的平台上都一致了，都叫做 svrmgrl 。以前在Windows NT 上 ORACLE 的执行文件名字随着版本变动而改变，对于那些在多平台上工作的人来说这很令人讨厌，尤其是在使用一些命令（ imp 、 exp 等）的时候。</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD><STRONG>ORACLE 服务器版本</STRONG></TD>
<TD><STRONG>Windows 服务器管理器可执行程序</STRONG></TD></TR>
<TR>
<TD>7.3</TD>
<TD>svrmgr23</TD></TR>
<TR>
<TD>8.0</TD>
<TD>svrmgr30</TD></TR>
<TR>
<TD>8.1</TD>
<TD>svrmgrl </TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>要注意 server manager 正在逐步被淘汰 ( 译者注： 9i 中彻底淘汰了 svrmgrl) ，一些额外的功能被加到了 SQL*Plus 中。</P>
<H2>数据库启动与关闭 </H2>
<P>在 Windows2000 上数据库可以通过启动相关的服务打开。通过控制面板的服务选项或者是通过命令行模式，如： net start OracleServiceatei 就可以打开相关服务。这依赖于一些注册表参数，我们在后面讨论。停止相关的服务，例如： net stop OracleServiceatei 可以关闭一个数据库。 </P>
<P>在所有的平台上， ORACLE8i 实例都可以从服务管理器（或者 SQL*Plus! ）中通过 startup 命令启动。在 Unix 中，这个命令启动后台进程并且打开数据库。它还生成了一个 Unix 特定文件，叫做 $ORACLE_HOME/dbs/lk &amp;DBNAME&gt;，这是个MOUNT 锁文件 [6 Metalink, 2000] 。这会阻止两个实例 mount 在同一数据库上，当不使用并行服务器的模式下，要使用不同的 ORACLE_SID 。原来这是个 0 长度文件，不过现在包含文本 'DO NOT DELETE THIS FILE!' 。不要试图通过查看这个文件来得知是否数据库是可用的，它不是很准确的。在 Windows 2000 中， startup 命令并不启动 ORACLE 服务，不过，如果服务已经运行的话，这将打开数据库。 </P>
<P>类似的，服务管理器 Server Manager 的 shutdown 命令在任何平台上都会关掉数据库，不过在Windows 2000 上它并不停掉服务。很有可能的情况就是 ORACLE 服务被启动但是数据库却关掉了。 </P>
<H2>UNIX 上的数据库的自动启动与关闭</H2>
<P>在 Unix 上， ORACLE 提供了 dbstart 和 dbshut 脚本以供使用。在 Linux 中 ORACLE 检测文件 /etc/oratab 来决定哪个数据库自动的启动 / 关闭。在 Solaris ( 和一些其他版本的 Unix) 中，检查 /var/opt/oracle/oratab 文件。要注意： 8.1.6 版本的 dbstart 有个 bug, 在 8.1.7 中已经被修复，察看 [7 Metalink, 2000] 有详细说明。 </P>
<P>在 Linux 上，作为 root 用户，在 /etc/rc.d/init.d 目录中创建一个一个名为 dbora 的文件。这个文件将会检查参数是否是 'start' 或者 'stop' 并且适当的执行 dbstart/dbshut ；通常也从这个脚本启动 listener 。再生成两个符号连接 /etc/rc.d/rc2.d/S99dbora 和 /etc/rc.d/rc0.d/K10dbora 。数据库在运行级 2( 多用户 ) 时通过 /etc/rc.d/rc2.d/S99dbora 启动 , 在系统关闭到运行级 0 的时候通过 /etc/rc.d/rc0.d/K10dbora 关闭数据库。在 Solaris 上，这个脚本的在 /etc/init.d 中而不是在 /etc/rc.d/init.d。 </P>
<P>要注意默认的 dbshut 执行了一个正常 (normal) 的关闭操作。在 Unix中可以通过编辑 $ORACLE_HOME/bin/dbshut 中的这一行来改变数据库的关闭模式。 </P>
<P>把 shutdown 修改成：shutdown immediate </P>
<P>如果启动一个已经运行的实例， dbstart 还会执行一个 shutdown abort 。在 dbstart script 脚本的顶部警告说 'It should ONLY be executed as part of the system boot procedure' 。这个脚本要常被复制、修改，这样在其它的时候使用才能足够安全。 </P>
<H2>WINDOWS 2000 上的数据库自动的启动与关闭 </H2>
<P>在以前的版本（ 8i ）中，当 oracle 的启动被一个额外的服务 ORACLEStartSID 处理，服务器的启动和关闭的时候 ORACLE 不能被自动的干净的关掉。从 ORACLE8i 开始， stop/start 功能成为了主要的 ORACLE 服务，并通过注册表控制。注意当 ORADIM 用于创建或者修改实例的时候，自动的在注册表中设定这些值。这些设置在 HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOMEID 键值下。 ID 号从 0 开始，每有一个额外的 ORACLE home 递增。 </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD><STRONG>参数</STRONG></TD>
<TD><STRONG>描述 </STRONG></TD></TR>
<TR>
<TD>ORA_SID_AUTOSTART</TD>
<TD>设定为 TRUE 的时候 ( 默认值 ) ， ORACLEServiceSID 启动的时候启动数据库。 </TD></TR>
<TR>
<TD>ORA_SID_PFILE</TD>
<TD>设定 INIT.ORA 参数文件的全路径。</TD></TR>
<TR>
<TD>ORA_SHUTDOWN</TD>
<TD>当设定为 TRUE 的时候，在当前任何 ORACLE home 下的任何数据库将 shutdown 。 </TD></TR>
<TR>
<TD>ORA_SID_SHUTDOWN</TD>
<TD>设定为 TRUE 的时候，关闭标记 SID 值的 ORACLE8i 数据库。</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>如果 SHUTDOWN 参数设定为 FALSE ，停掉 ORACLEServiceSID 将会 abort 的方式关闭实例，下次启动的时候要进行实例恢复。 </P>
<P>下面的可选参数可以在注册表中设为合适的值 </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD><STRONG>参数</STRONG></TD>
<TD><STRONG>描述</STRONG></TD></TR>
<TR>
<TD>ORA_SID_SHUTDOWNTYPE</TD>
<TD>指明数据库关闭模式 A (abort ）， I (immediate) ， N(normal) 。<BR>如果你不设定这个参数的话，默认的模式是 I (immediate) 。 </TD></TR>
<TR>
<TD>ORA_SID_SHUTDOWN_TIMEOUT</TD>
<TD>在一个 SID 停止前等待的最大时间。</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<H2>操作系统认证 </H2>
<P>OS 认证在两个平台间是相似的，参数文件中设定 os_authent_prefix 参数，创建用户都标记为 externally 。在 Windows2000 中创建用户要指定大写的域名并且用户名要在 " " 中，否则不起作用。如果你在注册表中把 OSAUTH_PREFIX_DOMAIN 设定成 FALSE 的话，你可以忽略掉域。客户机和服务器的机器还需要在 sqlnet.ora 中包含 sqlnet.authentication_services=(nts) 这一行。 </P>
<P>在 Windows 2000 中，可以允许一个域用户登陆到一个远程 pc 上，无需提供额外的密码就可以连接到数据库中。参见 [2 Kelly III,2000] 可以得到详细内容。 </P>
<H2>LISTENER</H2>
<P>在 Windows 2000 上面 listener 作为一个服务实现的，所以 listener 可以通过启动 ORACLETNSListener 服务来启动。两种平台上 listener 都可以从 lsnrctl 命令控制。在 Unix 上 lsnrctl start 启动 listener 进程；在 Windows 2000 启动 ORACLETNSListener 服务就可以。 如果 listener 第一次启动的时候没有 ORACLETNSListener 服务将创建它。如果从你的计算机中删除 ORACLE 的话， listener 服务要手工从注册表中删除。 </P>
<P>在两个平台上的 listener 都可以监听不同版本的数据库。在 win2000 中，在 LISTENER.ORA 中不需要 ORACLE_HOME 参数 ( 在 UNIX 中要使用到的），因为每个 SID 在 SERVER 中是唯一的。 listener 可以从注册表中得到正确的 ORACLE_HOME 。 </P>
<P>ORACLE8i 有个特性叫服务器注册， pmon 自动对 listener 注册信息。这意味着 Net8 listener 可以无需在 listener.ora 文件中设置就可以监听一个数据库。不过这样做的话， Enterprise Manager 要直到启动后才可以连接到数据库。所以这个例子不能用来启动一个远程的实例。 </P>
<P>通常最好在 listener.ora 中设置所有的实例以避免冲突，尤其在一个有多位 DBA 的站点中，可以避免我们提到的 Enterprise Manager 问题。 </P>
<H2>加长的 SID 名字 </H2>
<P>Windows NT 上的 ORACLE 7 实例名字有着 4 个字符长的限制，这可能会产生很晦涩的实例名--庆幸的是在8i 中 SID 名字已经加长了。不过在包括命名服务的几个场合中使用太长的实例名字也不总是很有用。在 Windows 2000 上面有个 bug ，限制了实例名字最长 15 个字符。 </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD>&nbsp; </TD>
<TD colSpan=3><STRONG>Unix操作系统 </STRONG></TD>
<TD colSpan=3><STRONG>NT 操作系统</STRONG></TD></TR>
<TR>
<TD>&nbsp; </TD>
<TD>数据库名长度</TD>
<TD colSpan=2>SID名字长度</TD>
<TD>数据库名长度</TD>
<TD>SID 名字长度</TD></TR>
<TR>
<TD>Oracle7 </TD>
<TD>8 </TD>
<TD colSpan=2>8 </TD>
<TD>8 </TD>
<TD>4 </TD></TR>
<TR>
<TD>Oracle8 </TD>
<TD>8 </TD>
<TD colSpan=2>8 </TD>
<TD>8 </TD>
<TD>4 </TD></TR>
<TR>
<TD>Oracle8i </TD>
<TD>8 </TD>
<TD colSpan=2>64 </TD>
<TD>8 </TD>
<TD>64 </TD></TR></TBODY></TABLE></BLOCKQUOTE>
<H2>数据库的创建</H2>
<P>当你在安装过程中的时候选择创建 ORACLE 8i 数据库，数据库生成助手就会通过 ORACLE Universal Installer 自动运行。在安装后它也可以作为一个单独的工具手工运行。用它还可以手工的输入 SID 代替默认的 ORCL ，默认的情况下，不在 ORACLE_HOME 下面创建数据库，完全遵循 OFA 的意图。 </P>
<P>建议你运行 Database Creation Assistant ，不过在最后一页选择[ Save information to a batch file ] (保存信息到一个批处理文件中)，再点击[完成]按钮。这会产生几个脚本。从不同的平台对比它们的内容很有趣的。在Unix 和 Windows 上的内容很相似，除了 windows 上对 oradim 的调用不同。第一次对它的调用产生了一个与ORACLE 数据库相关联的 ORACLE 服务：</P>
<BLOCKQUOTE><PRE>D:\ORACLE\Ora817\bin\oradim -new -sid ATEI -intpwd man -startmode manual 
-pfile "D:\ORACLE\admin\atei\pfile\initatei.ora"
</PRE></BLOCKQUOTE>
<P>第二次对 oradim 的调用把服务更改为自动启动： </P>
<BLOCKQUOTE><PRE>D:\ORACLE\Ora817\bin\oradim -edit -sid atei -startmode auto </PRE></BLOCKQUOTE>
<P>可以用这些文件作为创建其它数据库的模版。若你不使用上面建议的方式创建数据库的话， Database Creation Assistant 生成的这些文件和目录没什么大用处。在使用这些脚本创建额外的数据库之前，这些文件和目录不得实现创建。特别注明一下，脚本假定一个密码文件已经存在 , 密码文件可以用 orapwd 命令预创建 [2 H Kelly III, 2000] 。</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD colSpan=2><STRONG>Database Creation Assistant 创建的目录：</STRONG></TD></TR>
<TR>
<TD><STRONG>Windows 2000 </STRONG></TD>
<TD><STRONG>Unix </STRONG></TD></TR>
<TR>
<TD>ORACLE_BASE = D:\oracle </TD>
<TD>ORACLE_BASE = /db01/app/oracle </TD></TR>
<TR>
<TD>ORACLE_BASE\oradata\atei </TD>
<TD>$ORACLE_BASE/oradata/eighti </TD></TR>
<TR>
<TD>ORACLE_BASE\oradata\atei\archive </TD>
<TD>$ORACLE_BASE/oradata/eighti/archive </TD></TR>
<TR>
<TD>ORACLE_BASE\admin\atei </TD>
<TD>$ORACLE_BASE/admin/eighti </TD></TR>
<TR>
<TD colSpan=2>还有这些子文件夹：sadhoc bdump cdump create exp pfile udump </TD></TR></TBODY></TABLE><BR><BR>
<TABLE>
<TBODY>
<TR>
<TD width=480 colSpan=2><STRONG>通过 Database Creation Assistant 创建 / 改动的文件：</STRONG> </TD></TR>
<TR>
<TD><STRONG>Windows 2000 </STRONG></TD>
<TD><STRONG>Unix </STRONG></TD></TR>
<TR>
<TD>ORACLE_HOME = D:\oracle\ora817 </TD>
<TD>ORACLE_HOME = /db01/app/oracle/product/8.1.7 </TD></TR>
<TR>
<TD>ORACLE_HOME\database\PWDatei.ora </TD>
<TD>$ORACLE_HOME/dbs/orapweighti.ora </TD></TR>
<TR>
<TD>ORACLE_BASE\admin\atei\pfile\initatei.ora </TD>
<TD>$ORACLE_BASE/admin/eighti/pfile/initeighti.ora </TD></TR>
<TR>
<TD>ORACLE_HOME\database\initatei.ora <BR>包含一行 <BR>IFILE='d:\oracle\admin\atei\pfile\initatei.ora‘ </TD>
<TD>$ORACLE_HOME/dbs/initeighti.ora <BR>符号链接到： <BR>/db01/app/oracle/ admin/eighti/pfile/initeighti.ora </TD></TR>
<TR>
<TD>添加到 tnsnames.ora 的条目 </TD>
<TD>添加到 tnsnames.ora 的条目 </TD></TR>
<TR>
<TD>添加到 listener.ora 的条目 </TD>
<TD>添加到 listener.ora 的条目 </TD></TR>
<TR>
<TD>windows 没有相关的操作 </TD>
<TD>添加项目到 oratab &gt;</TD></TR></TBODY></TABLE><BR><BR>
<TABLE>
<TBODY>
<TR>
<TD colSpan=3><STRONG>通过 Database Creation Assistant 创建的脚本：</STRONG></TD></TR>
<TR>
<TD><STRONG>Windows 2000 </STRONG></TD>
<TD><STRONG>Unix </STRONG></TD>
<TD><STRONG>注释 </STRONG></TD></TR>
<TR>
<TD>atei.bat </TD>
<TD>eighti </TD>
<TD>调用其它脚本 , 在 Windows 上还可以调用 ORADIM </TD></TR>
<TR>
<TD>ateirun.sql </TD>
<TD>eightirun.sh </TD>
<TD>包含创建数据库的语句 </TD></TR>
<TR>
<TD>ateirun1.sql </TD>
<TD>eightirun1.sh </TD>
<TD>创建表空间 / 创建回滚段 不创建系统中的第二个回滚段</TD></TR>
<TR>
<TD>N/A </TD>
<TD>eightirun2.sh </TD>
<TD>额外的脚本(如,catproc ) , <BR>这些在 Windows 上从 ateirun1.sql 中运行</TD></TR>
<TR>
<TD>ateisqlplus.sql </TD>
<TD>eightisqlplus.sh </TD>
<TD>添加 SQL*Plus 帮助 <BR>@c:\oracle\ora817\sqlplus\admin\help\helpbld.sql helpus.sql </TD></TR>
<TR>
<TD>ateialterTablespace.sql</TD>
<TD>eightialterTablespace.sh </TD>
<TD>为 SYSTEM 用户更改默认的和临时的表空间</TD></TR>
<TR>
<TD>ateireplicate.sql ateijava.sql <BR>ateiordinst.sql <BR>ateiiMedia.sql <BR>ateidrsys.sql <BR>ateicontext.sql <BR>ateispatial1.sql <BR>ateitimeseries.sql <BR>ateivirage.sql <BR></TD>
<TD>eightireplicate.sh eightijava.sh <BR>eightiordinst.sh <BR>eightiiMedia.sh <BR>eightidrsys.sh <BR>eighticontext.sh <BR>eightispatial1.sh <BR>eightitimeseries.sh <BR>eightivirage.sh </TD>
<TD>各种脚本，只有在你选择相应的选项的时候才会生成。</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>远程挂接(mount)的文件系统，如 UNIX 上的 NFS 和 Windows 2000 上 UNC ，在两个平台上都不支持。</P>
<H2>ORACLE 的安装 </H2>
<P>ORACLE8i 通过新的基于 Java 的 ORACLE Universal Installer (OUI) 来安装，在所有的平台上都有一样的界面 [1 M Cyran, 1999] 。上面这句话是对的，不过一些小的差异要注明。在 Unix 上需要 X 兼容的显示能力, 或者是在客户机的工作站上 有一个象 Exceed 这样的应用。在 Windows2000 上安装器可以直接运行。 </P>
<P>在 Unix 中有许多手工设定的任务，在 Windows 2000 是不需要的。尤其是你不必手工设定环境变量。你不必生成一个管理数据库的 Unix dba 组，不必设定一个 UNIX 来为用户运行 ORACLE Universal Installer 或者是一个叫 oracle 的用户来安装或者升级 ORACLE 。在 Unix 中 ORACLE 可以重联接而在 Windows 2000 则不能。 </P>
<P>在 Windows 2000 中，用户必须是管理员（ administrator ）组的成员才可以安装数据库。在 ORACLE 8i 数据库安装后自动的创建 ORA_DBA 一个本地组。这个组的成员自动接受 SYSDBA 的权限。推荐在定制安装的时候选择安装 Administration Assistant for Windows ，要注意每个服务器只能安装这个软件的一个版本。 </P>
<P>ORACLE 8.1.7 for Solaris 是 2CD 的。切换到第二张 CD 不象手册上说的那么容易。察看 [10 Metalink, 2001] 可以得到具体内容。 </P>
<P>Windows 上的安装指导可以看 [3 Kennedy, 2000] 。《ORACLE Universal Installer 概念指导》没包括在 ORACLE8i 服务器联机文档中，不过在 ORACLE Universal Installer 安装的过程中自动的安装在你的硬盘中了。 </P>
<H2>Windows 上的数据库管理助手 </H2>
<P>Windows 上的 ORACLE 管理助手是个 GUI 工具，从 Windows 内建的 MMC （微软管理控制台）中运行 。 ORACLE 的 Windows 管理助手把几个常用的数据库管理工作集合到了一个工具中。可以使你在 Windows 中简单进行创建数据库管理员、操作员、用户和角色的工作。还可以用来管理 ORACLE 数据库服务和 ORACLE 数据库的启动与关闭的设置，编辑注册表参数设定，并察看 ORACLE 进程信息。 </P>
<H2>自动任务 </H2>
<P>在 Unix 上，象备份这样的自动任务是通过 cron 运行 Shell 脚本来做到的。在 Windows2000 上使用调度任务来定期运行批处理文件。这个调度要比以前的 Windows NT 上的 AT 调度命令要更有弹性。它允许一个带有用户上下文（ context ）而不是系统用户的任务运行，并且它允许对任务赋予权限。批处理脚本语言限制性很大，所以值得好好的弄一下 Perl [9 O'Reilly, 2000] 。在 Windows 2000 中当手工运行热备份的时候，ORACLE 提供了一个命令叫做 OCOPY ，用来拷贝文件到另一个磁盘位置，也可以备份到磁带上面。标准的 Windows 命令（如 COPY ）不拷贝一个打开的文件 ( 数据库的数据文件都是打开的 ) 。 </P>
<H2>调整与诊断 </H2>
<P>在 Windows 2000 上面可用来调试操作系统的工具很少，不过我们也要说点可以做的事情。 </P>
<P>交互的前台应用程序在 Windows2000 的安装过程中就指定了默认的优先级。为了阻止前台应用程序占用了额外的处理器时间，影响 ORACLE8i 数据库 , 去掉它的优先级，这可以通过系统控制面版的高级选项来做到。 </P>
<P>在 Unix 中，共享内存和信号量的设定通常需要通过 /etc/system来更改。在 Windows 2000上这样做没有必要，而且也不容易改动。 </P>
<P>针对 Windows 的 ORACLE 性能监视器是 Windows 2000 性能监视器预载入的 ORACLE8i 数据库性能元件。如果你没看到这些东西，试着这个命令来改变性能监视器的设定 : </P>
<BLOCKQUOTE><PRE>operfcfg -u system -p manager -d atei 
</PRE></BLOCKQUOTE>
<P>Windows NT 的 ORACLE 性能监视器允许你一次只监视一个数据库实例。上述的命令可以在数据库间切换。在 Windows 2000 中， ORACLE 和对待通常的 alert 和 trace 文件一样把信息写到事件日志中，这些信息可以通过标准的事件查看器读取。在 Windows 2000 中 dbverify (dbv) 可以用来检查联机数据文件，和 Unix 中的功能一样。而在以前的 Windows 中， dbv 只对关闭的数据库或是备份文件起作用。 </P>
<H2>总结 </H2>
<P>对于一个熟悉 Unix 上的 ORACLE DBA 来说，这篇文章描述了 ORACLE 在 Windows 2000 上的的主要的差别。可以看到 ORACLE 已经作了很多的努力使这两个平台上的 ORACLE 尽可能的相似，不过还没有完全的去除差别。这篇文章还是值得一看的。 </P>
<H2>关于作者 </H2>
<BLOCKQUOTE>
<P>David Stien and Ian Adam are both ORACLE8i Certified Database Administrators working for SAIC's Database Management Practice. They are both based in Aberdeen, Scotland. They are practising DBAs who provide ORACLE database support and development Services for customer databases on several different platforms. </P>
<P>Ian is a Chartered Engineer and Microsoft Certified Database Administrator with over ten years experience of ORACLE products. Ian can be reached by email at Ian.Adam@saic.com </P>
<P>David is a Chemistry Graduate with an MSc in Information Systems, Linux is his desktop operating system of choice. David can be reached by email at David.Stien@saic.com </P></BLOCKQUOTE>
<P><BR>&nbsp;</P>
<H2>参考信息</H2>
<P><BR>&nbsp;</P><PRE>[1] Cyran M, "Getting to Know ORACLE8i , Release 2 (8.1.6)", 
ORACLE Corporation December 1999, Part No. A76962-01 

[2] Kelly H III, Kennedy M, Rothenberg T, Slattery H, 
"ORACLE8i Administrator's Guide, Release 2 (8.1.6) for Windows NT" 
ORACLE Corporation 2000, Part No. A73008-01 

[3] Kennedy M, "ORACLE8i Installation Guide, Release 3 (8.1.7) for Windows NT" 
ORACLE Corporation November 2000, Part No. A85302-01 

[4] Leverenz L, Rehfield D, Baird C "ORACLE 8i Concepts Release 2 (8.1.6)" 
ORACLE Corporation December 1999, Part No. A76965-01 

[5] Metalink, "ORACLE Database Server product support Matrix for Windows 2000", 
ORACLE Corporation, http://metalink.oracle.com Note:77627.1 

[6] Metalink, "LKdbname - The MOUNT Lock File", 
ORACLE Corporation 2000, http://metalink.oracle.com Note:50594.1 

[7] Metalink, "WARNING: "dbstart" does not work with 8.1.6 Instances", 
ORACLE Corporation 2000, http://metalink.oracle.com Note:98418.1 

[8] Microsoft, "Windows 2000 Datacenter Server", 
Microsoft Corporation 2000 
Http://www.microsoft.com/windows2000/datacenter/default.asp 

[9] O'Reilly, "The Source for Perl", O'Reilly &amp; Associates Inc 2000, 
http://www.perl.com/pub/

[10] Metalink, "ALERT: Cannot Mount Second CD During 8.1.7 Installation", 
ORACLE Corporation, 
http://metalink.oracle.com Note: 120801.1 
</PRE>]]></description>
</item><item>
<title><![CDATA[书写历史的甲骨文--ORACLE公司传奇]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8440</link>
<author>blakestone</author>
<pubDate>2005/9/9 12:11:44</pubDate>
<description><![CDATA[整理：Fenng <BR>日期：09-Sep-2004 　 <BR>出处：<A href="http://www.dbanotes.net/">http://www.dbanotes.net</A> <BR>版本：1.01 (本文已经发表在《程序员》杂志) <BR>
<HR>
<BR>
<H2>ORACLE公司之起源</H2><BR>很难想象，ORACLE公司的这一段传奇居然要从<ACRONYM title="International Business Machines">IBM</ACRONYM>开始。 <BR><BR>1970年的6月，<ACRONYM title="International Business Machines">IBM</ACRONYM>公司的研究员埃德加·考特 （Edgar Frank Codd） 在 Communications of ACM 上发表了那篇著名的《大型共享数据库数据的关系模型》（A Relational Model of Data for Large Shared Data Banks）的论文。这是数据库发展史上的一个转折。要知道，当时还是层次模型和网状模型的数据库产品在市场上占主要位置。从这篇论文开始，拉开了关系型数据库软件革命的序幕。 <BR><BR>虽然早在1970年就诞生了关系模型理论，但是市场上迟迟不见关系型数据库管理软件的推出。主要原因是很多反对者认为关系型数据库速度太慢，比不上当时的层次式数据库。值得好笑的是，<ACRONYM title="International Business Machines">IBM</ACRONYM>虽然1973年就启动了System R的项目来研究关系型数据库的实际可行性，也没有及时推出这样的产品，因为当时<ACRONYM title="International Business Machines">IBM</ACRONYM>的的IMS（著名的层次型数据库）市场不错，如果推出关系型数据库，牵涉到<ACRONYM title="International Business Machines">IBM</ACRONYM>很多人的自身利益。再者，<ACRONYM title="International Business Machines">IBM</ACRONYM>庞大复杂的官僚机构处在决策上远不那么灵活。 <BR><BR>1977年6月，Larry Ellison与Bob Miner和Ed Oates在硅谷共同创办了一家名为软件开发实验室（Software Development Laboratories，SDL）的计算机公司（ORACLE公司的前身）。那个时候，32岁的Larry Ellison，这个读了三家大学都没能毕业的辍学生，还只是一个普通的软件工程师。公司创立之初，Miner是总裁，Oates为副总裁，而Ellison，因为一个合同的事情，还在另一家公司上班。没多久，第一位员工Bruce Scott（用过ORACLE数据库软件的人都知道有个Scott用户的吧？没错，就是这个Scott，至于Scott用户的密码Tiger，那是Scott养的猫的名字）加盟进来，在Miner和Oates有些厌倦了那种合同式的开发工作后，他们决定开发通用软件，不过们还不知道自己能开发出来什么样的产品。Oates最先看到了埃德加·考特的那篇著名的论文连同其他几篇相关的文章并推荐Ellison和Miner也阅读一下。Ellison和Miner预见到数据库软件的巨大潜力（跟着<ACRONYM title="International Business Machines">IBM</ACRONYM>走，没错），于是，SDL开始策划构建可商用的关系型数据库管理系统（<ACRONYM title="Relational Database Mangement System">RDBMS</ACRONYM>）。 <BR>
<P align=center><IMG alt="Oracle Company Gang of four" src="http://www.dbanotes.net/Images/Oracle_Gang_of_4.jpg"> <BR>图1 左起 Ed Oates、Bruce Scott、Bob Miner、Larry Ellison</P><BR>很快他们就弄出来一个不太像样的产品，或者具体的说，更像一个Demo。根据Ellison和Miner他们在前一家公司从事的一个由中央情报局投资的项目代码,他们把这个产品命名为ORACLE。因为他们相信，ORACLE（字典里的解释有“神谕, 预言”之意）是一切智慧的源泉。1979年，SDL更名为关系软件有限公司（Relational Software，Inc.，<ACRONYM title="Relational Software，Inc.">RSI</ACRONYM>），毕竟“软件开发实验室”不太像一个大公司的名字。1983年，为了突出公司的核心产品，<ACRONYM title="Relational Software，Inc.">RSI</ACRONYM>再次更名为ORACLE。 <BR><BR>
<P align=center><IMG height=415 alt="Oracle Company" src="http://www.dbanotes.net/Images/Oracle_Company.jpg" width=553> <BR>图2 美国 Oracle 公司总部一瞥</P><BR>
<HR>
<BR>
<H2>发展与壮大</H2><BR>RSI在1979年的夏季发布了可用于<ACRONYM title="Digital Equipment Corporation">DEC</ACRONYM>公司的<ACRONYM title="Progammable Data Processor">PDP</ACRONYM>-11计算机上的商用ORACLE产品，这个数据库产品整合了比较完整的<ACRONYM title="Structured Query Language">SQL</ACRONYM>实现，其中包括子查询、连接及其他特性。但不得不说，软件不是很稳定，并缺少事务处理这样的重要功能。出于市场策略，公司宣称这是该产品的第二版，但却是实际上的第一版。之所以被命名为第2版而不是第1版，是因为Ellison认为潜在的客户更愿意购买第2个版本，而不是初始版本。（虽然这样做有些不太诚实，还是要承认这是个十分高明的技巧。到现在还有一些公司把自己卖给客户的版本叫做1.0 ，学学1979年的ORACLE吧！）多年以后的今天，ORACLE公司声称是他们第一个提供了第一个<ACRONYM title="Structured Query Language">SQL</ACRONYM>关系型数据库管理系统。 <BR><BR>虽然软件不是很好，但是客户还是有的。美国中央情报局迫不及待的想买一套这样的软件来满足他们的需求。但在咨询了<ACRONYM title="International Business Machines">IBM</ACRONYM>公司之后发现<ACRONYM title="International Business Machines">IBM</ACRONYM>没有可以商用的产品，他们联系了<ACRONYM title="Relational Software，Inc.">RSI</ACRONYM>。于是<ACRONYM title="Relational Software，Inc.">RSI</ACRONYM>有了第一个客户。在当时，政府和军方的机构往往同时有几种计算机，而那时还没有什么“软件可移植”这样的说法，当然，也几乎没有具有这样的能力的应用软件。也就是说，给<ACRONYM title="Progammable Data Processor">PDP</ACRONYM>-11开发的ORACLE数据库不能用在<ACRONYM title="International Business Machines">IBM</ACRONYM>主机和<ACRONYM title="Digital Equipment Corporation">DEC</ACRONYM>的<ACRONYM title="Virtual Address eXtended">VAX</ACRONYM>上。很快用户就表现出来这样的需求：ORACLE能否同时在不同的操作系统上运行？这给<ACRONYM title="Relational Software，Inc.">RSI</ACRONYM>带来了新的挑战（主要是Miner和Scott）。70年代末期和80年代早期的软件一般都设计成在单一操作系统上运行，具有可移植能力的软件很少。 <BR><BR>1983年3月，<ACRONYM title="Relational Software，Inc.">RSI</ACRONYM>发布了ORACLE第三版。Miner和Scott历尽艰辛用C语言重新写就这一版本。要知道，C语言当时推出不久，用它来写ORACLE软件也是具有一定的风险的，但除此之外，别无他法。很快就证明了这样做是多么的正确:C编译器便宜而又有效，还有很好的移植性。从现在起，ORACLE产品有了一个关键的特性：<STRONG>[可移植性]</STRONG>。ORACLE第3版还推出了<ACRONYM title="Structured Query Language">SQL</ACRONYM>语句和事务处理的“原子性”--<ACRONYM title="Structured Query Language">SQL</ACRONYM>语句要么全部成功，要么全部失败，事务处理要么全部提交，要么全部回滚。ORACLE第3版还引入了非阻塞查询，使用存储在<STRONG>"Before Image File"</STRONG>中的数据来查询和回滚事务，从而避免了读锁定（read lock）的使用（虽然通过使用表级锁定限制了它的吞吐量）。同样是1983年，<ACRONYM title="International Business Machines">IBM</ACRONYM>发布了姗姗来迟的Database 2（<ACRONYM title="Database 2">DB2</ACRONYM>），但只可在MVS上使用。不管怎么说，ORACLE已经占取了先机。 <BR><BR>在开发第三版还没有结束的时候，Scott离开了ORACLE。当时用C语言改写ORACLE的压力很大，无休止的软件调试终于让Scott不堪重负，选择了一走了之。把剩下的重担交给了Miner一个人。在出售了自己的%4的股票之后，Scott 后来创建了Gupta公司（现更名为Centura Software）和PointBase公司（提供百分之百纯Java嵌入式数据库），都是开发和数据库相关的产品。多年后有人问到他的%4的ORACLE股票的时候，Scott，这个曾经给ORACLE写出第一行代码的技术高手，也只能报以一笑了。如果能坚持下来，那是一笔几亿美金的财富。不过当时的Scott没有那么多的想法，他只是太累了。 <BR><BR>
<P align=center><BR><IMG height=76 alt="Bruce Scott" src="http://www.dbanotes.net/Images/Scott.jpg" width=65> <BR>图3 Bruce Scott 现在是PointBase公司的创办者之一</P><BR>ORACLE最先将其软件移植到<ACRONYM title="Digital Equipment Corporation">DEC</ACRONYM> <ACRONYM title="Virtual Address eXtended">VAX</ACRONYM>计算机上的VMS操作系统上。早在1979年公司就已经雇了一位<ACRONYM title="Digital Equipment Corporation">DEC</ACRONYM>公司的技术高手Robot Brandt进行<ACRONYM title="Virtual Address eXtended">VAX</ACRONYM>上ORACLE的开发。开始的时候资金有限，只能到加州大学伯克利分校去蹭机器进行开发，后来好一些，但机器也是借来的。尽管困难重重，Brandt还是比较成功的完成了移植工作。随着<ACRONYM title="Virtual Address eXtended">VAX</ACRONYM>小型机的大量销售乃至供不应求，ORACLE软件也成为<ACRONYM title="Virtual Address eXtended">VAX</ACRONYM>上最受欢迎的程序。这一点要归功于Larry对市场的先知先觉。如果说，是<ACRONYM title="International Business Machines">IBM</ACRONYM>引领着ORACLE公司走上数据库的大船，那么<ACRONYM title="Digital Equipment Corporation">DEC</ACRONYM>公司的<ACRONYM title="Virtual Address eXtended">VAX</ACRONYM>就是带着他们扬帆出海了。短短的几年之后，ORACLE数据库被移植到各种主要平台之上。ORACLE产品也一直因为有可移植性这个关键特性而被那些潜在的客户关注。 <BR><BR>Oates这个时候因为婚姻趋于破裂而情绪沮丧，已经不能把精力全部放到公司上，不得不离开公司。几年后，他又重返公司，重新为ORACLE做出巨大的贡献，他许下诺言，在公司员工超过1万人的时候会再度离开。1999年，他完成了心愿。现在他正在纵情于音乐，自得其乐。 <BR><BR>很长一段时间里，公司研发由Miner独力承担。Miner视金钱如无物，为人低调，和Ellison的锋芒必露形成鲜明的对比。在公司里，大家一致认为他是老好人，他也深受员工爱戴。Ellison是公司的大脑，Miner则当之无愧的成为公司的心脏。他是个沉默的英雄，正如Steve Jobs背后的Steve Wozniak一样。 <BR><BR>1984年10月，ORACLE发布了第4版产品。产品的稳定性总算得到了得到了一定的增强，用Miner的话说，达到了“工业强度”。但是还不够令人满意，用户对产品的抱怨似乎永无休止。这一版增加了<STRONG>读一致性（Read Consistency）</STRONG>，这是数据库的一个关键特性，可以确保用户在查询期间看到一致的数据。也就是说，当一个会话正在修改数据时，其他的会话将看不到该会话未提交的修改。可以看到，在ORACLE第四版之前，产品始终是不稳定的，但是ORACLE的这群销售人员，主要是Ellison，他在宣传ORACLE的时候总是要夸大其词，但他就是有能力把软件卖出去，而且，还卖得很好，不得不承认，这的确有些神奇。让我们看看1984年软件市场的情形，在数据库市场上的霸主是Asnton-Tale公司，他们的拳头产品是刚推出不久的dBase III（确切的说dBase是PC上的数据库软件霸主），刚刚成为全球第三大的独立软件公司（第一和第二分别是微软、Lotus，ORACLE在当时还排不上号），这一年，也是苹果公司Macintosh诞生的年度，Steven Jobs用这个拳头产品挑战老大哥<ACRONYM title="International Business Machines">IBM</ACRONYM>。同样在这一年中，ORACLE公司的开发人员刚刚把产品移植到PC上。这是最好的年代，也是最坏的年代。数以千计的小公司在软件领域里争斗不休，新公司如雨后春笋般成立，ORACLE如何才能于不败之地？ <BR><BR>在1985年，ORACLE发布了5.0版。有用户说，这个版本算得上是ORACLE数据库的稳定版本。这也是首批可以在Client/Server模式下运行的的<ACRONYM title="Relational Database Mangement System">RDBMS</ACRONYM>产品，在技术趋势上，ORACLE数据库始终没有落后。这意味着运行在桌面PC机（客户机）上的商务应用程序能够通过网络访问数据库服务器。1986年发布的5.1版还支持<STRONG>分布式查询</STRONG>，允许通过一次性查询访问存储在多个位置的数据。 <BR><BR>那是在1985年，当时曾经的最大的独立软件公司Cullinet(主要销售网状数据库)已经如流星般陨落。ORACLE的主要竞争对手是Ingres数据库。Ingres在加州大学伯克利分校诞生，主要的设计者是当时鼎鼎大名的Michael Stonebraker教授。可以说Ingres数据库软件是上个世纪80年代技术上最好的数据库，Ingres市场分额的快速增长已经给ORACLE早成了很大的压力。巧的是，这个时候，<ACRONYM title="International Business Machines">IBM</ACRONYM>公司再一次伸出“上帝之手”。 <BR><BR>Ingres使用的是Stonebraker 发明的<ACRONYM title="QUEry Language">QUEL</ACRONYM>（Query Language））的查询技术，这和<ACRONYM title="International Business Machines">IBM</ACRONYM>的<ACRONYM title="Structured Query Language">SQL</ACRONYM>大不相同。在某些地方<ACRONYM title="QUEry Language">QUEL</ACRONYM>甚至要优于<ACRONYM title="Structured Query Language">SQL</ACRONYM>。<ACRONYM title="International Business Machines">IBM</ACRONYM>当时担心Ingres把<ACRONYM title="QUEry Language">QUEL</ACRONYM>变成标准会对自己不利。经过一番衡量，决定把自己的<ACRONYM title="Structured Query Language">SQL</ACRONYM>提交给数据库标准委员会。而Stonebraker教授可不打算把<ACRONYM title="QUEry Language">QUEL</ACRONYM>提交给数据库标准委员会，学院派的他认为这麽做实际上是扼杀了创新精神。鹬蚌相争，渔翁得利。ORACLE看到并抓住了这个绝佳的机会，大肆宣布ORACLE全面与<ACRONYM title="Structured Query Language">SQL</ACRONYM>兼容，加上ORACLE当时对Ingres PC上的版本的攻击（弱化对手优势，化解自己弱势是他们最拿手的本领），再加上ORACLE公司销售上的强势，Ingres不断丢城失地，等到后来推出支持<ACRONYM title="Structured Query Language">SQL</ACRONYM>的数据库的时候为时已晚。紧跟<ACRONYM title="International Business Machines">IBM</ACRONYM>让ORACLE得以成长、壮大，拥抱标准，拥抱开放，拥抱变化，让ORACLE立于不败之地。 <BR><BR>1986年3月12日，ORACLE公司以每股15美元公开上市，当日以20.75美元收盘，公司市值2.7亿美元。3月13日，微软以每股21美元的发行价上市，以28美元收市，公司市值达到7亿美元。远远超过了ORACLE。成功的光环的微软和盖茨遮盖住了ORACLE和Ellison的光芒，可能这也是Ellison敌视微软的开始。 
<P align=center><IMG height=455 alt="Larry Ellison" src="http://www.dbanotes.net/Images/Larry_Ellison.jpg" width=351> <BR>图4 桀骜不驯的Larry Ellison</P><BR>
<H2>经受挫折 </H2><BR>ORACLE第6版于1988年发布。由于过去的版本在性能上屡受诟病，Miner带领着工程师对数据库核心进行了重新的改写。引入了<STRONG>行级锁（row-level locking）</STRONG>这个重要的特性，也就是说，执行写入的事务处理只锁定受影响的行，而不是整个表。这个版本引入了还算不上完善的<ACRONYM title="Procedural Language extension to SQL">PL/SQL</ACRONYM>（Procedural Language extension to SQL）语言。第6版还引入了<STRONG>联机热备份</STRONG>功能，使数据库能够在使用过程中创建联机的备份，这极大地增强了可用性。同时在这一年，ORACLE开始研发<ACRONYM title="Enterprise Resource Planning">ERP</ACRONYM>软件。 <BR><BR>公司发展看上去比较顺利，不过，噩梦才刚刚开始。 <BR><BR>由于过去对软件测试重视的程度不够--那个时候公司规模小，基本上都是客户帮助免费测试的。在第六版刚发布之后，很多迫不及待开始使用的用户就怨声载道。这是个根本就没有测试好就进行发布的产品（也怪Ellison，大话总要说在前头，只好自尝苦果）。用户开始对ORACLE大肆抨击，ORACLE的一些对手也开始落井下石，针对ORACLE产品的一些弱点进行攻击。开发人员一面应付愤怒的用户，一面加班加点地对程序进行接连不断的修正，最后，总算得到了一个比较稳定的版本，暂时平息了用户的愤怒。 <BR><BR>但是，实际的问题并不在这里，几年来高速增长的同时也给公司带来了巨大的隐患，1990财年第三季度报表的公布引爆了一切。财务人员发现了1500万美元的坏帐，并且公司利润距离预期相差甚远。接下来的时间里，大公司病的诸般症状接踵而来，面对股东的指控，股票一落千丈，公司前景暗淡，甚至面临破产。一度靠贷款来维持自己的奢华生活也不变卖股票的Ellison也快撑不住了。公司下大力气整顿财务（财务主管杰夫·沃克从某种程度上解救了公司）。公司宣布削减开支，裁退大量销售人员，同时聘用了专门的管理人才。 <BR><BR>噩梦延续到ORACLE第七版的推出而结束。这个公司已经空谈了好几年的新版本（一度被讥讽为不过是Ellison的故计重施而已），直到1992年6月才终于闪亮登场，这一次公司吸取了第六版匆忙上市的教训，听取了用户的多方面的建议，并集中力量对新版本进行了大量而细致的测试。该版本增加了许多新的性能特性：<STRONG>分布式事务处理功能</STRONG>、增强的管理功能、用于应用程序开发的新工具以及安全性方法。ORACLE7还包含了一些新功能，如存储过程、触发过程和说明性引用完整性等，并使得数据库真正的具有可编程能力。还有一点必需要说明的是，这个版本在原有的基于规则的优化器（RBO）之外引入一种新的优化器：<STRONG>基于开销的优化器</STRONG>（Cost-Based Optimizer , <ACRONYM title="Cost-Based Optimizer">CBO</ACRONYM>）。<ACRONYM title="Cost-Based Optimizer">CBO</ACRONYM>根据数据库自身对对象的统计来计算语句的执行开销，从而得出具体的语句执行计划。在以后的几个重大版本中，ORACLE的工程师们逐步对这个优化器进行改进，<ACRONYM title="Cost-Based Optimizer">CBO</ACRONYM>逐渐取代了RBO。 <BR><BR>ORACLE 第七版是ORACLE真正出色的产品,取得了巨大的成功。这个版本的出现真是好时机，当时Sybase公司的数据库已经占据了不少份额，ORACLE借助这一版本的成功，一具击退了咄咄逼人的Sybase。公司的销售人员这次算到了给用户兑现空头许诺的时候。公司经过两三年的治理，终于摆脱了种种麻烦，重新开始健康发展，销售额也从92年的15亿美元变为四年后的42亿美元。 <BR><BR>
<H2>跨上巅峰</H2><BR>“搅浑水”是Ellison的一项绝技。在1995年巴黎举行的欧洲信息技术论坛会议上，Ellison在即兴演讲中介绍了网络计算机（Network Computer，NC）的概念,所谓NC指的是配置简单却能充分利用网络资源的低价电脑，最为重要的是，它不需要操作系统，或者更准确的说，不需要微软的操作系统。Ellison希望借此来抵制微软的强势。很快，ORACLE联合<ACRONYM title="International Business Machines">IBM</ACRONYM>、Sun、Apple和Netscape在1996年制定了网络计算机的标准，但事实上人们从头到尾没有看到一台真正的NC生产出来。这次的演讲在业界引起了轩然大波，通过这个事件，ORACLE公司吸引了足够多的注意力，同时也让人们看到ORACLE公司对于网络的巨大信心。 <BR><BR>1997年6月，ORACLE第八版发布。ORACLE8支持<STRONG>面向对象的开发</STRONG>及新的多媒体应用，这个版本也为支持Internet、网络计算等奠定了基础。同时这一版本开始具有同时处理大量用户和海量数据的特性。这个版本也算可圈可点了。 <BR><BR>1998年9月，ORACLE公司正式发布ORACLE 8i。“i”代表Internet，这一版本中添加了大量为支持Internet而设计的特性。这一版本为数据库用户提供了全方位的Java支持。ORACLE 8i成为第一个完全整合了本地Java运行时环境的数据库，用Java就可以编写ORACLE的存储过程。对，Java，只要是能够打击微软的武器，ORACLE都要派上用场。ORACLE8i 添加了SQLJ（一种开放式标准，用于将<ACRONYM title="Structured Query Language">SQL</ACRONYM>数据库语句嵌入客户机或服务器Java代码）和ORACLE interMedia（用于管理多媒体内容）以及<ACRONYM title="Extensible Markup Language">XML</ACRONYM>等特性。同时，ORACLE 8i 极大程度上提高了伸缩性、扩展性和可用性以满足网络应用需要。接下来的几年中，ORACLE陆续发布了8i的几个版本，并逐渐添加了一些面向网络应用的新特性。面对开源运动的蓬勃发展，ORACLE自然不甘落后，1998年十月ORACLE发布了可用于Linux平台的ORACLE 8 以及ORACLE Application Server 4.0，随后不久，ORACLE又发布了ORACLE 8i for Linux。在 .com大潮中，ORACLE是站在风口浪尖的弄潮儿。 <BR><BR>在2001年6月的ORACLE OpenWorld大会中，ORACLE发布了ORACLE 9i。在ORACLE 9i的诸多新特性中，最重要的就是Real Application Clusters（<ACRONYM title="Real Application Clusters">RAC</ACRONYM>）了。说起ORACLE集群服务器，早在第五版的时候，ORACLE就开始开发ORACLE并行服务器（ORACLE Parallel Server ，OPS），并在以后的版本中逐渐的完善了其功能，不过，严格来说，尽管OPS算得上是个集群环境，但是并没有体现出集群技术应有的优点。在完全吸收了Rdb（ORACLE在1994年收购了Compaq公司的Rdb数据库，此前Rdb属于<ACRONYM title="Digital Equipment Corporation">DEC</ACRONYM>公司，<ACRONYM title="Digital Equipment Corporation">DEC</ACRONYM>公司在<ACRONYM title="Virtual Address eXtended">VAX</ACRONYM>上实现了第一个可以商用的Rdb集群数据库）的一些技术优势之后，ORACLE终于推出了真正的应用集群软件。<ACRONYM title="Real Application Clusters">RAC</ACRONYM>使得多个集群计算机能够共享对某个单一数据库的访问，以获得更高的可伸缩性、可用性和经济性。ORACLE 9i的<ACRONYM title="Real Application Clusters">RAC</ACRONYM>在TPC-C的基准测试中打破了数项记录，一时间业内瞩目。这个新的数据库还包含集成的商务智能（BI）功能。ORACLE 9i第2版还做出了很多重要的改进，使ORACLE数据库成为一个本地的<ACRONYM title="Extensible Markup Language">XML</ACRONYM>数据库；此外还包括自动管理、<STRONG>Data Guard</STRONG>等高可用方面的特性。 <BR><BR>
<H2>历史还在继续</H2><BR>2003年9月8日，旧金山举办的ORACLE World大会上，Ellison宣布下一代数据库产品为“ORACLE 10g”。ORACLE应用服务器10g（ORACLE Application Server 10g）也将作为甲骨文公司下一代应用基础架构软件集成套件。“g”代表“grid ,网格”。这一版的最大的特性就是加入了网格计算的功能。何谓网格计算？网格计算可以把分布在世界各地的计算机连接在一起，并且将各地的计算机资源通过高速的互联网组成充分共享的资源集成。通过合理调度，不同的计算环境被综合利用并共享。ORACLE宣称10g可以作为网格计算的基础，矛头直指最大的敌人<ACRONYM title="International Business Machines">IBM</ACRONYM>的“随需应变”！看来，ORACLE公司已经把这一次的“赌注”押在了网格计算的大市场上。但前景如何？让我们拭目以待。 <BR><BR>如果说，<ACRONYM title="International Business Machines">IBM</ACRONYM>是IT产业中的一头巨鲸，那么ORACLE一定就是一条大鲨鱼：咄咄逼人，善于进攻。就在2003年6月初，ORACLE突然宣布51亿美金收购仁科（PeopleSoft），业内再次震动。此举又一次露出ORACLE 一贯善于进攻的本性。要知道，ORACLE在发展过程中很少对企业进行收购的，那么收购仁科目的何在？首先，ORACLE觊觎企业应用软件市场已久，但苦于不能进一步扩大市场分额，尤为重要的是，一旦成功，可以直接对最大的敌人<ACRONYM title="International Business Machines">IBM</ACRONYM>进行打击，还可以阻击SAP等巨头的强势。时至今日，ORACLE依然以不达目的不罢休的态势和仁科缠斗，结果如何，让我们拭目以待。 <BR><BR>"人生最大的快乐是击败敌人"，Ellison一定很喜欢这句话。 <BR><BR>后记：2004年12月13日，Oracle公司宣布签订了以每股26.50美元、总计约103亿美元的代价收购 仁科(PeopleSoft) 的最终协议。历时十八个月的争斗终于尘埃落定。 <BR>
<HR>

<SCRIPT type=text/javascript><!--
google_ad_client = "pub-2198040673582211";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_channel ="0605826110";
google_ad_type = "text";
google_color_border = "336699";
google_color_bg = "FFFFFF";
google_color_link = "0000FF";
google_color_url = "008000";
google_color_text = "000000";
//--></SCRIPT>

<SCRIPT src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript>
</SCRIPT>

<HR>

<H2>本文作者</H2>Fenng，某美资公司DBA，业余时间混迹于各数据库相关的技术论坛且乐此不疲。目前关注如何利用ORACLE数据库有效地构建企业应用。对Oracle tuning、troubleshooting有一点研究。<BR>个人技术站点:<A href="http://www.dbanotes.net/">http://www.dbanotes.net/</A> 。可以通过电子邮件 dbanotes@gmail.com 联系到他。 
<HR>

<H2>原文出处</H2><A href="http://www.dbanotes.net/Oracle/History_about_Oracle_company.htm">http://www.dbanotes.net/Oracle/History_about_Oracle_company.htm</A> <BR>]]></description>
</item><item>
<title><![CDATA[探讨ORACLE数据库的数据导入方法]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8439</link>
<author>blakestone</author>
<pubDate>2005/9/9 11:11:26</pubDate>
<description><![CDATA[<P>作者：万波 (Wanbo.cn) <BR>日期：19-Jan-2005　<BR>出处：<A href="http://www.dbanotes.net/">http://www.dbanotes.net</A><BR>版本：1.00<BR></P>
<HR>

<P><BR>&nbsp;</P>
<H2>前言</H2>
<P>每个数据库管理员都会面临数据导入的问题，这有可能发生在数据库的新老移植过程中，或者是在数据库崩溃后的恢复重建过程中，还有可能是在创建测试数据库的模拟环境过程中，总之作为一名合格的数据库管理员，你应该做好接受各种数据导入请求的技术储备，同时还要尽量满足人本能的对导入速度的苛求。本文仅<STRONG>针对 Oracle 数据库所提供的加速数据导入的各种特性和技术进行探讨</STRONG>，其中的一些方法也可以转化应用于其他数据库。以下七种数据导入方法哪个最适用需要针对具体情况具体分析，我也附带列举了影响导入速度的各种因素供斟酌。为了比较各种数据导入方法的效果，我创建了示例表和数据集，并用各种方法导入示例数据集来计算总体导入时间和导入进程占用 CPU 时间，这里得出的时间仅供参考。需要说明的是，建议你使用 Oracle 9i 企业版数据库，当然你也可以尝试使用 Oracle 7.3 以上的标准版数据库。本文使用的机器配置为：CPU Intel P4，内存 256M，数据库 Oracle 9i 企业版。</P>
<H2>示例表结构和数据集</H2>
<P>为了演示和比较各种数据导入方法，我假定数据导入任务是将外部文件数据导入到 Oracle 数据库的CALLS表中，外部数据文件包含十万条呼叫中心记录，将近 6MB 的文件大小，具体的数据示例如下:</P>
<BLOCKQUOTE><PRE>82302284384,2003-04-18:13:18:58,5001,投诉,手机三包维修质量
82302284385,2003-04-18:13:18:59,3352,咨询,供水热线的号码
82302284386,2003-04-18:13:19:01,3142,建议,增设公交线路 </PRE></BLOCKQUOTE>
<P>接受导入数据的表名是 CALLS，表结构如下：</P><PRE>     Name	            Null?         Type                 Comment
    ------------     ---------     -------------        -----------------
    CALL_ID          NOT NULL      NUMBER               Primary key
    CALL_DATE        NOT NULL      DATE                 Non-unique index
    EMP_ID           NOT NULL      NUMBER
    CALL_TYPE        NOT NULL      VARCHAR2(12)
    DETAILS                        VARCHAR2(25)
</PRE>
<H2>逐条数据插入INSERT</H2>
<P>数据导入的最简单方法就是编写 INSERT 语句，将数据逐条插入数据库。这种方法只<STRONG>适合导入少量数据</STRONG>，如 SQL*Plus 脚本创建某个表的种子数据。该方法的最大缺点就是导入速度缓慢，占用了大量的 CPU 处理时间，不适合大批量数据的导入；而其主要优点就是导入构思简单又有修改完善的弹性，不需要多做其它的准备就可以使用。如果你有很多时间没法打发，又想折磨一下数据库和 CPU，那这种方法正适合你。:)</P>
<P>为了与其它方法做比较，现将十万条记录通过此方法导入到 CALLS 表中，总共消耗 172 秒，其中导入进程占用 CPU 时间为 52 秒。</P>
<H2>逐条数据插入 INSERT，表暂无索引</H2>
<P>为什么上一种方法占用了较多的 CPU 处理时间，关键是 CALLS 表中已创建了索引，当一条数据插入到表中时，Oracle 需要判别新数据与老数据在索引方面是否有冲突，同时要更新表中的所有索引，重复更新索引会消耗一定的时间。因此提高导入速度的好办法就是在<STRONG>创建表时先不创建索引或者在导入数据之前删除所有索引</STRONG>，在外部文件数据逐条插入到表中后再统一创建表的索引。这样导入速度会提高，同时创建的索引也很紧凑而有效，这一原则同样适用于位图索引（Bitmap Index）。对于主要的和唯一的关键约束(key constraints)，可以使之先暂时失效(disabling)或者删除约束来获得同样的效果，当然这些做法会对已经存在的表的外键约束产生相关的影响，在删除前需要通盘斟酌。</P>
<P>需要说明的是，这种方法在表中已存在很多数据的情况下不太合适。例如表中已有九千万条数据，而此时需要追加插入一千万条数据，实际导入数据节省的时间将会被重新创建一亿条数据的索引所消耗殆尽，这是我们不希望得到的结果。但是，如果要导入数据的表是空的或导入的数据量比已有的数据量要大得多，那么导入数据节省的时间将会少量用于重新创建索引，这时该方法才可以考虑使用。</P>
<P>加快索引创建是另一个需要考虑的问题。为了减少索引创建中排序的工作时间，可以在当前会话中增加 SORT_AREA_SIZE 参数的大小，该参数允许当前会话在内存的索引创建过程中执行更多的排序操作。同样还可以使用 NOLOGGING 关键字来减少因创建索引而生成的 REDO 日志量，NOLOGGING 关键字会对数据库的恢复和 Standby 备用数据库产生明显的影响，所以在使用之前要仔细斟酌，到底是速度优先还是稳定优先。</P>
<P>运用这种方法，先删除 CALLS 表的主键和不唯一的索引，然后逐条导入数据，完成后重新创建索引( 表在导入数据前是空的)。该方法总共消耗 130 秒，包括重建索引的时间，其中导入进程占用 CPU 时间为 35秒。</P>
<P>这种方法的优点是可以加快导入的速度并使索引更加紧凑有效；缺点是缺乏通用性，当你对表增加新的复杂的模式元素（索引、外键等）时你需要添加代码、修改导入执行程序。另外针对 7*24 在线要求的数据库在线导入操作时，删除表的索引会对在线用户的查询有很大的性能影响，同时也要考虑，主要或唯一的关键约束条件的删除或失效可能会影响到引用它们的外键的使用。</P>
<H2>批量插入，表暂无索引</H2>
<P>在Oracle V6 中 OCI 编程接口加入了数组接口特性。数组操作允许导入程序读取外部文件数据并解析后，向数据库提交SQL语句，批量插入 SQL 语句检索出的数据。Oracle 仅需要执行一次 SQL 语句，然后在内存中批量解析提供的数据。批量导入操作比逐行插入重复操作更有效率，这是因为只需一次解析 SQL 语句，一些数据绑订操作以及程序与数据库之间来回的操作都显著减少，而且数据库对每一条数据的操作都是重复可知的，这给数据库提供了优化执行的可能。其优点是数据导入的总体时间明显减少，特别是进程占用 CPU 的时间。</P>
<P>需要提醒的是，通过 OCI 接口确实可以执行数据批量导入操作，但是许多工具和脚本语言却不支持使用此功能。如果要使用该方法，需要研究你所使用的开发工具是否支持 OCI 批量操作功能。导入程序需要进行复杂的编码并可能存在错误的风险，缺乏一定的弹性。</P>
<P>运用上述方法，程序将外部数据提取到内存中的数组里，并执行批量插入操作（100行/次），保留了表的删除/重建索引操作，总的导入时间下降到 14 秒，而进程占用 CPU 的时间下降到7秒，可见实际导入数据所花费的时间显著下降了 95%。</P>
<H2>CREATE TABLE AS SELECT，使用Oracle9i的External Table </H2>
<P>Oracle 9i 的一项新特性就是 External Table，它就象通常的数据库表一样，拥有字段和数据类型约束，并且可以查询，但是表中的数据却不存储在数据库中，而是在与数据库相关联的普通外部文件里。当你查询 External Table 时，Oracle 将解析该文件并返回符合条件的数据，就象该数据存储在数据库表中一样。</P>
<P>需要注意的是，你可以在查询语句中将 External Table 与数据库中其他表进行连接（Join），但是不能给 External Table 加上索引，并且不能插入/更新/删除数据，毕竟它不是真正的数据库表。另外，如果与数据库相关联的外部文件被改变或者被删除，这会影响到 External Table 返回查询结果，所以在变动前要先跟数据库打招呼。 </P>
<P>这种方法为导入数据打开了新的一扇门。你可以很容易的将外部文件与数据库相关联，并且在数据库中创建对应的 External Table，然后就可以立即查询数据，就象外部数据已经导入到数据库表中一样。唯一的不足需要明确，数据并未真正导入到数据库中，当外部文件被删除或覆盖时，数据库将不能访问 External Table 里的数据，而且索引没有被创建，访问数据速度将有所缓慢。创建 CALLS_EXTERNAL（External Table表）如下，使之与外部数据文件关联：</P><PRE>CREATE TABLE calls_external         
        (call_id    NUMBER,
         call_date  DATE,
         emp_id     NUMBER,
         call_type  VARCHAR2(12),
         details    VARCHAR2(25))
        ORGANIZATION EXTERNAL
        ( TYPE oracle_loader
        DEFAULT DIRECTORY extract_files_dir
        ACCESS PARAMETERS
          (
          RECORDS DELIMITED BY NEWLINE
          FIELDS TERMINATED BY ','
          MISSING FIELD VALUES ARE NULL
            (
            call_id, call_date CHAR DATE_FORMAT DATE MASK
            "yyyy-mm-dd:hh24:mi:ss",
            emp_id, call_type, details
            )
          )
        LOCATION ('calls.dat')
        );
		</PRE>
<P>然后将 External Table 与真正被使用的表 CALLS 关联同步，删除 CALLS 表并重建它：</P><PRE>    CREATE TABLE calls
        (
        call_id    NUMBER	 NOT NULL,
        call_date  DATE		 NOT NULL,
        emp_id  	 NUMBER	 NOT NULL,
        call_type	 VARCHAR2(12) NOT NULL,
        details	 VARCHAR2(25)
        )
        TABLESPACE tbs1 NOLOGGING
        AS
        SELECT call_id, call_date, emp_id, call_type, details
        FROM   calls_external;
		</PRE>
<P>因为 CALLS 表是真正的数据库表，可以创建索引来加快访问，表中的数据将被保留，即使外部数据文件被更新或被删除。在建表语句中NOLOGGING关键字用于加快索引重建。</P>
<P>运用这种方法导入数据，总的导入时间为 15 秒，进程占用 CPU 的时间为8秒，这比前一种方法稍微慢些，但不能就此认为使用 External Table 导入数据一定比 OCI 批量插入慢。</P>
<P>这种方法的优点是，未经进行大量的编写代码就取得了不错的结果，不象 OCI 批量插入存在编码错误风险，它还可以使用 dbms_job 包调度数据导入进程，实现数据导入的自动化。其缺点是目标表必须先删除后重建，如果只需要导入增量数据时此方法就不合适了，另外用户在表的重建过程中访问数据时会遇到 "table or view does not exist" 的错误，它仅适用于 Oracle 9i 以上版本的数据库。</P>
<H2>INSERT Append as SELECT，使用 Oracle9i 的 External Table</H2>
<P>上一种方法演示了如何创建与外部数据文件关联的数据库表，其表的数据是由外部数据文件映射过来。缺点是数据库表需要被先删除再重建来保持与外部数据文件的一致和同步，对导入增量的数据而不需要删除已有数据的情况不合适。针对这种需求，Oracle 提供了 INSERT 语句外带 APPEND 提示来满足。</P><PRE>    INSERT    /*+ APPEND */ INTO calls
            (call_id, call_date, emp_id, call_type, details)
   SELECT call_id, call_date, emp_id, call_type, details
     FROM calls_external;</PRE>
<P>该语句读取引用外部数据文件的 CALLS_EXTERNAL 表中内容，并将之增加到表 CALLS 中。Append 提示告诉 Oracle 使用快速机制来插入数据，同时可以配合使用表的 NOLOGGING 关键字。</P>
<P>可以预见这种方法与前一方法消耗了相同的时间，毕竟它们是使用 External Table 特性导入数据的不同阶段解决方法。如果目标表不是空的，那将会消耗稍微长的时间（因为要重建更长的索引），而前一 CREATE TABLE as SELECT 方法是整体创建索引。</P>
<H2>SQL*Loader的强大功能</H2>
<P>SQL*Loader 是 Oracle 提供的导入实用程序，特别针对从外部文件导入大批量数据进入数据库表。该工具已经有多年的历史，每一次版本升级都使其更加强大、灵活和快捷，但遗憾的是它的语法却是神秘而不直观，并且只能从命令行窗口处进行调用。</P>
<P>尽管它有不直观的缺点，但却是<STRONG>最快最有效的导入数据方法</STRONG>。缺省情况下它使用 "conventional path" 常规选项来批量导入数据，其性能提高度并不明显。我建议使用更快速的导入参数选项，在命令行添加"direct=true" 选项调用 "direct path" 导入选项。在 "direct path" 导入实现中，程序在数据库表的新数据块的 high water mark 处直接写入导入数据，缩短了数据插入的处理时间，同时优化使用了非常有效的B+二叉树方法来更新表的索引。 </P>
<P>运用这种方法，如果使用缺省的 conventional path 导入选项，总的导入时间是 81 秒，进程占用 CPU 时间大约是 12 秒，这包括了更新表的索引时间。如果使用 direct path 导入选项，总的导入时间竟是 9 秒，进程占用 CPU 时间也仅仅是 3 秒，也包括了更新表的索引时间。</P>
<P>由此可见，尽管表中的索引在数据导入之前并没有被删除，使用SQL*Loader的direct path 导入选项仍然是快速和有效的。当然它也有缺点，就像NOLOGGING关键字一样该方法不生成REDO日志数据，导入进程出错后将无法恢复到先前状态；在数据导入过程中表的索引是不起作用的，用户此时访问该表时将出现迟缓，当然在数据导入的过程中最好不要让用户访问表。</P>
<H2>分区交换 (Partition Exchange)</H2>
<P>以上讨论的数据导入方法都有一个限制，就是要求用户在导入数据完成之后才可以访问数据库表。面对7×24不间断访问数据库来说，如果我们只是导入需要增加的数据时，这种限制将对用户的实时访问产生影响。Oracle在这方面提供了表分区功能，它可以减少导入数据操作对用户实时访问数据的影响，操作模式就象使用可热插拔的硬盘一样，只不过这里的硬盘换成了分区（Partition）而已。需要声明的是 Partitioning 分区功能只有在企业版数据库中才提供。</P>
<P>在一个被分区过的表中，呈现给用户的表是多个分区段（segments）的集合。分区可以在需要时被添加，在维护时被卸载或删除，分区表可以和数据库中的表交换数据，只要它们的表结构和字段类型是一致的，交换后的分区表将拥有与之互动的表的数据。需要注意的是，这种交换只是在Oracle数据库的数据字典层面上进行，并没有数据被实际移动，所以分区表交换是极其快速的。</P>
<P>为了创建实验环境，先假设CALLS表是个分区表，要创建一个空的分区PART_01012004，用来保存2004年1月1日的呼叫数据。然后需要再创建一临时表为CALLS_TEMP，该表与CALLS表拥有相同的字段和数据类型。</P>
<P>我们使用先前介绍的导入方法将十万条数据导入到CALLS_TEMP表中，可以耐心等待数据完全导入到CALLS_TEMP表中，并且创建好索引和相关约束条件，所有这一切操作并不影响用户实时访问CALLS表，因为我们只对CALLS_TEMP临时表进行了操作。一旦数据导入完成，CALLS_TEMP表就存有2004年1月1日的呼叫数据。同时利用CALLS表中名为PART_01012004的空分区，使用如下语句执行分区交换： </P><PRE>       ALTER  TABLE  calls 
        EXCHANGE  PARTITION  part_01012004 WITH  TABLE calls_temp 
        INCLUDING  INDEXES  WITHOUT  VALIDATION;</PRE>
<P>分区交换操作将非常快速地只更新CALLS表的数据字典，PART_01012004分区表即刻拥有CALLS_TEMP表的所有数据，而CALLS_TEMP表变为空表。假定CALLS表使用局部索引而非全局索引，上述语句中的INCLUDING INDEXES将保证分区交换包括索引的可用性，WITHOUT VALIDATION 指明不检查交替表中数据的匹配，加快了交换的速度。</P>
<H2>结论</H2>
<P>以上探讨了Oracle数据库的多种数据导入方法，每种方法都有其优缺点和适用环境，能够满足你不同的导入需求，当然你需要在了解了这些方法后，在速度、简易性、灵活性、可恢复性和数据可用性之间寻求最佳导入方案。</P>
<P>为了对比各种方法的效果，我们创建了一个实例来展示各种方法的导入效率和效果，从中你可以选择最适合的方法用于今后的数据导入工作。同时请记住，本文并未囊括所有的ORACLE数据导入技术（比如并行数据导入技术），这需要我们继续不懈的探索和尝试。 </P>
<P>
<TABLE>
<TBODY>
<TR>
<TD><STRONG>数据导入方法</STRONG></TD>
<TD><STRONG>总体导入时间(秒)</STRONG></TD>
<TD><STRONG>导入进程占用CPU时间(秒)</STRONG></TD></TR>
<TR>
<TD>逐条数据插入INSERT</TD>
<TD>172 </TD>
<TD>52</TD></TR>
<TR>
<TD>逐条数据插入INSERT，表暂无索引</TD>
<TD>130 </TD>
<TD>35</TD></TR>
<TR>
<TD>批量插入，表暂无索引 </TD>
<TD>14 </TD>
<TD>7</TD></TR>
<TR>
<TD>Create As Select，使用Oracle9i的External Table</TD>
<TD>15</TD>
<TD>8</TD></TR>
<TR>
<TD>INSERT Append as SELECT，使用Oracle9i的External Table </TD>
<TD>15</TD>
<TD>8</TD></TR>
<TR>
<TD>SQL*Loader conventional path 缺省导入选项</TD>
<TD>81 </TD>
<TD>12</TD></TR>
<TR>
<TD>SQL*Loader direct path 导入选项 </TD>
<TD>9 </TD>
<TD>3</TD></TR></TBODY></TABLE><BR><BR><BR>
<SCRIPT type=text/javascript><!--
google_ad_client = "pub-2198040673582211";
google_alternate_ad_url = "http://www.dbanotes.net/blog/google_adsense_script.html";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_channel ="4565376735";
google_ad_type = "text";
google_color_border = "003366";
google_color_bg = "003366";
google_color_link = "FFFFFF";
google_color_url = "99CCFF";
google_color_text = "FFFFFF";
//--></SCRIPT>

<SCRIPT src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript>
</SCRIPT>
</P>
<HR>

<H2>本文作者</H2>
<P>万波(Wanbo.cn) .本文版权归原作者所有。转载请注明作者及出处！</P>]]></description>
</item><item>
<title><![CDATA[创建镜像备用数据库]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8438</link>
<author>blakestone</author>
<pubDate>2005/9/9 10:38:51</pubDate>
<description><![CDATA[&nbsp;Oracle DBA可以通过创建并维持一个主数据库的镜像数据库来保证工作系统即使用主数据库故障时也能7X24不间断提供服务。 <BR>&nbsp;&nbsp;<BR>一个镜像数据库是： <BR>*它应当是主数据库在另一台计算机上的一个拷贝，两者应有相同的版本并且运行在相同类型、相同版本的操作系统之上； <BR>*它一直处于RECOVERY状态以备激活； <BR>*它一旦被激活，就成为主数据库。 <BR>&nbsp;&nbsp;<BR>1、复制主数据库初始化文件init.ora到镜像数据库。 <BR>编辑修改init.ora文件的如下参数： <BR>CONTROL_FILES&nbsp; &nbsp;DB_FILE_NAME_CONVERT&nbsp;&nbsp;LOG_FILE_NAME_CONVERT <BR>这些参数在主数据库和镜像数据库目录名不同时，用以转换镜像数据库的数据文件和日志文件位置。 <BR>&nbsp;&nbsp;<BR>2、在主数据库方为镜像数据库创建控制文件： <BR>SQL&gt;alter database create standby controlfile as &amp;lt;filename&gt;; <BR>并将该文件复制到镜像端(init.ora中CONTROL_FILES)指定的位置； <BR>&nbsp;&nbsp;<BR>3、备份主数据库的数据文件。可以采用脱机或联机备份的方式。将备份复制到镜像数据库指定位置。 <BR>&nbsp;&nbsp;<BR>4、如果步骤3采用联机备份，立即归档当前重做日志： <BR>SQL&gt;alter system archive log current; <BR>复制归档日志文件到镜像服务器； <BR>&nbsp;&nbsp;<BR>5、启动镜像数据库到nomount状态： <BR>SQL&gt;startup pfile=%oracle_home%\initstandby.ora nomount <BR>&nbsp;&nbsp;<BR>6、Mount镜像数据库： <BR>SQL&gt;alter database mount standby database; <BR>&nbsp;&nbsp;<BR>7、将主数据库的归档日志应用到镜像数据库以保持主数据库与镜像数据库之间的同步： <BR>SQL&gt;recover standby database; <BR>&nbsp;&nbsp;<BR>一旦主数据故障无法使用，就可以迅速激活镜像备份： <BR>1、如果可能，归档主服务器当前重做日志，传送到镜像服务器； <BR>2、使用主服务器的归档日志文件做恢复： <BR>SQL&gt;recover standby database; <BR>3、激活并打开数据库： <BR>SQL&gt;alter database activate standby database; <BR>SQL&gt;alter database mount; <BR>SQL&gt;alter database open; <BR>]]></description>
</item><item>
<title><![CDATA[ORACLE备份策略(ORACLE BACKUP STRATEGY)]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8435</link>
<author>blakestone</author>
<pubDate>2005/9/9 9:37:25</pubDate>
<description><![CDATA[概要 <BR>1、了解什么是备份 <BR>2、了解备份的重要性 <BR>3、理解数据库的两种运行方式 <BR>4、理解不同的备份方式及其区别 <BR>5、了解正确的备份策略及其好处 <BR>&nbsp;&nbsp;<BR>一、了解备份的重要性 <BR>可以说，从计算机系统出世的那天起，就有了备份这个概念，计算机以其强大的速度处理能力，取代了很多人为的工作，但是，往往很多时候，它又是那么弱不禁风，主板上的芯片、主板电路、内存、电源等任何一项不能正常工作，都会导致计算机系统不能正常工作。当然，这些损坏可以修复，不会导致应用和数据的损坏。但是，如果计算机的硬盘损坏，将会导致数据丢失，此时必须用备份恢复数据。 <BR>其实，在我们的现实世界中，已经就存在很多备份策略，如RAID技术，双机热备，集群技术发展的不就是计算机系统的备份和高可用性吗？有很多时候，系统的备份的确就能解决数据库备份的问题，如磁盘介质的损坏，往往从镜相上面做简单的恢复，或简单的切换机器就可以了。 <BR>但是，上面所说的系统备份策略是从硬件的角度来考虑备份与恢复的问题，这是需要代价的。我们所能选择备份策略的依据是：丢是数据的代价与确保数据不丢失的代价之比。还有的时候，硬件的备份有时根本满足不了现实需要，假如你误删了一个表，但是你又想恢复的时候，数据库的备份就变的重要了。ORACLE本身就提供了强大的备份与恢复策略，这里我们只讨论ORACLE备份策略，以下的备份都是指ORACLE数据库备份，恢复将放到下一讲中。 <BR>所谓备份，就是把数据库复制到转储设备的过程。其中，转储设备是指用于放置数据库拷贝的磁带或磁盘。&nbsp;&nbsp;<BR>能够进行什么样的恢复依赖于有什么样的备份。作为 DBA，有责任从以下三个方面维护数据库的可恢复性：&nbsp;&nbsp;<BR>·使数据库的失效次数减到最少，从而使数据库保持最大的可用性；&nbsp;&nbsp;<BR>·当数据库不可避免地失效后，要使恢复时间减到最少，从而使恢复的效率达到最高；&nbsp;&nbsp;<BR>·当数据库失效后，要确保尽量少的数据丢失或根本不丢失，从而使数据具有最大的可恢复性。&nbsp;&nbsp;<BR>灾难恢复的最重要的工作是设计充足频率的硬盘备份过程。备份过程应该满足系统要求的可恢复性。例如，如果数据库可有较长的关机时间，则可以每周进行一次冷备份，并归档重做日志，对于24*7的系统，或许我们考虑的只能是热备份。 如果每天都能备份当然会很理想，但要考虑其现实性。企业都在想办法降低维护成本，现实的方案才可能被采用。只要仔细计划，并想办法达到数据库可用性的底线，花少量的钱进行成功的备份与恢复也是可能的。 <BR>二、了解ORACLE的运行方式 <BR>ORACLE数据库有两种运行方式：一是归档方式（ARCHIVELOG），归档方式的目的是当数据库发生故障时最大限度恢复数据库，可以保证不丢失任何已提交的数据；二是不归档方式(NOARCHIVELOG)，只能恢复数据库到最近的回收点（冷备份或是逻辑备份）。我们根据数据库的高可用性和用户可承受丢失的工作量的多少，对于生产数据库，强烈要求采用为归档方式；那些正在开发和调试的数据库可以采用不归档方式。&nbsp;&nbsp;<BR>&nbsp;&nbsp;如何改变数据库的运行方式，在创建数据库时，作为创建数据库的一部分，就决定了数据库初始的存档方式。一般情况下为NOARCHIVELOG方式。当数据库创建好以后，根据我们的需要把需要运行在归档方式的数据库改成ARCHIVELOG方式。&nbsp;&nbsp;<BR>1、改变不归档方式为为归档方式&nbsp;&nbsp;<BR>a.关闭数据库，备份已有的数据，改变数据库的运行方式是对数据库的重要改动，所以要对数据库做备份，对可能出现的问题作出保护。&nbsp;&nbsp;<BR>b. 修改初试化参数，使能自动存档&nbsp;&nbsp;<BR>修改（添加）初始化文件init[SID].ora参数：&nbsp;&nbsp;<BR>log_archive_start=true&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;#启动自动归档 <BR>log_archive_format=ARC%T%S.arc&nbsp; &nbsp;#归档文件格式 <BR>log_archive_dest=/arch12/arch&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;#归档路径 <BR>在8i中，可以最多有五个归档路径，并可以归档到其它服务器，如备用数据库(standby database)服务器 <BR>c.启动Instance到Mount状态，即加载数据库但不打开数据库：&nbsp;&nbsp;<BR>$&gt;SVRMGRL <BR>SVRMGRL &gt;connect internal <BR>SVRMGRL &gt;startup mount <BR>&nbsp; &nbsp; d.发出修改命令 <BR>SVRMGRL &gt;alter database archivelog; <BR>SVRMGRL&gt;alter database open; <BR>2、改变归档状态为不归档状态 <BR>&nbsp; &nbsp; 与以上步骤相同，但有些操作不一样，主要是在以上的b操作中，现在为删除或注释该参数，在d操作中，命令为 <BR>SVRMGRL &gt;alter database noarchivelog; <BR>&nbsp; &nbsp;&nbsp;&nbsp;注意，从归档方式转换到非归档方式后一定要做一次数据库的全冷备份，防止意外事件的发生。 <BR>三、ORACLE备份的分类 <BR>简单的按照备份进行的方式，可以分为逻辑备份、冷备份（脱机备份）、热备份（联机备份），其实冷备份与热备份又可以合称为物理备份 <BR>按照备份的工具，可以分为EXP/IMP备份、OS拷贝、RMAN、第三方工具，如VERITAS <BR>以下我们将从多个角度来说明以上的各种备份方式 <BR>1、EXP/IMP逻辑备份 <BR>导入/导出是ORACLE幸存的最古老的两个命令行工具了，其实我从来不认为Exp/Imp是一种好的备份方式，正确的说法是Exp/Imp只能是一个好的转储工具，特别是在小型数据库的转储，表空间的迁移，表的抽取，检测逻辑和物理冲突等中有不小的功劳。当然，我们也可以把它作为小型数据库的物理备份后的一个逻辑辅助备份，也是不错的建议。 <BR>对于越来越大的数据库，特别是TB级数据库和越来越多数据仓库的出现，EXP/IMP越来越力不从心了，这个时候，数据库的备份都转向了RMAN和第三方工具。下面我们还是简要介绍一下EXP/IMP的使用。 <BR>i、使用方法 <BR>Exp parameter_name=value <BR>Or Exp parameter_name=(value1,value2……) <BR>只要输入参数help=y就可以看到所有帮助 <BR>如： <BR>C:\&gt;set nls_lang=simplified chinese_china.zhs16gbk <BR>C:\&gt;exp -help <BR>Export: Release 8.1.6.0.0 - Production on 星期四 4月 10 19:09:21 2003 <BR>(c) Copyright 1999 Oracle Corporation.&nbsp;&nbsp;All rights reserved. <BR>&nbsp;&nbsp;<BR>通过输入 EXP 命令和用户名/口令，您可以 <BR>在用户 / 口令之后的命令: <BR>&nbsp;&nbsp;<BR>实例: EXP SCOTT/TIGER <BR>或者，您也可以通过输入跟有各种参数的 EXP 命令来控制“导出” <BR>的运行方式。要指定参数，您可以使用关键字: <BR>&nbsp;&nbsp;<BR>格式: EXP KEYWORD=value 或 KEYWORD=(value1,value2,...,valueN) <BR>实例: EXP SCOTT/TIGER GRANTS=Y TABLES=(EMP,DEPT,MGR) <BR>或 TABLES=(T1: P1,T1: P2)，如果 T1 是分区表 <BR>USERID 必须是命令行中的第一个参数。 <BR>关键字&nbsp;&nbsp;说明（默认）&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;关键字&nbsp; &nbsp;&nbsp; &nbsp;说明（默认） <BR>-------------------------------------------------------------------------- <BR>USERID&nbsp; &nbsp;用户名/口令&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;FULL&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;导出整个文件 (N) <BR>BUFFER&nbsp; &nbsp;数据缓冲区的大小&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; OWNER&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;所有者用户名列表 <BR>FILE&nbsp; &nbsp;&nbsp;&nbsp;输出文件 (EXPDAT.DMP)&nbsp; &nbsp; TABLES&nbsp; &nbsp;&nbsp; &nbsp; 表名列表 <BR>COMPRESS 导入一个范围 (Y)&nbsp; &nbsp;RECORDLENGTH&nbsp;&nbsp;IO 记录的长度 <BR>GRANTS&nbsp;&nbsp;导出权限 (Y)&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;INCTYPE&nbsp; &nbsp;&nbsp; &nbsp;增量导出类型 <BR>INDEXES 导出索引 (Y)&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RECORD&nbsp; &nbsp;&nbsp; &nbsp; 跟踪增量导出 (Y) <BR>ROWS&nbsp; &nbsp; 导出数据行 (Y)&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;PARFILE&nbsp; &nbsp;&nbsp; &nbsp;参数文件名 <BR>CONSTRAINTS 导出限制 (Y)&nbsp; &nbsp; CONSISTENT&nbsp; &nbsp;交叉表一致性 <BR>LOG&nbsp; &nbsp;&nbsp; &nbsp;屏幕输出的日志文件&nbsp; &nbsp; STATISTICS&nbsp;&nbsp;分析对象 (ESTIMATE) <BR>DIRECT&nbsp; &nbsp;直接路径 (N)&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;TRIGGERS&nbsp; &nbsp;&nbsp;&nbsp;导出触发器 (Y) <BR>FEEDBACK 显示每 x 行 (0) 的进度 <BR>FILESIZE 各转储文件的最大尺寸 <BR>QUERY&nbsp; &nbsp; 选定导出表子集的子句 <BR>&nbsp;&nbsp;<BR>下列关键字仅用于可传输的表空间 <BR>TRANSPORT_TABLESPACE 导出可传输的表空间元数据 (N) <BR>TABLESPACES 将传输的表空间列表 <BR>在没有警告的情况下成功终止导出。 <BR>C:\&gt; <BR>帮助已经很详细的说明了参数的意义和使用方法，并列举了几个简单的例子，注意的是，从8i开始，已经开始支持数据子集的方法，就是可以指定自己的Where条件，可以从表中导出一行或多行数据。 <BR>注意上面的set nls_lang=simplified chinese_china.zhs16gbk，通过设置环境变量，可以让exp的帮助以中文显示，如果set nls_lang=American_america.字符集，那么你的帮助就是英文的了。 <BR>增量和累计导出必须在全库方式下才有效，而且，大多数情况下，增量和累计导出并没有想象中的那么有效。ORACLE从9i开始，不再支持增量导出和累计导出。 <BR>ii、表空间传输 <BR>表空间传输是8i新增加的一种快速在数据库间移动数据的一种办法，是把一个数据库上的格式数据文件附加到另外一个数据库中，而不是把数据导出成Dmp文件，这在有些时候是非常管用的，因为传输表空间移动数据就象复制文件一样快。 <BR>关于传输表空间有一些规则，即： <BR>·源数据库和目标数据库必须运行在相同的平台上。 <BR>·源数据库与目标数据库必须使用相同的字符集。 <BR>·源数据库与目标数据库一定要有相同大小的数据块（9i已经不用） <BR>·目标数据库不能有与迁移表空间同名的表空间 <BR>·SYS的对象不能迁移 <BR>·必须传输自包含的对象集 <BR>·有一些对象，如物化视图，基于函数的索引等不能被传输 <BR>可以用以下的方法来检测一个表空间或一套表空间是否符合传输标准： <BR>exec sys.dbms_tts.transport_set_check(‘tablespace_name’,true); <BR>select * from sys.transport_set_violation; <BR>如果没有行选择，表示该表空间只包含表数据，并且是自包含的。对于有些非自包含的表空间，如数据表空间和索引表空间，可以一起传输。 <BR>以下为简要使用步骤，如果想参考详细使用方法，也可以参考ORACLE联机帮助。 <BR>a.设置表空间为只读（假定表空间名字为APP_Data 和APP_Index） <BR>&nbsp; &nbsp;alter tablespace app_data read only; <BR>&nbsp; &nbsp;alter tablespace app_index read only; <BR>b.发出EXP命令 <BR>&nbsp; &nbsp;SQL&gt;host exp userid=”””sys/password as sysdba”””&nbsp;&nbsp;<BR>transport_tablespace=y tablespace=(app_data, app_index) <BR>&nbsp;&nbsp;以上需要注意的是 <BR>·为了在SQL中执行EXP，USERID必须用三个引号，在UNIX中也必须注意避免“/”的使用 <BR>·在816和以后，必须使用sysdba才能操作 <BR>·这个命令在SQL中必须放置在一行（这里是因为显示问题放在了两行） <BR>&nbsp; &nbsp; c.拷贝数据文件到另一个地点，即目标数据库 <BR>&nbsp; &nbsp;&nbsp;&nbsp;可以是cp(unix)或copy(windows)或通过ftp传输文件（一定要在bin方式） <BR>&nbsp; &nbsp; d.把本地的表空间设置为读写 <BR>&nbsp; &nbsp; e.在目标数据库附加该数据文件 <BR>imp file=expdat.dmp userid=”””sys/password as sysdba””” <BR>&nbsp; &nbsp;&nbsp; &nbsp;transport_tablespace=y <BR>&nbsp; &nbsp;&nbsp; &nbsp;“datafile=(c:\temp\app_data,c:\temp\app_index)” <BR>&nbsp; &nbsp;f.设置目标数据库表空间为读写 <BR>alter tablespace app_data read write; <BR>&nbsp; &nbsp;&nbsp;&nbsp;alter tablespace app_index read write; <BR>iii、导出/导入与字符集 <BR>明白ORACLE的多国语言设置，ORACLE多国语言设置是为了支持世界范围的语言与字符集，一般对语言提示，货币形式，排序方式和CHAR,VARCHAR2,CLOB,LONG字段的数据的显示等有效。ORACLE的多国语言设置最主要的两个特性就是国家语言设置与字符集设置，国家语言设置决定了界面或提示使用的语言种类，字符集决定了数据库保存与字符集有关数据（如文本）时候的编码规则。正如刚才上面的一个小例子，环境变量NLS_LANG的不同，导致EXP帮助发生变化，这就是多国语言设置的作用（NLS_LANG包含国家语言设置与字符集设置，这里起作用的是国家语言设置，而不是字符集）。 <BR>ORACLE字符集设定，分为数据库字符集和客户端字符集环境设置。在数据库端，字符集在创建数据库的时候设定，并保存在数据库props$表中，对于8i以上产品，已经可以采用“Alter database character set 字符集”来修改数据库的字符集，但也仅仅是从子集到超集，不要通过update props$来修改字符集，如果是不支持的转换，可能会失去所有与字符集有关的数据，就是支持的转换，也可能导致数据库的不正常工作。字符集分为单字节字符集与多字节字符集，US7ASCII就是典型的单字节字符集，在这种字符集中length=lengthb，而ZHS16GBK就是常用的双字节字符集，在这里lengthb=2*length。 <BR>在客户端的字符集环境比较简单，主要就是环境变量或注册表项NLS_LANG，注意NLS_LANG的优先级别为：参数文件à注册表à环境变量àalter session。NLS_LANG的组成为“国家语言设置.字符集”，如nls_lang=simplified chinese_china.zhs16gbk。客户端的字符集最好与数据库端一样（国家语言设置可以不一样，如zhs16gbk的字符集，客户端可以是nls_lang =simplified chinese_china.zhs16gbk或Ameircan_America.zhs16gbk，都不影响数据库字符的正常显示），如果字符集不一样，而且字符集的转换也不兼容，那么客户端的数据显示与导出/导入的与字符集有关的数据将都是乱码。 <BR>使用一点点技巧，就可以使导出/导入在不同的字符集的数据库上转换数据。这里需要一个2进制文件编辑工具即可，如uedit32。用编辑方式打开导出的dmp文件，获取2、3字节的内容，如00 01，先把它转换为10进制数，为1，使用函数NLS_CHARSET_NAME即可获得该字符集： <BR>SQL&gt; select nls_charset_name(1) from dual; <BR>NLS_CHARSET_NAME(1) <BR>------------------- <BR>US7ASCII <BR>可以知道该dmp文件的字符集为US7ASCII，如果需要把该dmp文件的字符集换成ZHS16GBK，则需要用NLS_CHARSET_ID获取该字符集的编号： <BR>SQL&gt; select nls_charset_id('zhs16gbk') from dual; <BR>NLS_CHARSET_ID('ZHS16GBK') <BR>-------------------------- <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;852 <BR>把852换成16进制数，为354，把2、3字节的00 01换成03 54，即完成了把该dmp文件字符集从us7ascii到zhs16gbk的转化，这样，再把该dmp文件导入到zhs16gbk字符集的数据库就可以了。（注意，十进制数与十六进制之间的转换，想明白其中的道理） <BR>Iv、跨版本使用Exp/Imp <BR>Exp/Imp很多时候，可以跨版本使用，如在版本7与版本8之间导出导入数据，但这样做必须选择正确的版本，规则为： <BR>&nbsp; &nbsp;·总是使用IMP的版本匹配数据库的版本，如果要导入到816，则使用816的导入工具。 <BR>&nbsp; &nbsp;·总是使用EXP的版本匹配两个数据库中低的那个版本，如在815与816之间互导，则使用815的EXP工具。 <BR>2、OS备份 <BR>操作系统备份有两类，冷备份（Cold backup）与热备份（Hot backup），操作系统备份与以上的逻辑备份有本质的区别。逻辑备份提取数据库的数据内容，而不备份物理数据块。而操作系统备份则是拷贝整个的数据文件。 <BR>i、冷备份 <BR>在文件级备份开始前数据库必须彻底关闭。关闭操作必须用带有normal、immediate、transaction选项的shutdown来执行。 <BR>数据库使用的每个文件都被备份下来，这些文件包括： <BR>&nbsp; &nbsp;&nbsp;&nbsp;☆所有数据文件 <BR>&nbsp; &nbsp;&nbsp;&nbsp;☆所有控制文件 <BR>&nbsp; &nbsp;&nbsp;&nbsp;☆所有联机REDO LOG 文件 <BR>&nbsp; &nbsp;&nbsp;&nbsp;☆INIT.ORA文件(可选) <BR>&nbsp; &nbsp;&nbsp;&nbsp;作冷备份一般步骤是： <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;a.正常关闭要备份的实例(instance); <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;b.备份整个数据库到一个目录 <BR>c.启动数据库 <BR>如 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; SVRMGRL&gt;connect internal <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; SVRMGRL &gt;shutdown immediate <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; SVRMGRL &gt;! cp &amp;lt;file&gt; &amp;lt;backup directory&gt; <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 或 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; SVRMGRL &gt;!tar cvf /dev/rmt/0 /u01/oradata/prod <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; SVRMGRL &gt;startup <BR>&nbsp; &nbsp; 注意：如果利用脚本对数据库进行冷备份，必须对关闭数据库的命令进行逻辑检查，如果发生关闭数据库的命令不能正常执行而导致数据库没有正常关闭，那么，所有的冷备份将回是无效的。 <BR>ii、热备份 <BR>热备份是当数据库打开并对用户有效是的OS级的数据备份。热备份只能用于ARCHIVELOG方式的数据库。在数据文件备份之前，对应的表空间必须通过使用ALTER TABLESPACE …… BEGIN BACKUP以备份方式放置。然后组成表空间的数据文件可以使用类似冷备份的操作系统命令进行拷贝。在数据文件用操作系统命令拷贝后，应使用ALTER TABLESPACE …… END BACKUP命令使表空间脱离热备份方式。 <BR>热备份没有必要备份联机日志，但必须是归档状态，在实例恢复的时候，可能需要用到归档日志。当前联机日志一定要保护好或是处于镜相状态，当前联机日志的损坏，对于数据库的损坏是巨大的，只能以数据的丢失来进行数据库的恢复工作。 <BR>对于临时表空间，存放的是临时信息，在热备份是也可以考虑不用备份，如果临时文件发生故障，可以删除该数据文件与表空间，重建一个临时表空间。 <BR>热备份的优点是显而易见的 <BR>---- a．可在表空间或数据文件级备份，备份时间短。&nbsp;&nbsp;<BR>---- b．备份时数据库仍可使用。&nbsp;&nbsp;<BR>---- c．可达到秒级恢复（恢复到某一时间点上）。&nbsp;&nbsp;<BR>---- d．可对几乎所有数据库实体作恢复。&nbsp;&nbsp;<BR>---- e．恢复是快速的，在大多数情况下在数据库仍工作时恢复。 <BR>操作系统作热备份的一般步骤为： <BR>①连接数据库 <BR>SVRMGRL&gt;connect internal; <BR>②将需要备份的表空间（如User）设置为备份方式 <BR>SVRMGRL&gt;Alter tablespace User begin backup; <BR>③拷贝数据文件 <BR>SVRMGRL&gt;!cp /u01/oradata/prod/user01.ora /backup/prod/user01.ora <BR>Or <BR>$cp cp /u01/oradata/prod/user01.ora /backup/prod/user01.ora <BR>④在数据文件拷贝完成后，将表空间拖体备份方式 <BR>SVRMGRL&gt;Alter tablespace User end backup; <BR>⑤对所有需要备份的表空间重复2，3，4 <BR>⑥使用如下的命令备份控制文件ALTER DATABSE …… BACKUP CONTROLFILE <BR>如备份成二进制文件 <BR>alter database backup controlfile to ‘new fielname’; <BR>备份成文本文件 <BR>alter database backup controlfile to trace; <BR>因为热备份的时候，用户还在操作数据库，所以，最好是每个表空间处于备份状态的时间最短，这样就要求一个表空间一个表空间的备份，不要一起使表空间处于备份状态而同时拷贝数据文件。 <BR>&nbsp; &nbsp; 注意：如果在热备份的时候如果数据库中断（如断电），那么在重新启动数据库的时候，数据库将提示有数据文件需要恢复，你需要把正在断电时候的处于备份状态的数据文件通过ALTER TABLESPACE …… END BACKUP结束备份方式。具体哪个数据文件或表空间处于备份状态，可以通过v$backup与v$datafile来获得。 <BR>3、RMAN（备份与恢复管理器） <BR>i.使用RMAN进行备份 <BR>Recovery manager（RMAN）是ORACLE提供的DBA工具，用语管理备份和恢复操作。RMAN只能用于ORACLE8或更高的版本中。它能够备份整个数据库或数据库部件，其中包括表空间、数据文件，控制文件和归档文件。RMAN可以按要求存取和执行备份和恢复。 <BR>RMAN备份有如下优点 <BR>☆支持在线热备份 <BR>☆支持多级增量备份 <BR>☆支持并行备份、恢复 <BR>☆减少所需要备份量 <BR>☆备份、恢复使用简单 <BR>&nbsp; &nbsp; 重要的是，使用恢复管理器允许您进行增量数据块级的备份（这个与导出/导入的增量截然不同）。增量RMAN备份是时间和空间有效的，因为他们只备份自上次备份以来有变化的那些数据块。另一个空间有效的RMAN特性是它只备份数据文件中使用的数据块，忽略空的，未用的数据块，这个对于预分配空间的表空间有很大的好处。 <BR>&nbsp; &nbsp;从9i开始，还增加了RMAN的数据块级别的恢复，可以进一步减少数据库恢复时间。 <BR>RMAN支持以下不同类型的备份 <BR>FULL&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;数据库全备份，包括所有的数据块 <BR>INCREMENTAL&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;增量备份，只备份自上次增量备份以来修改过的数据块。需要一个0级的增量作为增量的基础，可以支持5级增量。 <BR>OPEN&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;在数据库打开的时候使用 <BR>CLOSED&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;在数据库安装(MOUNT)但不打开的时候备份，关闭备份可以是CONSISTENT或IN CONSISTENT类型的。 <BR>CONSISTENT&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 在数据库安装，单不打开，并且在安装之前数据库被彻底关闭（而不是被破坏或异常退出）时使用。CONSISTENT备份可以简单的进行复原(RESTORE)而不是恢复(RECOVER) <BR>INCONSISTENT&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;在数据库打开或安装（但不打开）时使用。在该数据库正常关闭或崩溃后，INCONSISTENT备份需要恢复。 <BR>理解BACKUP，RESTORE，RECOVER命令，这是RMAN最基本的三个命令，可以进行数据库的备份，复原以及恢复操作。 <BR>&nbsp; &nbsp; 理解恢复目录，RMAN可以在没有恢复目录(NOCATALOG)下运行，这个时候备份信息保存在控制文件。保存在控制文件的备份信息是很危险的，如果控制文件的破坏将导致备份信息的丢失与恢复的失败，而且，没有恢复目录，很多RMAN的命令将不被支持。所以对于重要的数据库，建议创建恢复目录，恢复目录也是一个数据库，只不过这个数据库用来保存备份信息，一个恢复目录可以用来备份多个数据库。 <BR>&nbsp; &nbsp;创建RMAN目录，以下步骤说明了在一个数据库中尽力RMAN目录的过程。 <BR>a.为目录创建一个单独的表空间 <BR>SQL&gt;Create tablespace tools datafile ‘fielname’ size 50m; <BR>b.创建RMAN用户 <BR>SQL&gt;Create user RMAN identified by RMAN default tablespace tools temporary tablespace temp; <BR>c.给RMAN授予权限 <BR>SQL&gt;Grant connect , resource , recovery_catalog_owner to rman; <BR>d.打开RMAN <BR>$&gt;RMAN <BR>e.连接数据库 <BR>RMAN&gt;connect catalog rman/rman <BR>f.创建恢复目录 <BR>RMAN&gt;Create catalog tablespace rman <BR>注册目标数据库，恢复目录创建成功后，就可以注册目标数据库了，目标数据库就是需要备份的数据库，一个恢复目录可以注册多个目标数据库，注册目标数据库的命令为： <BR>&nbsp; &nbsp;&nbsp;&nbsp;$&gt;RMAN target internal/password catalog rman/rman@rcdb; <BR>RMAN&gt;Register database; <BR>数据库注册完成,就可以用RMAN来进行备份了，更多命令请参考ORACLE联机手册或《ORACLE8i备份与恢复手册》。 <BR>RMAN使用脚本来备份数据库，以下是RMAN进行备份的几个例子。 <BR>a.备份整个数据库 <BR>backup full tag ‘basicdb’ format ‘/bak/oradata/full_%u_%s_%p’ database; <BR>b.备份一个表空间 <BR>&nbsp; &nbsp;&nbsp; &nbsp; backup tag ‘tsuser’ format ‘/bak/oradata/tsuser_%u_%s_%p’ tablespace users; <BR>c.备份归档日志 <BR>backup tag ‘alog’ format ‘/bak/archivebak/arcbak_%u_%s_%p’ archivelog all delete input; <BR>ii.维护RMAN <BR>&nbsp;&nbsp;RMAN的维护主要分为几个方面 <BR>1、&nbsp;&nbsp;查看RMAN的信息 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;检查现有备份 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RMAN&gt;list backup <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;列出过期备份 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RMAN&gt;report obsolete <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;删除过期的备份 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RMAN&gt;allocate channel for maintenance type disk; <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RMAN&gt;change backupset id delete; <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RMAN&gt;release channel; <BR>2、&nbsp;&nbsp;同步或重置RMAN <BR>如果目标数据库物理对象发生了变化，如添加了一个数据文件，需要用如下命令同步： <BR>RMAN&gt;resync catalog; <BR>如果目标数据库reset了数据库，需要用如下命令同步 <BR>RMAN&gt;reset database; <BR>当手工删除了数据库的归档文件后，要执行以下脚本同步 <BR>RMAN&gt;allocate channel for maintenance type disk; <BR>RMAN&gt; change archivelog all crosscheck; <BR>RMAN&gt;release channel; <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;当手工删除了数据库的RMAN备份后，要执行以下脚本来同步 <BR>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; RMAN&gt;allocate channel for maintenance type disk; <BR>RMAN&gt;crosscheck backup; <BR>RMAN&gt;delete expired backup; <BR>RMAN&gt;release channel; <BR>四、定制恰当的备份策略 <BR>i.定制正确的策略 <BR>正确的备份策略不仅能保证数据库服务器的24*7的高性能的运行，还能保证备份与恢复的快速性与可靠性。我们将以RMAN的多级增量备份作为一个备份策略的例子来讨论。采用多级备份就是为了减少每天备份所需要的时间，而又保证系统有良好的恢复性。恢复时间与备份时间要有一个权衡。比如只要进行一个数据库的全备份，然后就只备份归档也可以保证能把数据库恢复到最新的状态，但是这样的恢复时间将是不可容忍的。多级备份也正是&nbsp; &nbsp;&nbsp;&nbsp;为了解决这种问题，以下就是一个多级备份的例子： <BR>每半年做一个数据库的全备份（包括所有的数据和只读表空间） <BR>每一个月做一次零级备份（不包含只读表空间） <BR>每个星期做一次一级备份 <BR>每天做一次二级备份 <BR>任何数据库的更改需要重新同步CATALOG目录并重新备份（如添加数据文件）或重新备份（如修改表空间为只读） <BR>每次备份后都可以备份归档日志或定期备份归档日志。 <BR>如果可能，可以直接备份到磁带上。 <BR>数据库全备份的脚本 <BR>run{ <BR>allocate channel c1 type disk; <BR>allocate channel c2 type disk; <BR>allocate channel c3 type disk; <BR>backup full tag ‘dbfull’ format ‘/u01/oradata/backup/full%u_%s_%p’ database <BR>include current controlfile; <BR>sql ‘alter system archive log current’; <BR>backup fileaperset 3 format ‘/u01/oradata/backup/arch%u_%s_%p’&nbsp;&nbsp;<BR>archivelog all delete input;&nbsp; &nbsp;#备份归档可选，可以单独定期备份 <BR>release channel c1; <BR>release channel c2; <BR>release channel c3; <BR>} <BR>零级备份的脚本 <BR>run{ <BR>allocate channel c1 type disk; <BR>allocate channel c2 type disk; <BR>allocate channel c3 type disk; <BR>backup incremental level 0 tag ‘db0’ format ‘/u01/oradata/backup/db0%u_%s_%p’&nbsp;&nbsp;<BR>database skip readonly; <BR>sql ‘alter system archive log current’; <BR>backup fileaperset 3 format ‘/u01/oradata/backup/arch%u_%s_%p’&nbsp;&nbsp;<BR>archivelog all delete input;&nbsp; &nbsp;#备份归档可选，可以单独定期备份 <BR>release channel c1; <BR>release channel c2; <BR>release channel c3; <BR>} <BR>同理，我们可以得到一级备份，二级备份的脚本，如一级备份的脚本 <BR>run{ <BR>allocate channel c1 type disk; <BR>allocate channel c2 type disk; <BR>allocate channel c3 type disk; <BR>backup incremental level 1 tag ‘db1’ format ‘/u01/oradata/backup/db1%u_%s_%p’&nbsp;&nbsp;<BR>database skip readonly; <BR>sql ‘alter system archive log current’; <BR>backup fileaperset 3 format ‘/u01/oradata/backup/arch%u_%s_%p’&nbsp;&nbsp;<BR>archivelog all delete input;&nbsp; &nbsp;#备份归档可选，可以单独定期备份 <BR>release channel c1; <BR>release channel c2; <BR>release channel c3; <BR>} <BR>如果按照以上备份策略，则每天的所需要备份的数据量只有一天的改变量。而做恢复时最多要恢复当月的一个零级备份+三个一级备份+6个二级备份+当天的归档文件。如果不能接受这样的恢复时间，可以减少零级备份之间的时间间隔。 <BR>&nbsp; &nbsp;&nbsp;&nbsp;在每次备份后，原则上在该备份点之前的归档日志就可以删除掉了，但是为了进一步的安全以及日后需要（如使用LOGMNR查找所需信息），建议有条件的话，归档日志保存一年，可以保存在磁带等廉价存取设备上。 <BR>ii.与RMAN备份有关的优化 <BR>备份操作主要是完成以下三个步骤 <BR>1、从磁盘上读取数据 <BR>2、在内存中处理数据块 <BR>3、写入数据到磁盘或磁带 <BR>以上的读写操作可以同步或异步的完成，在同步I/O操作中，一个时间只允许有一个IO操作，但是在异步I/O操作中，一个时间允许有多个IO操作。因此，备份与恢复的调优主要集中在以下几个方面： <BR>1、&nbsp;&nbsp;提高同步或异步I/O操作能力 <BR>在支持异步操作的操作系统上，可以通过设置TAPE_AYSNCH_IO,DISK_ASYNCH_IO和BACKUP_TYPE_IO_SLAVES来支持异步操作，提高写的能力。 <BR>2、&nbsp;&nbsp;提高磁盘读能力 <BR>可以在backup命令后通过设置DISKRATIO来保证从多个磁盘上读取数据，保证连续的数据流。 <BR>3、&nbsp;&nbsp;正确设置缓冲区与参数值 <BR>设置LARGE_POOL_SIZE，使备份可以使用连续的缓冲池，通过设置DB_FIL_DIRECT_IO_COUNT可以提高缓冲区的利用。如果使用磁带备份，还可以设置BACKUP_TYPE_IO_SLAVES来提高磁带的写能力。 <BR>4、&nbsp;&nbsp;采用并行备份 <BR>开辟多个通道，可以实现并行备份与恢复 <BR>&nbsp;&nbsp;<BR>iii.备份RMAN数据库 <BR>RMAN自己的数据库也需要备份，但是本身很小，而且不是经常发生变化，所以在每次RMAN备份完成后，都可以用如下脚本对RMAN数据库备份。 <BR>EXP pafile =exprman.sql <BR>exprman.sql为 <BR>USERID=RMAN/RMAN <BR>BUFFER=32768 <BR>OWNER=RMAN <BR>FILE=RMAN.DMP <BR>ROWS=Y <BR>GRANTS=Y <BR>COMPRESS=Y <BR>CONSISTENT=Y <BR>iv.使自动备份数据库 <BR>自动备份数据库不外乎以下三种方式 <BR>&nbsp; &nbsp;&nbsp;&nbsp;WINDOWS下的任务计划(At命令) <BR>&nbsp; &nbsp;&nbsp;&nbsp;UNIX下的Crontab <BR>&nbsp; &nbsp;&nbsp;&nbsp;第三方工具如Viritas <BR>在以上三种方式中Viritas属于第三方工具，很多人可能都没有接触，主要说一下windows的任务计划与unix的cron <BR>1、生成脚本文件，如backup.rcv <BR>假定文件内容如下： <BR>$&gt;cat backup.rcv <BR>connect target sys/password rcvcat rman/rman@localname; <BR>run{ <BR>allocate channel c1 type disk; <BR>allocate channel c2 type disk; <BR>allocate channel c3 type disk; <BR>backup fileaperset 3 format ‘/u01/oradata/backup/arch%u_%s_%p’&nbsp;&nbsp;<BR>archivelog all delete input;&nbsp; &nbsp; <BR>release channel c1; <BR>release channel c2; <BR>release channel c3; <BR>} <BR>&nbsp; &nbsp;2、生成执行文件 <BR>在windows上生成backup_archive.bat，内容包括 <BR>rman cmdfile = backup.rcv <BR>在unix下生成 backup_archive.sh，内容包括 <BR>/oracle/ramn/rman cmdfile = backup.rcv <BR>&nbsp;&nbsp;3、加入调度 <BR>在windows中用任务计划向导即可，或使用at命令。 <BR>在unix中，在目标机器上编写一个文件，用以启动自动备份进程。假定文件名为ORACLE，文件将放在/var/spool/cron/crontabs目录下 <BR>$&gt;cat oracle <BR>0 23 * * 0 backup_archive.sh <BR>#表示星期天23点对数据库备份 <BR>0 12,18 * * * backup_archive.sh <BR>&nbsp; &nbsp;&nbsp;&nbsp;#表示每天12点，18点备份 <BR>Crontab文件的每一行由六个域(minutes,hours,day of month,month,day of week,command)组成，域之间用空格或Tab分隔开来 <BR>五、常见误区 <BR>1、使用EXP/IMP备份 <BR>EXP/IMP不是一个良好的备份工具，在以后的发展之中，ORACLE对EXP/IMP用于备份的支持会越来越低。ORACLE只是把EXP/IMP当作一个好的工具而不是备份工具，在对于大型数据库，如TB级数据库或数据仓库，EXP/IMP肯定会力不从心。 <BR>2、在应用程序中备份数据库 <BR>在论坛上，有很多这样的要求，“我怎么在程序中备份与恢复数据库？”。首先说，这个并不是不可以实现，但是实现的过程会很复杂而且意外会很多。就我的感觉，提出这样问题的人，首先一点就是对ORACLE或DBA的不了解，如果ORACLE可以这么轻松的实现备份与恢复，那么我可以说，就不需要DBA了。 <BR>3、冷备份比热备份更容易，效果会更好 <BR>有人认为，冷备份是关闭数据库进行的一致性备份，肯定比热备份要好，使用也容易，其实不尽然，在热备份中，一样可以实现数据库的全备份，而且不会影响到数据库的运行。建议所有的生产机，都运行在归档方式下，采用热备份方式。 <BR>六、常见问题 <BR>1、我导出的数据为什么不能导入，提示不支持的字符集转换 <BR>答：参考上面的字符集原则，导出数据时客户端与数据库字符集一致，导入时修改为与目标数据库字符集一致。 <BR>2、我的归档日志越来越多，我什么时候可以删除归档日志？ <BR>答：在每一次全备份（如OS全冷备份或全热备份）或基于全备份的增量备份（如RMAN基于0级备份上的增量备份）后都可以删除该备份点之前的归档日志，建议在磁带上保留一年。 <BR>3、全备份时一定需要备份所有数据文件吗？ <BR>答：不需要，起码有两类数据文件可以不备份，一类就是临时数据文件，如果丢失，可以删除后重建；一类是只读表空间数据文件，如果上次备份以来，没有修改过表空间的只读属性，就可以不需要备份。 <BR>4、联机日志需要备份吗？ <BR>答：如果是归档方式热备份，就没有必要备份联机日志。但是对于冷备份，可以备份联机日志，特别是不归档状态。备份过联机日志后的冷备份，因为数据库是一致的，可以恢复到该备份点。 <BR>七、小结 <BR>1、什么是数据库备份，数据库备份就是把数据库复制到转储设备的过程。 <BR>&nbsp; &nbsp;2、数据库的运行方式，可以分为归档方式和非归档方式，建议运行在归档方式下运行热备份。 <BR>&nbsp; &nbsp;3、了解了数据库的备份方式，逻辑备份、冷备份、热备份 <BR>&nbsp; &nbsp;4、了解数据库的备份工具，EXP/IMP执行逻辑备份，OS脚本可以执行冷备份或热备份，RMAN也可以执行冷备份或热备份 <BR>&nbsp; &nbsp;5、了解ORACLE的备份策略，并怎样选择最佳的备份策略 <BR>&nbsp; &nbsp;6、知道怎么样启动自动备份，了解Windows的at命令与unix的cron进程。 <BR>参考文献： <BR>Expert One-on-one Oracle&nbsp;&nbsp;[美] Thomas Kyte 著 清华大学出版社 <BR>Oracle 8i Web开发指南 [美] Dan Hotka,et al. 著 清华大学出版社 <BR>Oracle 8i DBA Architecture &amp; Administration and backup &amp; Recovery Study Guide <BR>&nbsp;&nbsp;[美] Dong Stuns Biju Thomas著 电子工业出版社 <BR>Oracle 数据库管理员技术指南 [美] Sumit Sarin著 机械工业出版社<BR>]]></description>
</item><item>
<title><![CDATA[java读取oracle的存储过程]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8233</link>
<author>blakestone</author>
<pubDate>2005/9/3 14:53:06</pubDate>
<description><![CDATA[java读取oracle的存储过程网上的例子不少，都太简单，没有一个返回参考游标的,返回记录集，自己写一个怕日后忘了。
<P>oracle的PLSQL</P>
<P>CREATE OR REPLACE package chapter_13 as<BR>&nbsp;TYPE rs IS REF CURSOR ;<BR>procedure founder(oFields out rs);</P>
<P>end;</P>
<P>CREATE OR REPLACE package body chapter_13 as</P>
<P>PROCEDURE founder(oFields out rs) IS<BR>BEGIN<BR>&nbsp; open oFields for<BR>&nbsp;&nbsp; select * from person;<BR>END founder;<BR>end;<BR>java代码</P>
<P>package jdbc;</P>
<P>import java.io.*;<BR>import java.sql.*;<BR>import java.text.*;<BR>import oracle.jdbc.OracleTypes;</P>
<P>public class TestStoredProcedures {<BR>&nbsp;&nbsp;&nbsp; Connection conn;</P>
<P>&nbsp;&nbsp;&nbsp; public TestStoredProcedures() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn = DriverManager.getConnection(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "jdbc:oracle:thin:@localhost:1521:orcl", "jola", "jola");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println(e.getMessage());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new TestStoredProcedures().process();<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; public void process() throws SQLException {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long start = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long end = 0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CallableStatement cstmt = null;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; start = System.currentTimeMillis();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // *** SQL92 escape syntax ***</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cstmt = conn.prepareCall(<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "{call&nbsp; chapter_13.founder(?)}");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cstmt.registerOutParameter(1, OracleTypes.CURSOR);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResultSet rs = null;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cstmt.execute();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs = (ResultSet)cstmt.getObject(1);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (rs.next()) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(rs.getString("NAME"));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rs.close();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end = System.currentTimeMillis();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Average elapsed 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; (end - start) / 8 + " milliseconds");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println("SQL Error: " + e.getMessage());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (cstmt != null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cstmt.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException ignore) {}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; protected void finalize() throws Throwable {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (conn != null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException ignore) {}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.finalize();<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>]]></description>
</item><item>
<title><![CDATA[理解和使用Oracle 8i分析工具－LogMiner]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=blakestone&amp;id=8232</link>
<author>blakestone</author>
<pubDate>2005/9/3 13:05:41</pubDate>
<description><![CDATA[看到有人想審計用戶對數據庫的操作，<U><B><FONT color=#ff0000>logminer</FONT></B></U> 是各不錯的工具<BR><BR>理解和使用Oracle 8i分析工具－<U><B><FONT color=#ff0000>logminer</FONT></B></U> <BR>　　Oracle <U><B><FONT color=#ff0000>logminer</FONT></B></U> 是Oracle公司从产品8i以后提供的一个实际非常有用的分析工具，使用该工具可以轻松获得Oracle 重作日志文件（归档日志文件）中的具体内容，特别是，该工具可以分析出所有对于数据库操作的DML（insert、update、delete等）语句，另外还可分析得到一些必要的回滚SQL语句。该工具特别适用于调试、审计或者回退某个特定的事务。 <BR><BR>　　<U><B><FONT color=#ff0000>logminer</FONT></B></U>分析工具实际上是由一组PL/SQL包和一些动态视图（Oracle8i内置包的一部分）组成，它作为Oracle数据库的一部分来发布，是8i产品提供的一个完全免费的工具。但该工具和其他Oracle内建工具相比使用起来显得有些复杂，主要原因是该工具没有提供任何的图形用户界面（GUI）。本文将详细介绍如何安装以及使用该工具。 <BR><BR>　　一、<U><B><FONT color=#ff0000>logminer</FONT></B></U>的用途 <BR><BR>　　日志文件中存放着所有进行数据库恢复的数据，记录了针对数据库结构的每一个变化，也就是对数据库操作的所有DML语句。 <BR><BR>　　在Oracle 8i之前，Oracle没有提供任何协助数据库管理员来读取和解释重作日志文件内容的工具。系统出现问题，对于一个普通的数据管理员来讲，唯一可以作的工作就是将所有的log文件打包，然后发给Oracle公司的技术支持，然后静静地等待Oracle 公司技术支持给我们最后的答案。然而从8i以后，Oracle提供了这样一个强有力的工具-<U><B><FONT color=#ff0000>logminer</FONT></B></U>。 <BR><BR>　　<U><B><FONT color=#ff0000>logminer</FONT></B></U> 工具即可以用来分析在线，也可以用来分析离线日志文件，即可以分析本身自己数据库的重作日志文件，也可以用来分析其他数据库的重作日志文件。 <BR><BR>　　总的说来，<U><B><FONT color=#ff0000>logminer</FONT></B></U>工具的主要用途有： <BR><BR>　　　1． 跟踪数据库的变化：可以离线的跟踪数据库的变化，而不会影响在线系统的性能。 <BR><BR>　　　2． 回退数据库的变化：回退特定的变化数据，减少point-in-time recovery的执行。 <BR><BR>　　　3． 优化和扩容计划：可通过分析日志文件中的数据以分析数据增长模式。 <BR><BR>　　二、安装<U><B><FONT color=#ff0000>logminer</FONT></B></U> <BR><BR>　　要安装<U><B><FONT color=#ff0000>logminer</FONT></B></U>工具，必须首先要运行下面这样两个脚本， <BR><BR>　　　l $ORACLE_HOME/rdbms/admin/dbmslsm.sql <BR><BR>　　　2 $ORACLE_HOME/rdbms/admin/dbmslsmd.sql. <BR><BR>　　这两个脚本必须均以SYS用户身份运行。其中第一个脚本用来创建DBMS_LOGMNR包，该包用来分析日志文件。第二个脚本用来创建DBMS_LOGMNR_D包，该包用来创建数据字典文件。 <BR><BR><BR><BR>　　三、使用<U><B><FONT color=#ff0000>logminer</FONT></B></U>工具 <BR><BR>　　下面将详细介绍如何使用<U><B><FONT color=#ff0000>logminer</FONT></B></U>工具。 <BR><BR>　　1、创建数据字典文件（data-dictionary） <BR><BR>　　前面已经谈到，<U><B><FONT color=#ff0000>logminer</FONT></B></U>工具实际上是由两个新的PL/SQL内建包（(DBMS_LOGMNR 和 DBMS_ LOGMNR_D）和四个V$动态性能视图（视图是在利用过程DBMS_LOGMNR.START_LOGMNR启动<U><B><FONT color=#ff0000>logminer</FONT></B></U>时创建）组成。在使用<U><B><FONT color=#ff0000>logminer</FONT></B></U>工具分析redo log文件之前，可以使用DBMS_LOGMNR_D 包将数据字典导出为一个文本文件。该字典文件是可选的，但是如果没有它，<U><B><FONT color=#ff0000>logminer</FONT></B></U>解释出来的语句中关于数据字典中的部分（如表名、列名等）和数值都将是16进制的形式，我们是无法直接理解的。例如，下面的sql语句： <BR><BR>INSERT INTO dm_dj_swry (rydm, rymc) VALUES (00005, '张三'); <BR><BR>　　<U><B><FONT color=#ff0000>logminer</FONT></B></U>解释出来的结果将是下面这个样子， <BR><BR>insert into Object#308(col#1, col#2) values (hextoraw('c30rte567e436'), hextoraw('4a6f686e20446f65')); <BR><BR>　　创建数据字典的目的就是让<U><B><FONT color=#ff0000>logminer</FONT></B></U>引用涉及到内部数据字典中的部分时为他们实际的名字，而不是系统内部的16进制。数据字典文件是一个文本文件，使用包DBMS_LOGMNR_D来创建。如果我们要分析的数据库中的表有变化，影响到库的数据字典也发生变化，这时就需要重新创建该字典文件。另外一种情况是在分析另外一个数据库文件的重作日志时，也必须要重新生成一遍被分析数据库的数据字典文件。 <BR><BR>　　首先在init.ora初始化参数文件中，指定数据字典文件的位置，也就是添加一个参数UTL_FILE_DIR，该参数值为服务器中放置数据字典文件的目录。如： <BR><BR>UTL_FILE_DIR = (e:\Oracle\logs) <BR><BR>　　重新启动数据库，使新加的参数生效，然后创建数据字典文件： <BR><BR>SQL&gt; CONNECT SYS <BR>SQL&gt; EXECUTE dbms_logmnr_d.build( <BR>dictionary_filename =&gt; ' v816dict.ora', <BR>dictionary_location =&gt; 'e:\oracle\logs'); <BR><BR><BR><BR>　　2、创建要分析的日志文件列表 <BR><BR>　　Oracle的重作日志分为两种，在线（online）和离线（offline）归档日志文件，下面就分别来讨论这两种不同日志文件的列表创建。 <BR><BR>　　（1）分析在线重作日志文件 <BR><BR>　　A. 创建列表 <BR><BR>SQL&gt; EXECUTE dbms_logmnr.add_logfile( <BR>LogFileName=&gt;' e:\Oracle\oradata\sxf\redo01.log', <BR>Options=&gt;dbms_logmnr.new); <BR><BR>　　B. 添加其他日志文件到列表 <BR><BR>SQL&gt; EXECUTE dbms_logmnr.add_logfile( <BR>LogFileName=&gt;' e:\Oracle\oradata\sxf\redo02.log', <BR>Options=&gt;dbms_logmnr.addfile); <BR><BR>　　（2）分析离线日志文件 <BR><BR>　　A.创建列表 <BR><BR>SQL&gt; EXECUTE dbms_logmnr.add_logfile( <BR>LogFileName=&gt;' E:\Oracle\oradata\sxf\archive\ARCARC09108.001', <BR>Options=&gt;dbms_logmnr.new); <BR><BR>　　B.添加另外的日志文件到列表 <BR><BR>SQL&gt; EXECUTE dbms_logmnr.add_logfile( <BR>LogFileName=&gt;' E:\Oracle\oradata\sxf\archive\ARCARC09109.001', <BR>Options=&gt;dbms_logmnr.addfile); <BR><BR>　　关于这个日志文件列表中需要分析日志文件的个数完全由你自己决定，但这里建议最好是每次只添加一个需要分析的日志文件，在对该文件分析完毕后，再添加另外的文件。 <BR><BR>　　和添加日志分析列表相对应，使用过程 'dbms_logmnr.removefile' 也可以从列表中移去一个日志文件。下面的例子移去上面添加的日志文件e:\Oracle\oradata\sxf\redo02.log。 <BR><BR>SQL&gt; EXECUTE dbms_logmnr.add_logfile( <BR>LogFileName=&gt;' e:\Oracle\oradata\sxf\redo02.log', <BR>Options=&gt;dbms_logmnr. REMOVEFILE); <BR><BR>　　创建了要分析的日志文件列表，下面就可以对其进行分析了。 <BR>3、使用<U><B><FONT color=#ff0000>logminer</FONT></B></U>进行日志分析 <BR><BR>　　（1）无限制条件 <BR><BR>SQL&gt; EXECUTE dbms_logmnr.start_logmnr( <BR>DictFileName=&gt;' e:\oracle\logs\ v816dict.ora '); <BR><BR>　　（2）有限制条件 <BR><BR>　　通过对过程DBMS_ LOGMNR.START_LOGMNR中几个不同参数的设置（参数含义见表1），可以缩小要分析日志文件的范围。通过设置起始时间和终止时间参数我们可以限制只分析某一时间范围的日志。如下面的例子，我们仅仅分析2001年9月18日的日志，： <BR><BR>SQL&gt; EXECUTE dbms_logmnr.start_logmnr( <BR>DictFileName =&gt; ' e:\oracle\logs\ v816dict.ora ', <BR>StartTime =&gt; to_date('2001-9-18 00:00:00','YYYY-MM-DD HH24:MI:SS') <BR>EndTime =&gt; to_date(''2001-9-18 23:59:59','YYYY-MM-DD HH24:MI:SS ')); <BR><BR>　　也可以通过设置起始SCN和截至SCN来限制要分析日志的范围： <BR><BR>SQL&gt; EXECUTE dbms_logmnr.start_logmnr( <BR>DictFileName =&gt; ' e:\oracle\logs\ v816dict.ora ', <BR>StartScn =&gt; 20, <BR>EndScn =&gt; 50); <BR><BR>　　表1 DBMS_LOGMNR.START__LOGMNR过程参数含义 <BR><BR>参数 参数类型 默认值 含义 <BR>StartScn 数字型（Number） 0 分析重作日志中SCN≥StartScn日志文件部分 <BR>EndScn 数字型（Number） 0 分析重作日志中SCN≤EndScn日志文件部分 <BR>StartTime 日期型(Date) 1998-01-01 分析重作日志中时间戳≥StartTime的日志文件部分 <BR>EndTime 日期型(Date) 2988-01-01 分析重作日志中时间戳≤EndTime的日志文件部分 <BR>DictFileName 字符型(VARCHAR2) 字典文件，该文件包含一个数据库目录的快照。使用该文件可以使得到的分析结果是可以理解的文本形式，而非系统内部的16进制 <BR>Options BINARY_INTEGER 0 系统调试参数，实际很少使用 <BR><BR><BR><BR>　　4、观察分析结果（v$logmnr_contents） <BR><BR>　　到现在为止，我们已经分析得到了重作日志文件中的内容。动态性能视图v$logmnr_contents包含<U><B><FONT color=#ff0000>logminer</FONT></B></U>分析得到的所有的信息。 <BR><BR>SELECT sql_redo FROM v$logmnr_contents; <BR><BR>　　如果我们仅仅想知道某个用户对于某张表的操作，可以通过下面的SQL查询得到，该查询可以得到用户DB_ZGXT对表SB_DJJL所作的一切工作。 <BR><BR>SQL&gt; SELECT sql_redo FROM v$logmnr_contents WHERE username='DB_ZGXT' AND tablename='SB_DJJL'; <BR><BR>　　需要强调一点的是，视图v$logmnr_contents中的分析结果仅在我们运行过程'dbms_logmrn.start_logmnr'这个会话的生命期中存在。这是因为所有的<U><B><FONT color=#ff0000>logminer</FONT></B></U>存储都在PGA内存中，所有其他的进程是看不到它的，同时随着进程的结束，分析结果也随之消失。 <BR><BR>　　最后，使用过程DBMS_LOGMNR.END_LOGMNR终止日志分析事务，此时PGA内存区域被清除，分析结果也随之不再存在。 <BR><BR>　　四、其他注意事项 <BR><BR>　　我们可以利用<U><B><FONT color=#ff0000>logminer</FONT></B></U>日志分析工具来分析其他数据库实例产生的重作日志文件，而不仅仅用来分析本身安装<U><B><FONT color=#ff0000>logminer</FONT></B></U>的数据库实例的redo logs文件。使用<U><B><FONT color=#ff0000>logminer</FONT></B></U>分析其他数据库实例时，有几点需要注意： <BR><BR>　　1. <U><B><FONT color=#ff0000>logminer</FONT></B></U>必须使用被分析数据库实例产生的字典文件，而不是安装<U><B><FONT color=#ff0000>logminer</FONT></B></U>的数据库产生的字典文件，另外必须保证安装<U><B><FONT color=#ff0000>logminer</FONT></B></U>数据库的字符集和被分析数据库的字符集相同。 <BR><BR>　　2. 被分析数据库平台必须和当前<U><B><FONT color=#ff0000>logminer</FONT></B></U>所在数据库平台一样，也就是说如果我们要分析的文件是由运行在UNIX平台上的Oracle 8i产生的，那么也必须在一个运行在UNIX平台上的Oracle实例上运行<U><B><FONT color=#ff0000>logminer</FONT></B></U>，而不能在其他如Microsoft NT上运行<U><B><FONT color=#ff0000>logminer</FONT></B></U>。当然两者的硬件条件不一定要求完全一样。 <BR><BR>　　3. <U><B><FONT color=#ff0000>logminer</FONT></B></U>日志分析工具仅能够分析Oracle 8以后的产品，对于8以前的产品，该工具也无能为力。 <BR><BR>　　五、结语 <BR><BR>　　<U><B><FONT color=#ff0000>logminer</FONT></B></U>对于数据库管理员（DBA）来讲是个功能非常强大的工具，也是在日常工作中经常要用到的一个工具，借助于该工具，可以得到大量的关于数据库活动的信息。其中一个最重要的用途就是不用全部恢复数据库就可以恢复数据库的某个变化。另外，该工具还可用来监视或者审计用户的活动，如你可以利用<U><B><FONT color=#ff0000>logminer</FONT></B></U>工具察看谁曾经修改了那些数据以及这些数据在修改前的状态。我们也可以借助于该工具分析任何Oracle 8及其以后版本产生的重作日志文件。另外该工具还有一个非常重要的特点就是可以分析其他数据库的日志文件。总之，该工具对于数据库管理员来讲，是一个非常有效的工具，深刻理解及熟练掌握该工具，对于每一个数据库管理员的实际工作是非常有帮助的。]]></description>
</item>
</channel>
</rss>