﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-见酒就晕-文章分类-DB</title><link>http://www.blogjava.net/franlk/category/9529.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 02 Apr 2008 12:21:27 GMT</lastBuildDate><pubDate>Wed, 02 Apr 2008 12:21:27 GMT</pubDate><ttl>60</ttl><item><title>[摘录]ORACLE系统表处理</title><link>http://www.blogjava.net/franlk/articles/190384.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Wed, 02 Apr 2008 07:31:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/190384.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/190384.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/190384.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/190384.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/190384.html</trackback:ping><description><![CDATA[<br />
摘录地址：<a href="http://daniel-wuz.javaeye.com/blog/145925">http://daniel-wuz.javaeye.com/blog/145925</a><br />
<br />
<p>1.取得指定用户的所有表名： <br />
Java代码 <br />
SELECT OWNER&nbsp; AS "对象所有者",OBJECT_NAME AS "表名",OBJECT_ID AS "对象编号" from dba_objects where owner = 'RAXNYB' AND OBJECT_TYPE = 'TABLE' ORDER BY OWNER,OBJECT_TYPE;&nbsp;&nbsp; <br />
或&nbsp;&nbsp; <br />
OWNER&nbsp; AS "对象所有者",TABLE_NAME AS "表名" from DBA_TABLES where owner = 'RAXNYB'&nbsp; ORDER BY OWNER,TABLE_NAME;&nbsp; </p>
<p>SELECT OWNER&nbsp; AS "对象所有者",OBJECT_NAME AS "表名",OBJECT_ID AS "对象编号" from dba_objects where owner = 'RAXNYB' AND OBJECT_TYPE = 'TABLE' ORDER BY OWNER,OBJECT_TYPE;<br />
或<br />
OWNER&nbsp; AS "对象所有者",TABLE_NAME AS "表名" from DBA_TABLES where owner = 'RAXNYB'&nbsp; ORDER BY OWNER,TABLE_NAME;</p>
<p><br />
2.取得指定用户的所有视图名称： <br />
Java代码 <br />
SELECT OWNER&nbsp; AS "对象所有者",VIEW_NAME AS "视图名称" from DBA_VIEWS&nbsp; where owner = 'RAXNYB'&nbsp; ORDER BY OWNER,VIEW_NAME;&nbsp; </p>
<p>SELECT OWNER&nbsp; AS "对象所有者",VIEW_NAME AS "视图名称" from DBA_VIEWS&nbsp; where owner = 'RAXNYB'&nbsp; ORDER BY OWNER,VIEW_NAME;</p>
<p><br />
oracle系统表查询 </p>
<p>1.用户： <br />
Java代码 <br />
select username from dba_users;&nbsp; </p>
<p>select username from dba_users;</p>
<p>改口令 <br />
Java代码 <br />
alter user spgroup identified by spgtest;&nbsp;&nbsp; </p>
<p>alter user spgroup identified by spgtest; </p>
<p><br />
2.表空间: <br />
Java代码 <br />
select * from dba_data_files;&nbsp;&nbsp;&nbsp; <br />
select * from dba_tablespaces;//表空间&nbsp;&nbsp;&nbsp; <br />
select tablespace_name,sum(bytes), sum(blocks) from dba_free_space group by tablespace_name;//空闲表空间&nbsp;&nbsp;&nbsp; <br />
select * from dba_data_files where tablespace_name='RBS';//表空间对应的数据文件&nbsp;&nbsp;&nbsp; <br />
select * from dba_segments where tablespace_name='INDEXS';&nbsp;&nbsp; </p>
<p>select * from dba_data_files; <br />
select * from dba_tablespaces;//表空间 <br />
select tablespace_name,sum(bytes), sum(blocks) from dba_free_space group by tablespace_name;//空闲表空间 <br />
select * from dba_data_files where tablespace_name='RBS';//表空间对应的数据文件 <br />
select * from dba_segments where tablespace_name='INDEXS'; </p>
<p><br />
3.数据库对象 <br />
Java代码 <br />
select * from dba_objects;&nbsp;&nbsp;&nbsp; <br />
&nbsp; <br />
CLUSTER、DATABASE LINK、FUNCTION、INDEX、LIBRARY、PACKAGE、PACKAGE BODY、PROCEDURE、SEQUENCE、SYNONYM、TABLE、TRIGGER、TYPE、UNDEFINED、VIEW。&nbsp; </p>
<p>select * from dba_objects; </p>
<p>CLUSTER、DATABASE LINK、FUNCTION、INDEX、LIBRARY、PACKAGE、PACKAGE BODY、PROCEDURE、SEQUENCE、SYNONYM、TABLE、TRIGGER、TYPE、UNDEFINED、VIEW。</p>
<p><br />
4.表 <br />
Java代码 <br />
select * from dba_tables;&nbsp;&nbsp;&nbsp; <br />
&nbsp; <br />
select extent_id,bytes from dba_extents where segment_name='CUSTOMERS' and segment_type='TABLE' order by extent_id;//表使用的extent的信息。segment_type='ROLLBACK'查看回滚段的空间分配信息&nbsp;&nbsp; <br />
&nbsp; <br />
select distinct table_name from user_tab_columns where column_name='SO_TYPE_ID';&nbsp;&nbsp; </p>
<p>select * from dba_tables; </p>
<p>select extent_id,bytes from dba_extents where segment_name='CUSTOMERS' and segment_type='TABLE' order by extent_id;//表使用的extent的信息。segment_type='ROLLBACK'查看回滚段的空间分配信息</p>
<p>select distinct table_name from user_tab_columns where column_name='SO_TYPE_ID'; </p>
<p><br />
5.索引 <br />
Java代码 <br />
select * from dba_indexes;//索引，包括主键索引&nbsp;&nbsp; <br />
select * from dba_ind_columns;//索引列&nbsp;&nbsp; <br />
select i.index_name,i.uniqueness,c.column_name&nbsp;&nbsp; <br />
from user_indexes i,user_ind_columns c&nbsp;&nbsp; <br />
where i.index_name=c.index_name&nbsp;&nbsp; <br />
and i.table_name ='ACC_NBR';//联接使用&nbsp; </p>
<p>select * from dba_indexes;//索引，包括主键索引<br />
select * from dba_ind_columns;//索引列<br />
select i.index_name,i.uniqueness,c.column_name<br />
from user_indexes i,user_ind_columns c<br />
where i.index_name=c.index_name<br />
and i.table_name ='ACC_NBR';//联接使用</p>
<p><br />
6.序列 <br />
Java代码 <br />
select * from dba_sequences;&nbsp; </p>
<p>select * from dba_sequences;</p>
<p>7.视图 <br />
Java代码 <br />
select * from dba_views&nbsp;&nbsp; <br />
select * from all_views&nbsp;&nbsp; <br />
text字段 可用于查询视图生成的脚本&nbsp; </p>
<p>select * from dba_views<br />
select * from all_views<br />
text字段 可用于查询视图生成的脚本</p>
<p><br />
8.聚簇 <br />
Java代码 <br />
select * from dba_clusters&nbsp; </p>
<p>select * from dba_clusters</p>
<p>9.快照 <br />
Java代码 <br />
select * from dba_snapshots&nbsp; </p>
<p>select * from dba_snapshots<br />
快照、分区应存在相应的表空间 </p>
<p>10.同义词 <br />
Java代码 <br />
select * from dba_synonyms&nbsp; </p>
<p>select * from dba_synonyms<br />
//if owner is PUBLIC,then the synonyms is a public synonym. <br />
//if owner is one of users,then the synonyms is a private synonym </p>
<p>11.数据库链 <br />
Java代码 <br />
select * from dba_db_links&nbsp; </p>
<p>select * from dba_db_links<br />
在spbase下建数据库链: <br />
Java代码 <br />
create database link dbl_spnew&nbsp;&nbsp;&nbsp; <br />
connect to spnew identified by spnew using 'jhhx';&nbsp;&nbsp; <br />
&nbsp; <br />
insert into acc_nbr@dbl_spnew select * from acc_nbr where nxx_nbr='237' and line_nbr='8888';&nbsp;&nbsp; </p>
<p>create database link dbl_spnew <br />
connect to spnew identified by spnew using 'jhhx';</p>
<p>insert into acc_nbr@dbl_spnew select * from acc_nbr where nxx_nbr='237' and line_nbr='8888'; </p>
<p><br />
12.触发器 <br />
Java代码 <br />
select * from dba_trigers;&nbsp; </p>
<p>select * from dba_trigers;</p>
<p>存储过程，函数从dba_objects查找 <br />
其文本：select text from user_source where name='BOOK_SP_EXAMPLE'; <br />
建立出错：select * from user_errors <br />
oracle总是将存储过程，函数等软件放在SYSTEM表空间。 </p>
<p>13.约束 <br />
（1）约束是和表关联的，可在create table或alter table table_name add/drop/modify来建立、修改、删除约束. <br />
　　可以临时禁止约束，如： <br />
Java代码 <br />
alter table book_example disable constraint book_example_1;&nbsp;&nbsp; <br />
alter table book_example enable constraint book_example_1;&nbsp;&nbsp; </p>
<p>alter table book_example disable constraint book_example_1;<br />
alter table book_example enable constraint book_example_1; </p>
<p>（2）主键和外键被称为表约束，而not null和unique之类的约束被称为列约束。通常将主键和外键作为单独的命名约束放在字段列表下面，而列约束可放在列定义的同一行，这样更具有可读性 <br />
（3）列约束可从表定义看出，即describe;表约束即主键和外键，可从dba_constraints和dba_cons_columns 查。 <br />
Java代码 <br />
select * from user_constraints where table_name='BOOK_EXAMPLE';&nbsp;&nbsp;&nbsp; <br />
select owner,CONSTRAINT_NAME,TABLE_NAME from user_constraints where constraint_type='R' order by table_name;&nbsp;&nbsp; </p>
<p>select * from user_constraints where table_name='BOOK_EXAMPLE'; <br />
select owner,CONSTRAINT_NAME,TABLE_NAME from user_constraints where constraint_type='R' order by table_name; </p>
<p>（4）定义约束可以无名（系统自动生成约束名）和自己定义约束名（特别是主键、外键） 如： <br />
Java代码 <br />
create table book_example (identifier number not null);&nbsp;&nbsp;&nbsp; <br />
create table book_example (identifier number constranit book_example_1 not null);&nbsp;&nbsp; </p>
<p>create table book_example (identifier number not null); <br />
create table book_example (identifier number constranit book_example_1 not null); </p>
<p><br />
14、回滚段： <br />
在所有的修改结果存入磁盘前，回滚段中保持恢复该事务所需的全部信息，必须以数据库发生的事务来相应确定其大小（DML语句才可回滚，create,drop,truncate等DDL不能回滚）。 <br />
回滚段数量=并发事务/4，但不能超过50；使每个回滚段大小足够处理一个完整的事务； <br />
Java代码 <br />
create rollback segment r05&nbsp; tablespace rbs;&nbsp;&nbsp;&nbsp; <br />
create rollback segment rbs_cvt tablespace rbs storage(initial 1M next 500k);&nbsp; </p>
<p>create rollback segment r05&nbsp; tablespace rbs; <br />
create rollback segment rbs_cvt tablespace rbs storage(initial 1M next 500k);</p>
<p><br />
使回滚段在线 <br />
Java代码 <br />
alter rollback segment r04 online;&nbsp; </p>
<p>alter rollback segment r04 online;</p>
<p>用dba_extents,v$rollback_segs监测回滚段的大小和动态增长。 </p>
<p>回滚段的区间信息 <br />
Java代码 <br />
select * from dba_extents where segment_type='ROLLBACK' and segment_name='RB1';&nbsp;&nbsp; </p>
<p>select * from dba_extents where segment_type='ROLLBACK' and segment_name='RB1'; </p>
<p><br />
回滚段的段信息,其中bytes显示目前回滚段的字节数 <br />
Java代码 <br />
select * from dba_segments where segment_type='ROLLBACK' and segment_name='RB1';&nbsp;&nbsp; </p>
<p>select * from dba_segments where segment_type='ROLLBACK' and segment_name='RB1'; </p>
<p><br />
为事物指定回归段 <br />
Java代码 <br />
set transaction use rollback segment rbs_cvt&nbsp;&nbsp; </p>
<p>set transaction use rollback segment rbs_cvt </p>
<p><br />
针对bytes可以使用回滚段回缩。 <br />
Java代码 <br />
&nbsp;&nbsp;&nbsp; <br />
alter rollback segment rbs_cvt shrink;&nbsp;&nbsp; <br />
select bytes,extents,max_extents from dba_segments where segment_type='ROLLBACK' and segment_name='RBS_CVT';&nbsp;&nbsp; </p>
<p>&nbsp;<br />
alter rollback segment rbs_cvt shrink;<br />
select bytes,extents,max_extents from dba_segments where segment_type='ROLLBACK' and segment_name='RBS_CVT'; </p>
<p><br />
回滚段的当前状态信息： <br />
Java代码 <br />
select * from dba_rollback_segs where segment_name='RB1';&nbsp; </p>
<p>select * from dba_rollback_segs where segment_name='RB1';</p>
<p>比多回滚段状态status，回滚段所属实例instance_num <br />
查优化值optimal <br />
Java代码 <br />
select n.name,s.optsize from v$rollname n,v$rollstat s where n.usn=s.usn;&nbsp;&nbsp; </p>
<p>select n.name,s.optsize from v$rollname n,v$rollstat s where n.usn=s.usn; </p>
<p><br />
回滚段中的数据 <br />
Java代码 <br />
set transaction use rollback segment rb1;/*回滚段名*/&nbsp;&nbsp;&nbsp; <br />
select n.name,s.writes from v$rollname n,v$rollstat s where n.usn=s.usn;&nbsp;&nbsp; </p>
<p>set transaction use rollback segment rb1;/*回滚段名*/ <br />
select n.name,s.writes from v$rollname n,v$rollstat s where n.usn=s.usn; </p>
<p><br />
当事务处理完毕，再次查询$rollstat，比较writes(回滚段条目字节数)差值，可确定事务的大小。 <br />
查询回滚段中的事务 <br />
Java代码 <br />
column rr heading 'RB Segment' format a18&nbsp;&nbsp;&nbsp; <br />
column us heading 'Username' format a15&nbsp;&nbsp;&nbsp; <br />
column os heading 'Os User' format a10&nbsp;&nbsp;&nbsp; <br />
column te heading 'Terminal' format a10&nbsp;&nbsp;&nbsp; <br />
select r.name rr,nvl(s.username,'no transaction') us,s.osuser os,s.terminal te from v$lock l,v$session s,v$rollname r&nbsp;&nbsp;&nbsp; <br />
where l.sid=s.sid(+)&nbsp;&nbsp; <br />
and trunc(l.id1/65536)=R.USN and l.type='TX' and l.lmode=6 order by r.name;&nbsp; </p>
<p>column rr heading 'RB Segment' format a18 <br />
column us heading 'Username' format a15 <br />
column os heading 'Os User' format a10 <br />
column te heading 'Terminal' format a10 <br />
select r.name rr,nvl(s.username,'no transaction') us,s.osuser os,s.terminal te from v$lock l,v$session s,v$rollname r <br />
where l.sid=s.sid(+)<br />
and trunc(l.id1/65536)=R.USN and l.type='TX' and l.lmode=6 order by r.name;</p>
<p><br />
15、作业 <br />
　　查询作业信息 <br />
Java代码 <br />
select job,broken,next_date,interval,what from user_jobs;&nbsp;&nbsp;&nbsp; <br />
select job,broken,next_date,interval,what from dba_jobs;&nbsp; </p>
<p>select job,broken,next_date,interval,what from user_jobs; <br />
select job,broken,next_date,interval,what from dba_jobs;</p>
<p>查询正在运行的作业 <br />
Java代码 <br />
select * from dba_jobs_running;&nbsp; </p>
<p>select * from dba_jobs_running;</p>
<p>使用包 <br />
Java代码 <br />
exec dbms_job.submit(:v_num,'a;',sysdate,'sysdate + (10/(24*60*60))')加入作业。间隔10秒钟&nbsp;&nbsp;&nbsp; <br />
exec dbms_job.submit(:v_num,'a;',sysdate,'sysdate + (11/(24*60))')加入作业。间隔11分钟使用包exec dbms_job.remove(21)删除21号作业。&nbsp; </p>
<p>exec dbms_job.submit(:v_num,'a;',sysdate,'sysdate + (10/(24*60*60))')加入作业。间隔10秒钟 <br />
exec dbms_job.submit(:v_num,'a;',sysdate,'sysdate + (11/(24*60))')加入作业。间隔11分钟使用包exec dbms_job.remove(21)删除21号作业。</p>
<p>&nbsp;</p>
<p>16.批注: <br />
ALL_COL_COMMENTS </p>
<img src ="http://www.blogjava.net/franlk/aggbug/190384.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2008-04-02 15:31 <a href="http://www.blogjava.net/franlk/articles/190384.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]修改mysql的root密码</title><link>http://www.blogjava.net/franlk/articles/184517.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Fri, 07 Mar 2008 07:02:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/184517.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/184517.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/184517.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/184517.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/184517.html</trackback:ping><description><![CDATA[<br />
<p>首先要声明一点，大部分情况下，修改MySQL是需要有mysql里的root权限的， <br />
所以一般用户无法更改密码，除非请求管理员。 <br />
<br />
方法一 <br />
使用phpmyadmin，这是最简单的了，修改mysql库的user表， <br />
不过别忘了使用PASSWORD函数。 <br />
<br />
方法二 <br />
使用mysqladmin，这是前面声明的一个特例。 <br />
mysqladmin -u root -p password mypasswd <br />
输入这个命令后，需要输入root的原密码，然后root的密码将改为mypasswd。 <br />
把命令里的root改为你的用户名，你就可以改你自己的密码了。 <br />
当然如果你的mysqladmin连接不上mysql server，或者你没有办法执行mysqladmin， <br />
那么这种方法就是无效的。 <br />
而且mysqladmin无法把密码清空。 <br />
<br />
下面的方法都在mysql提示符下使用，且必须有mysql的root权限： <br />
方法三 <br />
mysql&gt; INSERT INTO mysql.user (Host,User,Password) <br />
VALUES(\'%\',\'jeffrey\',PASSWORD(\'biscuit\')); <br />
mysql&gt; FLUSH PRIVILEGES <br />
确切地说这是在增加一个用户，用户名为jeffrey，密码为biscuit。 <br />
在《mysql中文参考手册》里有这个例子，所以我也就写出来了。 <br />
注意要使用PASSWORD函数，然后还要使用FLUSH PRIVILEGES。 <br />
<br />
方法四 <br />
和方法三一样，只是使用了REPLACE语句 <br />
mysql&gt; REPLACE INTO mysql.user (Host,User,Password) <br />
VALUES(\'%\',\'jeffrey\',PASSWORD(\'biscuit\')); <br />
mysql&gt; FLUSH PRIVILEGES <br />
<br />
方法五 <br />
使用SET PASSWORD语句， <br />
mysql&gt; SET PASSWORD FOR jeffrey@\"%\" = PASSWORD(\'biscuit\'); <br />
你也必须使用PASSWORD()函数， <br />
但是不需要使用FLUSH PRIVILEGES。 <br />
<br />
<br />
方法六 <br />
使用GRANT ... IDENTIFIED BY语句 <br />
mysql&gt; GRANT USAGE ON *.* TO jeffrey@\"%\" IDENTIFIED BY \'biscuit\'; <br />
这里PASSWORD()函数是不必要的，也不需要使用FLUSH PRIVILEGES。 <br />
<br />
<br />
注意： PASSWORD() [不是]以在Unix口令加密的同样方法施行口令加密。</p>
<img src ="http://www.blogjava.net/franlk/aggbug/184517.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2008-03-07 15:02 <a href="http://www.blogjava.net/franlk/articles/184517.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Oracle数据库中的锁机制研究</title><link>http://www.blogjava.net/franlk/articles/166860.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 11 Dec 2007 02:10:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/166860.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/166860.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/166860.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/166860.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/166860.html</trackback:ping><description><![CDATA[<br />
<p>本文通过对Oracle数据库锁机制的研究，首先介绍了Oracle数据库锁的种类，并描述了实际应用中遇到的与锁相关的异常情况，特别对经常遇到的由于等待锁而使事务被挂起的问题进行了定位及解决，并对死锁这一比较严重的现象，提出了相应的解决方法和具体的分析过程。</p>
<p>数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时，在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据，破坏数据库的一致性。</p>
<p>加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前，先向系统发出请求，对其加锁。加锁后事务就对该数据对象有了一定的控制，在该事务释放锁之前，其他的事务不能对此数据对象进行更新操作。</p>
<p>在数据库中有两种基本的锁类型：排它锁（Exclusive Locks，即X锁）和共享锁（Share Locks，即S锁）。当数据对象被加上排它锁时，其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取，但不能修改。数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。</p>
<p>在实际应用中经常会遇到的与锁相关的异常情况，如由于等待锁事务被挂起、死锁等现象，如果不能及时地解决，将严重影响应用的正常执行，而目前对于该类问题的解决缺乏系统化研究和指导，本文在总结实际经验的基础上，提出了相应的解决方法和具体的分析过程。</p>
<p><strong>Oracle数据库的锁类型</strong></p>
<p>根据保护的对象不同，Oracle数据库锁可以分为以下几大类：DML锁（data locks，数据锁），用于保护数据的完整性；DDL锁（dictionary locks，字典锁），用于保护数据库对象的结构，如表、索引等的结构定义；内部锁和闩（internal locks and latches），保护数据库的内部结构。</p>
<p>DML锁的目的在于保证并发情况下的数据完整性，本文主要讨论DML锁。在Oracle数据库中，DML锁主要包括TM锁和TX锁，其中TM锁称为表级锁，TX锁称为事务锁或行级锁。</p>
<p>当Oracle执行DML语句时，系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后，系统再自动申请TX类型的锁，并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志，而只需检查TM锁模式的相容性即可，大大提高了系统的效率。TM锁包括了SS、SX、S、X等多种模式，在数据库中用0－6来表示。不同的SQL操作产生不同类型的TM锁。如表1所示。</p>
<p>在数据行上只有X锁（排他锁）。在 Oracle数据库中，当一个事务首次发起一个DML语句时就获得一个TX锁，该锁保持到事务被提交或回滚。当两个或多个会话在表的同一条记录上执行DML语句时，第一个会话在该条记录上加锁，其他的会话处于等待状态。当第一个会话提交后，TX锁被释放，其他会话才可以加锁。</p>
<p>当Oracle数据库发生TX锁等待时，如果不及时处理常常会引起Oracle数据库挂起，或导致死锁的发生，产生ORA-60的错误。这些现象都会对实际应用产生极大的危害，如长时间未响应，大量事务失败等。</p>
<p><strong>TX锁等待的分析</strong></p>
<p>在介绍了有关地Oracle数据库锁的种类后，下面讨论如何有效地监控和解决锁等待现象，及在产生死锁时如何定位死锁的原因。</p>
<p>监控锁的相关视图 数据字典是Oracle数据库的重要组成部分，用户可以通过查询数据字典视图来获得数据库的信息。和锁相关的数据字典视图如表2所示。</p>
<p>TX锁等待的监控和解决在日常工作中，如果发现在执行某条SQL时数据库长时间没有响应，很可能是产生了TX锁等待的现象。为解决这个问题，首先应该找出持锁的事务，然后再进行相关的处理，如提交事务或强行中断事务。</p>
<p>死锁的监控和解决在数据库中，当两个或多个会话请求同一个资源时会产生死锁的现象。死锁的常见类型是行级锁死锁和页级锁死锁，Oracle数据库中一般使用行级锁。下面主要讨论行级锁的死锁现象。</p>
<p>当Oracle检测到死锁产生时，中断并回滚死锁相关语句的执行，报ORA-00060的错误并记录在数据库的日志文件alertSID.log中。同时在user_dump_dest下产生了一个跟踪文件，详细描述死锁的相关信息。</p>
<p>在日常工作中，如果发现在日志文件中记录了ora-00060的错误信息，则表明产生了死锁。这时需要找到对应的跟踪文件，根据跟踪文件的信息定位产生的原因。</p>
<p>如果查询结果表明，死锁是由于bitmap索引引起的，将IND_T_PRODUCT_HIS_STATE索引改为normal索引后，即可解决死锁的问题。</p>
<table bordercolor="#666666" height="194" cellspacing="0" cellpadding="1" width="456" bgcolor="#ffffff" border="1">
    <tbody>
        <tr>
            <td colspan="4"><span class="style1">表1 Oracle的TM锁类型</span></td>
        </tr>
        <tr>
            <td width="40"><span class="style4">锁模式</span></td>
            <td width="84"><span class="style4">锁描述</span></td>
            <td width="101"><span class="style4">解释</span></td>
            <td width="213"><span class="style4">SQL操作</span></td>
        </tr>
        <tr>
            <td><span class="style4">0</span></td>
            <td><span class="style4">none</span></td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td><span class="style4">1</span></td>
            <td><span class="style4">NULL</span></td>
            <td><span class="style4">空</span></td>
            <td><span class="style4">Select</span></td>
        </tr>
        <tr>
            <td><span class="style4">2</span></td>
            <td><span class="style4">SS(Row-S)</span></td>
            <td><span class="style4">行级共享锁，其他对象只能查询这些数据行</span></td>
            <td>
            <p class="style4">Select for update、Lock for update、Lock row share</p>
            </td>
        </tr>
        <tr>
            <td><span class="style4">3</span></td>
            <td><span class="style4">SX(Row-X)</span></td>
            <td><span class="style4">行级排它锁，在提交前不允许做DML操作</span></td>
            <td>
            <p class="style4">Insert、Update、Delete、Lock row share</p>
            </td>
        </tr>
        <tr>
            <td><span class="style4">4</span></td>
            <td><span class="style4">S(Share)</span></td>
            <td><span class="style4">共享锁</span></td>
            <td><span class="style4">Create index、Lock share</span></td>
        </tr>
        <tr>
            <td><span class="style4">5</span></td>
            <td><span class="style4">SSX(S/Row-X)</span></td>
            <td><span class="style4">共享行级排它锁</span></td>
            <td><span class="style4">Lock share row exclusive</span></td>
        </tr>
        <tr>
            <td><span class="style4">6</span></td>
            <td><span class="style4">X(Exclusive)</span></td>
            <td><span class="style4">排它锁</span></td>
            <td>
            <p class="style4">Alter table、Drop able、Drop index、Truncate table 、Lock exclusive</p>
            </td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<table bordercolor="#666666" height="194" cellspacing="0" cellpadding="1" width="577" bgcolor="#ffffff" border="1">
    <tbody>
        <tr>
            <td colspan="3"><span class="style1">表2 数据字典视图说明</span></td>
        </tr>
        <tr>
            <td width="105"><span class="style4">视图名</span></td>
            <td width="82"><span class="style4">描述</span></td>
            <td width="376"><span class="style4">主要字段说明</span></td>
        </tr>
        <tr>
            <td><span class="style4">v$session</span></td>
            <td><span class="style4">查询会话的信息和锁的信息。</span></td>
            <td>
            <p class="style4">sid,serial#：表示会话信息。</p>
            <p class="style4">program：表示会话的应用程序信息。</p>
            <p class="style4">row_wait_obj#：表示等待的对象。</p>
            <p class="style4">和dba_objects中的object_id相对应。</p>
            </td>
        </tr>
        <tr>
            <td><span class="style4">v$session_wait</span></td>
            <td><span class="style4">查询等待的会话信息。</span></td>
            <td>
            <p class="style4">sid：表示持有锁的会话信息。</p>
            <p class="style4">Seconds_in_wait：表示等待持续的时间信息</p>
            <p class="style4">Event：表示会话等待的事件。</p>
            </td>
        </tr>
        <tr>
            <td><span class="style4">v$lock</span></td>
            <td><span class="style4">列出系统中的所有的锁。</span></td>
            <td>
            <p class="style4">Sid：表示持有锁的会话信息。</p>
            <p class="style4">Type：表示锁的类型。值包括TM和TX等。</p>
            <p class="style4">ID1：表示锁的对象标识。</p>
            <p class="style4">lmode,request：表示会话等待的锁模式的信</p>
            <p class="style4">息。用数字0－6表示，和表1相对应。</p>
            </td>
        </tr>
        <tr>
            <td><span class="style4">dba_locks</span></td>
            <td><span class="style4">对v$lock的格式化视图。</span></td>
            <td>
            <p class="style4">Session_id：和v$lock中的Sid对应。</p>
            <p class="style4">Lock_type：和v$lock中的type对应。</p>
            <p class="style4">Lock_ID1： 和v$lock中的ID1对应。</p>
            <p class="style4">Mode_held,mode_requested：和v$lock中</p>
            <p class="style4">的lmode,request相对应。</p>
            </td>
        </tr>
        <tr>
            <td><span class="style4">v$locked_object</span></td>
            <td><span class="style4">只包含DML的锁信息，包括回滚段和会话信息。</span></td>
            <td>
            <p class="style4">Xidusn,xidslot,xidsqn：表示回滚段信息。和</p>
            <p class="style4">v$transaction相关联。</p>
            <p class="style4">Object_id：表示被锁对象标识。</p>
            <p class="style4">Session_id：表示持有锁的会话信息。</p>
            <p class="style4">Locked_mode：表示会话等待的锁模式的信</p>
            <p class="style4">息，和v$lock中的lmode一致。</p>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/franlk/aggbug/166860.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-12-11 10:10 <a href="http://www.blogjava.net/franlk/articles/166860.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]oracle IMP 命令详解</title><link>http://www.blogjava.net/franlk/articles/153584.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Wed, 17 Oct 2007 07:18:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/153584.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/153584.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/153584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/153584.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/153584.html</trackback:ping><description><![CDATA[<br />
摘录地址:http://blog.donews.com/yahoo163/archive/2007/02/02/1124486.aspx<br />
<br />
<span style="color: #0000ff">exp system/oracle file=d:\temp\yxdb2007-9.dmp log=d:\temp\yxdb2007-9.log owner=userid&nbsp; consistent=N direct=Y<br />
<br />
imp userid/oracle file =e:\yxdb.dmp log=e:\sqlnet.log fromuser=userid touser=userid buffer=6000000<br />
</span><br />
<div class="p_entry2" id="textboxContent">
<p><font size="2">Oracle的导入实用程序(Import utility)允许从数据库提取数据，并且将数据写入操作系统文件。imp使用的基本格式：imp[username[/password[@service]]]，以下例举imp常用用法。 </font></p>
<br />
<p class="postText" align="left"><font size="2">1. 获取帮助 </font></p>
<div twffan="done">
<pre><font size="2"> imp help=y</font></pre>
</div>
<p class="postText" align="left"><font size="2">2. 导入一个完整数据库</font></p>
<div twffan="done">
<pre><font size="2"> imp system/manager file=bible_db log=dible_db full=y ignore=y</font></pre>
</div>
<p class="postText" align="left"><font size="2">3. 导入一个或一组指定用户所属的全部表、索引和其他对象</font></p>
<div twffan="done">
<pre><font size="2"> imp system/manager file=seapark log=seapark fromuser=seapark imp </font></pre>
<pre><font size="2"> system/manager file=seapark log=seapark fromuser=(seapark,amy,amyc,harold)</font></pre>
</div>
<p class="postText" align="left"><font size="2">4. 将一个用户所属的数据导入另一个用户</font></p>
<div twffan="done">
<pre><font size="2"> imp system/manager file=tank log=tank fromuser=seapark touser=seapark_copy</font></pre>
<pre><font size="2"> imp system/manager file=tank log=tank fromuser=(seapark,amy)</font></pre>
<pre><font size="2"> touser=(seapark1, amy1)</font></pre>
</div>
<p class="postText" align="left"><font size="2">5. 导入一个表</font></p>
<div twffan="done">
<pre><font size="2"> imp system/manager file=tank log=tank fromuser=seapark TABLES=(a,b)</font></pre>
</div>
<p class="postText" align="left"><font size="2">6. 从多个文件导入</font></p>
<div twffan="done">
<pre><font size="2"> imp system/manager file=(paycheck_1,paycheck_2,paycheck_3,paycheck_4) </font></pre>
<pre><font size="2">log=paycheck, filesize=1G full=y</font></pre>
</div>
<p class="postText" align="left"><font size="2">7. 使用参数文件</font></p>
<div twffan="done">
<pre><font size="2"> imp system/manager parfile=bible_tables.par</font></pre>
</div>
<blockquote class="postText">
<p align="left"><font size="2">bible_tables.par参数文件：</font></p>
</blockquote>
<div twffan="done">
<pre><font size="2"> #Import the sample tables used for the Oracle8i Database Administrator's </font></pre>
<pre><font size="2">Bible. fromuser=seapark touser=seapark_copy file=seapark log=seapark_import</font></pre>
</div>
<p class="postText" align="left"><font size="2">8. 增量导入</font></p>
<div twffan="done">
<pre><font size="2"> imp system./manager inctype= RECTORE FULL=Y FILE=A</font></pre>
<pre>
<pre>
<div class="diaryContent" id="diary650062" twffan="done">
<h5 class="postTitle"><a href="http://blog.csdn.net/adijava/archive/2004/07/28/54573.aspx"><font color="#007799">Oracle imp/exp</font></a> </h5>
<p class="postText" align="left"><font face="Verdana" size="2">C:Documents and Settingsadministrator&gt;exp help=y</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">Export: Release 9.2.0.1.0 - Production on 星期三 7月 28 17:04:43 2004</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.</font></p>
<p class="postText" align="left"><font size="2"> </font></p>
<p class="postText" align="left"><font face="Verdana" size="2">通过输入 EXP 命令和用户名/口令，您可以<br />
后接用户名/口令的命令:</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">例程: EXP SCOTT/TIGER</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">或者，您也可以通过输入跟有各种参数的 EXP 命令来控制&#8220;导出&#8221;<br />
按照不同参数。要指定参数，您可以使用关键字:</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">格式: EXP KEYWORD=value 或 KEYWORD=(value1,value2,...,valueN)<br />
例程: EXP SCOTT/TIGER GRANTS=Y TABLES=(EMP,DEPT,MGR)<br />
或 TABLES=(T1: P1,T1: P2)，如果 T1 是分区表</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">USERID 必须是命令行中的第一个参数。</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">关键字  说明(默认)        关键字      说明(默认)<br />
--------------------------------------------------------------------------<br />
USERID   用户名/口令           FULL         导出整个文件 (N)<br />
BUFFER   数据缓冲区大小         OWNER     所有者用户名列表<br />
FILE       输出文件 (EXPDAT.DMP)  TABLES       表名称列表<br />
COMPRESS   导入到一个区 (Y) RECORDLENGTH IO 记录的长度<br />
GRANTS  导出权限 (Y)           INCTYPE      增量导出类型<br />
INDEXES    导出索引 (Y)         RECORD       跟踪增量导出 (Y)<br />
DIRECT     直接路径 (N)            TRIGGERS     导出触发器 (Y)<br />
LOG        屏幕输出的日志文件  STATISTICS   分析对象 (ESTIMATE)<br />
ROWS    导出数据行 (Y)        PARFILE      参数文件名<br />
CONSISTENT 交叉表的一致性 (N) CONSTRAINTS  导出的约束条件 (Y)</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">OBJECT_CONSISTENT    只在对象导出期间设置为读的事务处理 (N)<br />
FEEDBACK             每 x 行的显示进度 (0)<br />
FILESIZE             每个转储文件的最大大小<br />
FLASHBACK_SCN        用于将会话快照设置回以前状态的 SCN<br />
FLASHBACK_TIME       用于获取最接近指定时间的 SCN 的时间<br />
QUERY                用于导出表的子集的 select 子句<br />
RESUMABLE            遇到与空格相关的错误时挂起 (N)<br />
RESUMABLE_NAME       用于标识可恢复语句的文本字符串<br />
RESUMABLE_TIMEOUT    RESUMABLE 的等待时间<br />
TTS_FULL_CHECK       对 TTS 执行完整的或部分相关性检查<br />
TABLESPACES          要导出的表空间列表<br />
TRANSPORT_TABLESPACE 导出可传输的表空间元数据 (N)<br />
TEMPLATE             调用 iAS 模式导出的模板名</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">在没有警告的情况下成功终止导出。<br />
==================================================</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">C:Documents and Settingsadministrator&gt;imp help=y</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">Import: Release 9.2.0.1.0 - Production on 星期三 7月 28 17:06:54 2004</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.</font></p>
<p class="postText" align="left"><font size="2"> </font></p>
<p class="postText" align="left"><font face="Verdana" size="2">可以通过输入 IMP 命令和您的用户名/口令<br />
后接用户名/口令的命令:</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">例程: IMP SCOTT/TIGER</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">或者, 可以通过输入 IMP 命令和各种参数来控制&#8220;导入&#8221;<br />
按照不同参数。要指定参数，您可以使用关键字:</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">格式: IMP KEYWORD=value 或 KEYWORD=(value1,value2,...,vlaueN)<br />
例程: IMP SCOTT/TIGER IGNORE=Y TABLES=(EMP,DEPT) FULL=N<br />
或 TABLES=(T1: P1,T1: P2)，如果 T1 是分区表</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">USERID 必须是命令行中的第一个参数。</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">关键字  说明（默认）        关键字      说明（默认）<br />
--------------------------------------------------------------------------<br />
USERID   用户名/口令           FULL         导入整个文件 (N)<br />
BUFFER   数据缓冲区大小         FROMUSER     所有人用户名列表<br />
FILE     输入文件 (EXPDAT.DMP)    TOUSER       用户名列表<br />
SHOW     只列出文件内容 (N) TABLES      表名列表<br />
IGNORE   忽略创建错误 (N)    RECORDLENGTH  IO 记录的长度<br />
GRANTS  导入权限 (Y)           INCTYPE      增量导入类型<br />
INDEXES 导入索引 (Y)          COMMIT       提交数组插入 (N)<br />
ROWS    导入数据行 (Y)        PARFILE      参数文件名<br />
LOG      屏幕输出的日志文件   CONSTRAINTS  导入限制 (Y)<br />
DESTROY                覆盖表空间数据文件 (N)<br />
INDEXFILE              将表/索引信息写入指定的文件<br />
SKIP_UNUSABLE_INDEXES  跳过不可用索引的维护 (N)<br />
FEEDBACK               每 x 行显示进度 (0)<br />
TOID_NOVALIDATE        跳过指定类型 ID 的验证<br />
FILESIZE               每个转储文件的最大大小<br />
STATISTICS             始终导入预计算的统计信息<br />
RESUMABLE            在遇到有关空间的错误时挂起 (N)<br />
RESUMABLE_NAME         用来标识可恢复语句的文本字符串<br />
RESUMABLE_TIMEOUT      RESUMABLE 的等待时间<br />
COMPILE                编译过程, 程序包和函数 (Y)<br />
STREAMS_CONFIGURATION  导入 Streams 的一般元数据 (Y)<br />
STREAMS_INSTANITATION  导入 Streams 的实例化元数据 (N)</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">下列关键字仅用于可传输的表空间<br />
TRANSPORT_TABLESPACE 导入可传输的表空间元数据 (N)<br />
TABLESPACES 将要传输到数据库的表空间<br />
DATAFILES 将要传输到数据库的数据文件<br />
TTS_OWNERS 拥有可传输表空间集中数据的用户</font></p>
<p class="postText" align="left"><font face="Verdana" size="2">成功终止导入，但出现警告。</font></p>
<p class="postText" align="left"><font size="2"></font></p>
<p class="postText" align="left"><font size="2"></font></p>
<p class="postText" align="left"><font size="2"></font></p>
<h2 class="diaryTitle" align="left"><font size="2">oracle的imp和exp的一些用法- -</font></h2>
<p class="postText" align="left"><font size="2">                                       </font></p>
<p class="postText" align="left"><font size="2"></font></p>
<p class="postText" align="left"><font size="2">Oracle8i/9i EXP/IMP使用经验  <br />
一、8i EXP常用选项 </font></p>
<p class="postText" align="left"><font size="2">1、FULL，这个用于导出整个数据库，在ROWS=N一起使用时，可以导出整个数据库的结构。例如： </font></p>
<p class="postText" align="left"><font size="2">exp sys file=./db_str.dmp log=./db_str.log full=y rows=n compress=y direct=y </font></p>
<p class="postText" align="left"><font size="2">2、BUFFER和FEEDBACK，在导出比较多的数据时，我会考虑设置这两个参数。例如： </font></p>
<p class="postText" align="left"><font size="2">exp new file=yw97_2003.dmp log=yw97_2003_3.log feedback=10000 buffer=100000000 tables=WO4,OK_YT </font></p>
<p class="postText" align="left"><font size="2">3、FILL和LOG，这两个参数分别指定备份的DMP名称和LOG名称，包括文件名和目录，例子见上面。 </font></p>
<p class="postText" align="left"><font size="2">需要说明的是，EXP可以直接备份到磁带中，即使用FILE=/dev/rmt0(磁带设备名)，但是一般我们都不这么做，原因有二：一、这样做的速度会慢很多，二、现在一般都是使用磁带库的，不建议直接对磁带进行操作。至于没有使用磁带库的朋友可以考虑和UNIX的TAR结合使用。 </font></p>
<p class="postText" align="left"><font size="2">如果你真想使用EXP直接到磁带，你可以参考Metalink文章&#8220;EXPORTING TO TAPE ON UNIX SYSTEMS&#8221;（文档号：30428.1），该文中有详细解释。 </font></p>
<p class="postText" align="left"><font size="2">4、COMPRESS参数将在导出的同时合并碎块，尽量把数据压缩到initial的EXTENT里，默认是N，一般建议使用。DIRECT参数将告诉EXP直接读取数据，而不像传统的EXP那样，使用SELECT来读取表中的数据，这样就减少了SQL语句处理过程。一般也建议使用。不过有些情况下DIRECT参数是无法使用的。 </font></p>
<p class="postText" align="left"><font size="2">5、如何使用SYSDBA执行EXP/IMP？ </font></p>
<p class="postText" align="left"><font size="2">这是一个很现实的问题，有时候我们需要使用SYSDBA来执行EXP/IMP，如进行传输表空间的EXP/IMP，以及在9i下用SYS用户来执行EXP/IMP时，都需要使用SYSDBA才可。我们可以使用下面方式连入EXP/IMP： </font></p>
<p class="postText" align="left"><font size="2">exp "'sys/sys as sysdba'" file=1.dmp tables=gototop.t rows=n </font></p>
<p class="postText" align="left"><font size="2">6、QUERY参数后面跟的是where条件，值得注意的是，整个where子句需要使用""括起来，where子句的写法和SELECT中相同，如果是UNIX平台所有"和'都需要使用u26469屏蔽它们的特殊含义： </font></p>
<p class="postText" align="left"><font size="2">exp gototop/gototop file=1.dmp log=1.log tables=cyx.t query="where c1=20 and c2=gototop" </font></p>
<p class="postText" align="left"><font size="2">如果是windows平台，则使用下面的格式： </font></p>
<p class="postText" align="left"><font size="2">exp </font><a href="mailto:c/c@ncn"><font color="#007799" size="2">c/c@ncn</font></a><font size="2"> file=c.dmp log=c.log tables=t query="""where id=1 and name='gototop'""" </font></p>
<p class="postText" align="left"><font size="2">二、8i IMP常用选项 </font></p>
<p class="postText" align="left"><font size="2">1、FROMUSER和TOUSER，使用它们实现将数据从一个SCHEMA中导入到另外一个SCHEMA中。 </font></p>
<p class="postText" align="left"><font size="2">2、IGNORE、GRANTS和INDEXES，其中IGNORE参数将忽略表的存在，继续导入，这个对于需要调整表的存储参数时很有用，我们可以先根据实际情况用合理的存储参数建好表，然后直接导入数据。而GRANTS和INDEXES则表示是否导入授权和索引，如果想使用新的存储参数重建索引，或者为了加快到入速度，我们可以考虑将INDEXES设为N，而GRANTS一般都是Y。 </font></p>
<p class="postText" align="left"><font size="2">另外一个EXP/IMP都有的参数是PARFILE，它是用来定义EXP/IMP的参数文件，也就是说，上面的参数都可以写在一个参数文件中，但我们一般很少使用。 </font></p>
<p class="postText" align="left"><font size="2">三、Oracle9i EXP功能描述 </font></p>
<p class="postText" align="left"><font size="2">Oracle9i EXP在原有的基础上新增了部分新的参数，按功能主要分为以下几个部分： </font></p>
<p class="postText" align="left"><font size="2">1、OBJECT_CONSISTENT - 用于设置EXP对象为只读以保持对象的一致性。默认是N。 </font></p>
<p class="postText" align="left"><font size="2">2、FLASHBACK_SCN和FLASHBACK_TIME - 用于支持FLASHBACK功能而新增。 </font></p>
<p class="postText" align="left"><font size="2">3、RESUMABLE、RESUMABLE_NAME和RESUMABLE_TIMEOUT - 用于支持RESUMABLE空间分配而新增。 </font></p>
<p class="postText" align="left"><font size="2">4、TTS_FULL_CHECK - 用于在传输表空间时使用依赖性检查。 </font></p>
<p class="postText" align="left"><font size="2">5、TEMPLATE - 用于支持iAS。 </font></p>
<p class="postText" align="left"><font size="2">6、TABLESPACES - 设置表空间导出模式。个人觉得对于一般用户而言，这个才是新增参数中最实用的一个，可以让用户在原来的FULL、OWNER、TABLES的基础上多了一种选择，使得EXP更加灵活。 </font></p>
<p class="postText" align="left"><font size="2">四、不同版本的EXP/IMP问题？ </font></p>
<p class="postText" align="left"><font size="2">一般来说，从低版本导入到高版本问题不大，麻烦的是将高版本的数据导入到低版本中，在Oracle9i之前，不同版本Oracle之间的EXP/IMP可以通过下面的方法来解决： </font></p>
<p class="postText" align="left"><font size="2">1、在高版本数据库上运行底版本的catexp.sql； </font></p>
<p class="postText" align="left"><font size="2">2、使用低版本的EXP来导出高版本的数据； </font></p>
<p class="postText" align="left"><font size="2">3、使用低版本的IMP将数据库导入到底版本数据库中； </font></p>
<p class="postText" align="left"><font size="2">4、在高版本数据库上重新运行高版本的catexp.sql脚本。 </font></p>
<p class="postText" align="left"><font size="2">但在9i中，上面的方法并不能解决问题。如果直接使用底版本EXP/IMP会出现如下错误： </font></p>
<p class="postText" align="left"><font size="2">EXP-00008: ORACLE error %lu encountered </font></p>
<p class="postText" align="left"><font size="2">ORA-00904: invalid column name </font></p>
<p class="postText" align="left"><font size="2">这已经是一个公布的BUG，需要等到Oracle10.0才能解决，BUG号为2261，你可以到METALINK上去查看有关此BUG的详细信息。 </font></p>
<p class="postText" align="left"><font size="2">BUG归BUG，我们的工作还是要做，在没有Oracle的支持之前，我们就自己解决。在Oracle9i中执行下面的SQL重建exu81rls视图即可。 </font></p>
<p class="postText" align="left"><font size="2">CREATE OR REPLACE view exu81rls  </font></p>
<p class="postText" align="left"><font size="2">(objown,objnam,policy,polown,polsch,polfun,stmts,chkopt,enabled,spolicy)  </font></p>
<p class="postText" align="left"><font size="2">AS select u.name, o.name, r.pname, r.pfschma, r.ppname, r.pfname,  </font></p>
<p class="postText" align="left"><font size="2">decode(bitand(r.stmt_type,1), 0,'', 'SELECT,')  </font></p>
<p class="postText" align="left"><font size="2">|| decode(bitand(r.stmt_type,2), 0,'', 'INSERT,')  </font></p>
<p class="postText" align="left"><font size="2">|| decode(bitand(r.stmt_type,4), 0,'', 'UPDATE,')  </font></p>
<p class="postText" align="left"><font size="2">|| decode(bitand(r.stmt_type,8), 0,'', 'DELETE,'),  </font></p>
<p class="postText" align="left"><font size="2">r.check_opt, r.enable_flag,  </font></p>
<p class="postText" align="left"><font size="2">DECODE(BITAND(r.stmt_type, 16), 0, 0, 1)  </font></p>
<p class="postText" align="left"><font size="2">from user$ u, obj$ o, rls$ r  </font></p>
<p class="postText" align="left"><font size="2">where u.user# = o.owner#  </font></p>
<p class="postText" align="left"><font size="2">and r.obj# = o.obj#  </font></p>
<p class="postText" align="left"><font size="2">and (uid = 0 or  </font></p>
<p class="postText" align="left"><font size="2">uid = o.owner# or  </font></p>
<p class="postText" align="left"><font size="2">exists ( select * from session_roles where role='SELECT_CATALOG_ROLE')  </font></p>
<p class="postText" align="left"><font size="2">)  </font></p>
<p class="postText" align="left"><font size="2">/  </font></p>
<p class="postText" align="left"><font size="2">grant select on sys.exu81rls to public;  </font></p>
<p class="postText" align="left"><font size="2">/  </font></p>
<p class="postText" align="left"><font size="2">五、其他问题 </font></p>
<p class="postText" align="left"><font size="2">本文只讨论了Oracle8i和9i中的EXP/IMP的一些情况，对于之前的版本，在8.0.X中，除了QUERY参数不能用外，其它差别不大。针对没有QUERY的情况，我们可以先在数据库中使用查询条件建立临时中间表，然后使用EXP导出这个中间表即可。至于Oracle7因为目前使用的人较少，gototop不打算在此做详细解释了，如果读者朋友有需求，你可以参考Metalink文档：&#8220;Overview of Export and Import in Oracle7&#8221;（文档号：61949.1）。关于EXP/IMP的详细参数信息你可以通过EXP/IMP HELP=Y来获得。 </font></p>
<p class="postText" align="left"><font size="2">另外关于传输表空间的更多信息可以参考下面的Metelink文档，本文不再详述。 </font></p>
<p class="postText" align="left"><font size="2">[NOTE:77523.1] Transportable Tablespaces -- An Example to setup and use.  </font></p>
<p class="postText" align="left"><font size="2">[NOTE:100698.1] Perform tablespace point-in-time recovery using Transportable Tablespace.  </font></p>
<p class="postText" align="left"><font size="2">在进行并行EXP/IMP的时候，如果IMP过程建索引的话不建议同时运行5个以上的IMP，如果你想加快速度</font></p>
</div>
</pre>
</pre>
</div>
</div>
<p>&nbsp;</p>
<p><br />
&nbsp;</p>
<p>1 table model<br />
&nbsp; 1) backup one user's table<br />
&nbsp;&nbsp;&nbsp;&nbsp; exp icdmain/icd rows=y indexes=n compress=n buffer=65536 feedback=100000 volsize=0 file=exp_icdmain_table_yyyymmdd.dmp log=exp_icdmain_table_yyyymmdd.log tables=icdmain.commoninformation,icdmain.serviceinfo,icdmain.dealinfo<br />
&nbsp; 2) recover all table<br />
&nbsp;&nbsp;&nbsp;&nbsp; imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 file=exp_icdmain_table_yyyymmdd.dmp log=imp_icdmain_table_yyyymmdd.log<br />
&nbsp; 3) recover some table of all table<br />
&nbsp;&nbsp;&nbsp;&nbsp; imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 file=exp_icdmain_table_yyyymmdd.dmp log=imp_icdmain_table_yyyymmdd.log tables=commoninformation,serviceinfo<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;</p>
<p>2 user model<br />
&nbsp; 1) backup all someone's object<br />
&nbsp;&nbsp;&nbsp;&nbsp; exp icdmain/icd rows=y indexes=n compress=n buffer=65536 feedback=100000 volsize=0&nbsp; owner=icdmain file=exp_icdmain_user_yyyymmdd.dmp log=exp_icdmain_user_yyyymmdd.log<br />
&nbsp; 2) recover all someone's object<br />
&nbsp;&nbsp;&nbsp;&nbsp; imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 file=exp_icdmain_user_yyyymmdd.dmp log=imp_icdmain_user_yyyymmdd.log<br />
&nbsp; 3) recover some table of all someone's object<br />
&nbsp;&nbsp;&nbsp;&nbsp; imp icdmain/icd fromuser=icdmain touser=icdmain rows=y indexes=n commit=y buffer=65536 feedback=100000 ignore=y volsize=0 file=exp_icdmain_user_yyyymmdd.dmp log=imp_icdmain_user_yyyymmdd.log tables=commoninformation,serviceinfo </p>
<p>&nbsp;</p>
<p><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
&nbsp;</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/franlk/aggbug/153584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-10-17 15:18 <a href="http://www.blogjava.net/franlk/articles/153584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]动态SQL和PL/SQL的EXECUTE IMMEDIATE选项</title><link>http://www.blogjava.net/franlk/articles/148917.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Thu, 27 Sep 2007 17:49:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/148917.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/148917.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/148917.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/148917.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/148917.html</trackback:ping><description><![CDATA[<br />
摘录地址：http://blog.csdn.net/yzsind/archive/2005/01/07/243744.aspx<br />
<br />
EXECUTE IMMEDIATE代替了以前Oracle8i中DBMS_SQL package包.它解析并马上执行动态的SQL语句或非运行时创建的PL/SQL块.动态创建和执行SQL语句性能超前，EXECUTE IMMEDIATE的目标在于减小企业费用并获得较高的性能，较之以前它相当容易编码.尽管DBMS_SQL仍然可用，但是推荐使用EXECUTE IMMEDIATE,因为它获的收益在包之上。
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">&nbsp;<strong>使用技巧</strong></span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">1.&nbsp;EXECUTE IMMEDIATE将不会提交一个DML事务执行，应该显式提交<br />
&nbsp;如果通过EXECUTE IMMEDIATE处理DML命令，那么在完成以前需要显式提交或者作为EXECUTE IMMEDIATE自己的一部分. 如果通过EXECUTE IMMEDIATE处理DDL命令,它提交所有以前改变的数据</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">2.&nbsp;不支持返回多行的查询,这种交互将用临时表来存储记录(参照例子如下)或者用REF cursors.</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">3.&nbsp;当执行SQL语句时，不要用分号，当执行PL/SQL块时，在其尾部用分号.</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">4.&nbsp;在Oracle手册中，未详细覆盖这些功能。下面的例子展示了所有用到Execute immediate的可能方面.希望能给你带来方便.</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">5.&nbsp;对于Forms开发者,当在PL/SQL 8.0.6.3.版本中，Forms 6i不能使用此功能.</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial"><strong>EXECUTE IMMEDIATE用法例子</strong></span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">1.&nbsp;在PL/SQL运行DDL语句</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial"><br />
&nbsp;begin<br />
&nbsp;&nbsp;execute immediate 'set role all';<br />
&nbsp;end;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">2.&nbsp;给动态语句传值(USING 子句)</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial"><br />
&nbsp;declare<br />
&nbsp; l_depnam varchar2(20) := 'testing';<br />
&nbsp; l_loc&nbsp;&nbsp;&nbsp; varchar2(10) := 'Dubai';<br />
&nbsp; begin<br />
&nbsp;&nbsp;execute immediate 'insert into dept values &nbsp;(:1, :2, :3)'<br />
&nbsp; &nbsp; using 50, l_depnam, l_loc;<br />
&nbsp;&nbsp;commit;<br />
&nbsp;end;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">3.&nbsp;从动态语句检索值(INTO子句)</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial"><br />
&nbsp;declare<br />
&nbsp;&nbsp;l_cnt&nbsp;&nbsp;&nbsp; varchar2(20);<br />
&nbsp;begin<br />
&nbsp;&nbsp;execute immediate 'select count(1) from emp'<br />
&nbsp;&nbsp; &nbsp;into l_cnt;<br />
&nbsp;&nbsp;dbms_output.put_line(l_cnt);<br />
&nbsp;end;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">4.&nbsp;动态调用例程.例程中用到的绑定变量参数必须指定参数类型.黓认为IN类型,其它类型必须显式指定</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">&nbsp;declare<br />
&nbsp;&nbsp;l_routin&nbsp;&nbsp; varchar2(100) := 'gen2161.get_rowcnt';<br />
&nbsp; l_tblnam&nbsp;&nbsp; varchar2(20) := 'emp';<br />
&nbsp; l_cnt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; number;<br />
&nbsp; l_status&nbsp;&nbsp; varchar2(200);<br />
&nbsp;begin<br />
&nbsp;&nbsp;execute immediate 'begin ' || l_routin || '(:2, :3, :4); end;'<br />
&nbsp; &nbsp; using in l_tblnam, out l_cnt, in out l_status;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">&nbsp;&nbsp;if l_status != 'OK' then<br />
&nbsp;&nbsp; &nbsp; dbms_output.put_line('error');<br />
&nbsp;&nbsp;end if;<br />
&nbsp;end;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">5.&nbsp;将返回值传递到PL/SQL记录类型;同样也可用%rowtype变量</span></p>
<span style="font-family: Arial">
<p style="margin: 0cm 0cm 0pt"><br />
&nbsp;declare<br />
&nbsp; type empdtlrec is record (empno&nbsp; number(4),<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; ename&nbsp; varchar2(20),<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; deptno&nbsp; number(2));<br />
&nbsp; empdtl empdtlrec;<br />
&nbsp;begin<br />
&nbsp;&nbsp;execute immediate 'select empno, ename, deptno ' ||<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'from emp where empno = 7934'<br />
&nbsp; &nbsp; into empdtl;<br />
&nbsp;end;</p>
<p style="margin: 0cm 0cm 0pt"></span>&nbsp;</p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">6.&nbsp;传递并检索值.INTO子句用在USING子句前</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">&nbsp;declare<br />
&nbsp; l_dept&nbsp;&nbsp;&nbsp; pls_integer := 20;<br />
&nbsp;&nbsp;l_nam&nbsp;&nbsp;&nbsp;&nbsp; varchar2(20);<br />
&nbsp;&nbsp;l_loc&nbsp;&nbsp;&nbsp;&nbsp; varchar2(20);<br />
&nbsp;begin<br />
&nbsp;&nbsp;execute immediate 'select dname, loc from dept where deptno = :1'<br />
&nbsp; &nbsp; into l_nam, l_loc<br />
&nbsp;&nbsp; &nbsp;using l_dept ;<br />
&nbsp;end;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">7.&nbsp;多行查询选项.对此选项用insert语句填充临时表，用临时表进行进一步的处理,也可以用REF cursors纠正此缺憾.<br />
&nbsp;<br />
&nbsp;declare<br />
&nbsp; l_sal&nbsp;&nbsp; pls_integer := 2000;<br />
&nbsp;begin<br />
&nbsp;&nbsp;execute immediate 'insert into temp(empno, ename) ' ||<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; select empno, ename from emp ' ||<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; where&nbsp; sal &gt; :1'<br />
&nbsp; &nbsp; using l_sal;<br />
&nbsp;&nbsp;commit;<br />
&nbsp;end;</span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于处理动态语句,EXECUTE IMMEDIATE比以前可能用到的更容易并且更高效.当意图执行动态语句时，适当地处理异常更加重要.应该关注于捕获所有可能的异常.<br />
</span></p>
<img src ="http://www.blogjava.net/franlk/aggbug/148917.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-09-28 01:49 <a href="http://www.blogjava.net/franlk/articles/148917.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]基于Oracle的高性能动态SQL程序开发</title><link>http://www.blogjava.net/franlk/articles/148916.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Thu, 27 Sep 2007 17:46:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/148916.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/148916.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/148916.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/148916.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/148916.html</trackback:ping><description><![CDATA[<br />
摘录地址：http://tech.tfol.com/techs/wlxx/block/html/2005011800336.html<br />
<br />
文/冯杰<br />
<br />
摘要：对动态SQL的程序开发进行了总结，并结合笔者实际开发经验给出若干开发技巧。<br />
<br />
　　关键词：动态SQL，PL/SQL，高性能<br />
<br />
　　1． 静态SQLSQL与动态SQL<br />
<br />
　　Oracle编译PL/SQL程序块分为两个种：其一为前期联编（early binding），即SQL语句在程序编译期间就已经确定，大多数的编译情况属于这种类型；另外一种是后期联编（late binding），即SQL语句只有在运行阶段才能建立，例如当查询条件为用户输入时，那么Oracle的SQL引擎就无法在编译期对该程序语句进行确定，只能在用户输入一定的查询条件后才能提交给SQL引擎进行处理。通常，静态SQL采用前一种编译方式，而动态SQL采用后一种编译方式。<br />
<br />
　　本文主要就动态SQL的开发进行讨论，并在最后给出一些实际开发的技巧。<br />
<br />
　　2． 动态SQL程序开发<br />
<br />
　　理解了动态SQL编译的原理，也就掌握了其基本的开发思想。动态SQL既然是一种&#8221;不确定&#8221;的SQL，那其执行就有其相应的特点。Oracle中提供了Execute immediate语句来执行动态SQL，语法如下：<br />
<br />
Excute immediate 动态SQL语句 using 绑定参数列表 returning into 输出参数列表;<br />
<br />
　　对这一语句作如下说明：<br />
<br />
　　1) 动态SQL是指DDL和不确定的DML（即带参数的DML）<br />
<br />
　　2) 绑定参数列表为输入参数列表，即其类型为in类型，在运行时刻与动态SQL语句中的参数（实际上占位符，可以理解为函数里面的形式参数）进行绑定。<br />
<br />
　　3) 输出参数列表为动态SQL语句执行后返回的参数列表。<br />
<br />
　　4) 由于动态SQL是在运行时刻进行确定的，所以相对于静态而言，其更多的会损失一些系统性能来换取其灵活性。<br />
<br />
　　为了更好的说明其开发的过程，下面列举一个实例：<br />
<br />
　　设数据库的emp表，其数据为如下：<br />
<br />
ID NAME SALARY <br />
100 Jacky 5600 <br />
101 Rose 3000 <br />
102 John 4500 <br />
<br />
　　要求：<br />
<br />
　　1．创建该表并输入相应的数据。<br />
<br />
　　2．根据特定ID可以查询到其姓名和薪水的信息。<br />
<br />
　　3．根据大于特定的薪水的查询相应的员工信息。<br />
<br />
　　根据前面的要求，可以分别创建三个过程（均使用动态SQL）来实现： <br />
<br />
　　过程一：<br />
<br />
create or replace procedure create_table as<br />
begin<br />
execute immediate '<br />
create table emp(id number,<br />
name varchar2(10)<br />
salary number; )'; --动态SQL为DDL语句<br />
insert into emp<br />
values (100,'jacky',5600);<br />
insert into emp<br />
values (101,'rose',3000);<br />
insert into emp<br />
values (102,'john',4500);<br />
end create_table; <br />
<br />
　　过程二： <br />
<br />
create or replace procedure find_info(p_id number) as<br />
v_name varchar2(10);<br />
v_salary number;<br />
begin<br />
execute immediate '<br />
select name,salary from emp<br />
where id=:1'<br />
using p_id<br />
returning into v_name,v_salary; --动态SQL为查询语句<br />
dbms_output.put_line(v_name ||'的收入为：'||to_char(v_salary))；<br />
exception<br />
when others then <br />
dbms_output.put_line('找不到相应数据')；<br />
end find_info; <br />
<br />
　　过程三：<br />
<br />
create or replace procedure find_emp(p_salary number) as<br />
r_emp emp%rowtype;<br />
type c_type is ref cursor;<br />
c1 c_type;<br />
begin<br />
open c1 for '<br />
select * from emp<br />
where salary &gt;:1'<br />
using p_salary;<br />
loop<br />
fetch c1 into r_emp;<br />
exit when c1%notfound;<br />
dbms_output.put_line('薪水大于&#8216;||to_char(p_salary)||&#8217;的员工为：&#8216;);<br />
dbms_output.put_line('ID为'to_char(r_emp)||' 其姓名为：'||r_emp.name);<br />
end loop;<br />
close c1; <br />
end create_table; <br />
<br />
<br />
　　注意：在过程二中的动态SQL语句使用了占位符&#8220;:1&#8220;，其实它相当于函数的形式参数，使用&#8221;：&#8220;作为前缀，然后使用using语句将p_id在运行时刻将:1给替换掉，这里p_id相当于函数里的实参。另外过程三中打开的游标为动态游标，它也属于动态SQL的范畴，其整个编译和开发的过程与execute immediate执行的过程很类似，这里就不在赘述了。<br />
<br />
<br />
　3． 动态SQL语句开发技巧<br />
<br />
　　前面分析到了，动态SQL的执行是以损失系统性能来换取其灵活性的，所以对它进行一定程度的优化也是必要的，笔者根据实际开发经验给出一些开发的技巧，需要指出的是，这里很多经验不仅局限于动态SQL，有些也适用于静态SQL，在描述中会给予标注。<br />
<br />
　　技巧一：尽量使用类似的SQL语句，这样Oracle本身通过SGA中的共享池来直接对该SQL语句进行缓存，那么在下一次执行类似语句时就直接调用缓存中已解析过的语句，以此来提高执行效率。<br />
<br />
　　技巧二：当涉及到集合单元的时候，尽量使用批联编。比如需要对id为100和101的员工的薪水加薪10％，一般情况下应该为如下形式：<br />
<br />
declare <br />
type num_list is varray(20) of number;<br />
v_id num_list :=num_list(100,101);<br />
begin<br />
...<br />
for i in v_id.first .. v_id.last loop<br />
...<br />
execute immediate 'update emp <br />
set =salary*1.2 <br />
where id=:1 '<br />
using v_id(i);<br />
end loop;<br />
end; <br />
<br />
　　对于上面的处理，当数据量大的时候就会显得比较慢，那么如果采用批联编的话，则整个集合首先一次性的传入到SQL引擎中进行处理，这样比单独处理效率要高的多，进行批联编处理的代码如下：<br />
<br />
declare <br />
type num_list is varray(20) of number;<br />
v_id num_list :=num_list(100,101);<br />
begin<br />
...<br />
forall i in v_id.first .. v_id.last loop<br />
...<br />
execute immediate 'update emp <br />
set =salary*1.2 <br />
where id=:1 '<br />
using v_id(i);<br />
end loop;<br />
end; <br />
<br />
　　这里是使用forall来进行批联编，这里将批联编处理的情形作一个小结：<br />
<br />
　　1) 如果一个循环内执行了insert，delete，update等语句引用了集合元素，那么可以将其移 动到一个forall语句中。<br />
<br />
　　2) 如果select into，fetch into 或returning into 子句引用了一个集合，应该使用bulk collect 子句进行合并。<br />
<br />
　　3) 如有可能，应该使用主机数组来实现在程序和数据库服务器之间传递参数。<br />
<br />
　　技巧三：使用NOCOPY编译器来提高PL/SQL性能。缺省情况下，out类型和in out类型的参数是由值传递的方式进行的。但是对于大的对象类型或者集合类型的参数传递而言，其希望损耗将是很大的，为了减少损耗，可以采用引用传递的方式，即在进行参数声明的时候引用NOCOPY关键字来说明即可到达这样的效果。比如创建一个过程：<br />
<br />
create or replace procedure test(p_object in nocopy square)<br />
...<br />
end; <br />
<br />
　　其中square为一个大的对象类型。这样只是传递一个地址，而不是传递整个对象了。显然这样的处理也是提高了效率。<br />
<br />
　　4． 小结<br />
<br />
　　本文对动态SQL的编译原理、开发过程以及开发技巧的讨论，通过本文的介绍后，相信读者对动态SQL程序开发有了一个总体的认识，为今后深入的工作打下一个良好的基础。<br />
<br />
　　前面代码部分已经在下列环境中调试成功：<br />
<br />
　　服务器端：UNIX+ORACLE9.2<br />
<br />
　　客户端：WINDOWS2000 PRO+TOAD<br />
<img src ="http://www.blogjava.net/franlk/aggbug/148916.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-09-28 01:46 <a href="http://www.blogjava.net/franlk/articles/148916.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]一次解决session无法完全删除问题的全过程</title><link>http://www.blogjava.net/franlk/articles/146209.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 18 Sep 2007 09:03:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/146209.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/146209.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/146209.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/146209.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/146209.html</trackback:ping><description><![CDATA[<br />
摘录地址: http://blog.csdn.net/hooyang/archive/2005/04/27/365746.aspx<br />
<br />
<p><font face="Verdana">开发环境：win2000server+oracle9i+delphi</font><br />
开发人员报告：在程序中杀了JOB，但是被操作的表还是锁表状态，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中有一张日志表还在不断插入记录，直到执行完所有插入操作（一个漫长的等待过程）才能解锁<br />
现场描述：oem中被杀job起的SESSION状态为killed,其中有3张表被锁点击右键－－》中断会话&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 提示： 标记要删去的会话 </p>
<p>===================================================================================================<br />
处理方法一 ：</p>
<p>1.SELECT saddr,sid,serial#,paddr,username,status FROM v$session WHERE username IS NOT NULL<br />
example:saddr,sid,serial#,paddr,username,status FROM v$session WHERE username = 'XNJW0419' ;<br />
SADDR SID SERIAL# PADDR USERNAME STATUS <br />
-------- ---------- ---------- -------- ------------------------------ -------- <br />
542E0E6C 11 314 542B70E8 EYGLE INACTIVE 542E5044 18 662 542B6D38 SYS ACTIVE </p>
<p>2.ALTER SYSTEM KILL SESSION 'sid, serial#';<br />
example:ALTER SYSTEM KILL SESSION '11,314';(注：在sqlplus中执行 )</p>
<p>结果： 提示标记要删去的会话 无法释放会话,未成功解锁</p>
<p>====================================================================================================<br />
处理方法二 ：</p>
<p>a、 找到你要杀掉的那个SESSION, 并记下paddr </p>
<p>SELECT sid, username, paddr, status FROM v$session WHERE username = '用户名' ; <br />
example:SELECT sid, username, paddr, status FROM v$session WHERE username = 'XNJW0419' ;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SID USERNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PADDR&nbsp;&nbsp;&nbsp; STATUS<br />
---------- ------------------------------ -------- --------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 XNJW0419&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2B5E2E2C KILLED</p>
<p>b、 找到这个SESSION所对应的spid </p>
<p>SELECT * FROM v$process WHERE addr = '上面查寻的paddr'; <br />
example:SELECT ADDR,PID,SPID,USERNAME,SERIAL#,TERMINAL FROM v$process WHERE addr = '2B5E2E2C';<br />
ADDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PID SPID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; USERNAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SERIAL# TERMINAL<br />
-------- ---------- ------------ --------------- ---------- ----------------<br />
2B5E2E2C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 44 1204&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SYSTEM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -99 JWC</p>
<p>c、 杀掉spid所标识的那个进程 </p>
<p>D:\&gt;orakill sid 　spid （注：cmd命令窗口中执行 只有oracle服务器端才有orakill命令）<br />
example: D:\&gt;orakill oemrep 1204</p>
<p>提示：KILL OF THREAD id 1204 IN INSTANCE oemrep successfully signalled.</p>
<p>结果：成功删除该SESSION,表也解锁</p>
<br />
<img src ="http://www.blogjava.net/franlk/aggbug/146209.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-09-18 17:03 <a href="http://www.blogjava.net/franlk/articles/146209.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle 中的demo与sqlldr 的用法</title><link>http://www.blogjava.net/franlk/articles/142677.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 04 Sep 2007 08:45:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/142677.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/142677.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/142677.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/142677.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/142677.html</trackback:ping><description><![CDATA[<br />
在oracle的安装目录下有相应的demo,包含创建表、增加记录数据相应的脚本。<br />
<br />
hr用户(注意它的表空间为system)<br />
&nbsp;&nbsp;&nbsp;&nbsp;$ORACLE_HOME/demo/schema/human_resources/hr_main.sql，<br />
<br />
sh用户(注意它的表空间为example)<br />
&nbsp;&nbsp;&nbsp;&nbsp;$ORACLE_HOME/demo/schema/sales_history/sh_main.sql，执行完后一些表中的数据要通过sqlldr来导入数据。<br />
&nbsp;&nbsp;&nbsp;&nbsp;sqlldr 用法&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$&gt;sqlldr userid=sh/franlk control=*.ctl&nbsp; log=*.log&nbsp; (*代表相应的文件)<br />
&nbsp;&nbsp;&nbsp;&nbsp;我们在$ORACLE_HOME/demo/schema/sales_history/目录下能够看到.ctl与.dat文件<br />
&nbsp;&nbsp;&nbsp;&nbsp;.ctl是数据导入的规则文件,内容如下：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>LOAD DATA<br />
<span style="color: red"><span style="color: #0000ff">INFILE 'E:\oracle\ora92\demo\schema\sales_history\sh_sales.dat'&nbsp;</span>&nbsp;</span>------自定义部分(要导入的数据)<br />
APPEND</p>
<p>INTO TABLE sales<br />
FIELDS TERMINATED BY "|"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;------依据.dat中分隔符<br />
( PROD_ID, CUST_ID, TIME_ID, CHANNEL_ID, PROMO_ID,<br />
&nbsp;QUANTITY_SOLD, AMOUNT_SOLD)<br />
<br />
因为.dat中的日期，我们必须设置一下NLS_LANG<br />
<br />
那么我们在dos下执行顺序应该是：<br />
<br />
$&gt;set NLS_LANG=american_america.zhs16cgb231280<br />
$&gt;sqlldr userid=sh/franlk control=E:\oracle\ora92\demo\schema\sales_history\sh_cust.ctl log=E:\oracle\ora92\demo\schema\log\sh_cust.log<br />
<br />
$&gt;sqlldr userid=sh/franlk control=E:\oracle\ora92\demo\schema\sales_history\sh_prod.ctl log=E:\oracle\ora92\demo\schema\log\sh_prod.log<br />
<br />
$&gt;sqlldr userid=sh/franlk control=E:\oracle\ora92\demo\schema\sales_history\sh_promo.ctl log=E:\oracle\ora92\demo\schema\log\sh_promo.log<br />
<br />
$&gt;sqlldr userid=sh/franlk control=E:\oracle\ora92\demo\schema\sales_history\sh_sales.ctl log=E:\oracle\ora92\demo\schema\log\sales.log<br />
<br />
<br />
<br />
<span style="color: red"><strong>注意</strong></span><span style="color: red">：蓝色为后来加上的，原文件是没有的。</span><br />
</p>
<br />
<br />
<img src ="http://www.blogjava.net/franlk/aggbug/142677.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-09-04 16:45 <a href="http://www.blogjava.net/franlk/articles/142677.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle资料整理</title><link>http://www.blogjava.net/franlk/articles/128324.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Thu, 05 Jul 2007 06:02:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/128324.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/128324.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/128324.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/128324.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/128324.html</trackback:ping><description><![CDATA[<p><br><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">★ ROACLE中最好性能的SQL查询<br><br>SELECT *<br>&nbsp; FROM (SELECT PARSING_USER_ID 　 EXECUTIONS,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SORTS,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COMMAND_TYPE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DISK_READS,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sql_text 　　<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM v$sqlarea 　　<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ORDER BY disk_reads DESC 　　)<br>&nbsp;WHERE ROWNUM &lt; 10;<br><br><br><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">★ ORACLE中锁表查询及删除SESSION</span></span></p>
<p><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">SELECT /*+ RULE */<br>&nbsp;LPAD(' ', DECODE(L.XIDUSN, 0, 3, 0)) || L.ORACLE_USERNAME USER_NAME,<br>&nbsp;O.OWNER,<br>&nbsp;O.OBJECT_NAME,<br>&nbsp;O.OBJECT_TYPE,<br>&nbsp;S.SID,<br>&nbsp;S.SERIAL#,<br>&nbsp;P.SPID<br>&nbsp; FROM V$LOCKED_OBJECT L, DBA_OBJECTS O, V$SESSION S, V$PROCESS P<br>&nbsp;WHERE L.OBJECT_ID = O.OBJECT_ID<br>&nbsp;&nbsp; AND L.SESSION_ID = S.SID<br>&nbsp;&nbsp; AND S.PADDR = P.ADDR<br>&nbsp;ORDER BY O.OBJECT_ID, XIDUSN DESC;<br><br>ALTER SYSTEM KILL SESSION&nbsp; 'SID,SERIR#';</span></span></p>
<img src ="http://www.blogjava.net/franlk/aggbug/128324.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-07-05 14:02 <a href="http://www.blogjava.net/franlk/articles/128324.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]oracle问题集</title><link>http://www.blogjava.net/franlk/articles/128025.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Wed, 04 Jul 2007 01:50:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/128025.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/128025.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/128025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/128025.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/128025.html</trackback:ping><description><![CDATA[<p><br>转载地址:http://blog.oracle.com.cn/html/91/t-120491.html<br><br>1. Oracle安裝完成后的初始口令? <br>　　internal/oracle </p>
<p>　　sys/change_on_install </p>
<p>　　system/manager </p>
<p>　　scott/tiger </p>
<p>　　sysman/oem_temp </p>
<p>　　2. ORACLE9IAS WEB CACHE的初始默认用户和密码？ </p>
<p>　　administrator/administrator </p>
<p>　　3. oracle 8.0.5怎么创建数据库? </p>
<p>　　用orainst。如果有motif界面，可以用orainst /m </p>
<p>　　4. oracle 8.1.7怎么创建数据库? </p>
<p>　　dbassist </p>
<p>　　5. oracle 9i 怎么创建数据库? </p>
<p>　　dbca </p>
<p>　　6. oracle中的裸设备指的是什么? </p>
<p>　　裸设备就是绕过文件系统直接访问的储存空间 </p>
<p>　　7. oracle如何区分 64-bit/32bit 版本？</p>
<p>　　$ sqlplus '/ AS SYSDBA' <br>　　SQL*Plus: Release 9.0.1.0.0 - Production on Mon Jul 14 17:01:09 2003 <br>　　(c) Copyright 2001 Oracle Corporation. All rights reserved. <br>　　Connected to: <br>　　Oracle9i Enterprise Edition Release 9.0.1.0.0 - Production With the Partitioning option <br>　　JServer Release 9.0.1.0.0 - Production <br>　　SQL&gt; select * from v$version; <br>　　BANNER <br>　　---------------------------------------------------------------- <br>　　Oracle9i Enterprise Edition Release 9.0.1.0.0 - Production <br>　　PL/SQL Release 9.0.1.0.0 - Production <br>　　CORE 9.0.1.0.0 Production <br>　　TNS for Solaris: Version 9.0.1.0.0 - Production <br>　　NLSRTL Version 9.0.1.0.0 - Production <br>　　SQL&gt; </p>
<p>　　8. SVRMGR什么意思？ </p>
<p>　　svrmgrl，Server Manager. <br>　　9i下没有，已经改为用SQLPLUS了 <br>　　sqlplus /nolog <br>　　变为归档日志型的 </p>
<p>　　9. 请问如何分辨某个用户是从哪台机器登陆ORACLE的? </p>
<p>　　SELECT machine , terminal FROM V$SESSION; </p>
<p>　　10. 用什么语句查询字段呢？ </p>
<p>　　desc table_name 可以查询表的结构 <br>　　select field_name,... from ... 可以查询字段的值 </p>
<p>　　select * from all_tables where table_name like '%' <br>　　select * from all_tab_columns where table_name='??' </p>
<p>　　11. 怎样得到触发器、过程、函数的创建脚本？ </p>
<p>　　desc user_source <br>　　user_triggers </p>
<p>　　12. 怎样计算一个表占用的空间的大小？ </p>
<p>　　select owner,table_name, <br>　　NUM_ROWS, <br>　　BLOCKS*AAA/1024/1024 "Size M", <br>　　EMPTY_BLOCKS, <br>　　LAST_ANALYZED <br>　　from dba_tables <br>　　where table_name='XXX'; </p>
<p>　　Here: AAA is the value of db_block_size ; <br>　　XXX is the table name you want to check </p>
<p>　　13. 如何查看最大会话数？ </p>
<p>　　SELECT * FROM V$PARAMETER WHERE NAME LIKE 'proc%'; </p>
<p>　　SQL&gt; <br>　　SQL&gt; show parameter processes </p>
<p>　　NAME 　　　　　　　　　　　　　　　　　　TYPE 　　　　　　VALUE <br>　　-----------------------------------　------------　-------------------------- <br>　　aq_tm_processes 　　　　　　　　　　　integer 　　　　　　　1 <br>　　db_writer_processes 　　　　　　　　　integer 　　　　　　　1 <br>　　job_queue_processes 　　　　　　　　　integer 　　　　　　　4 <br>　　log_archive_max_processes 　　　　　　integer 　　　　　　　1 <br>　　processes 　　　　　　　　　　　　　　integer 　　　　　　　200 </p>
<p>　　这里为200个用户。 </p>
<p>　　select * from v$license; <br>　　其中sessions_highwater纪录曾经到达的最大会话数 </p>
<p>　　14. 如何查看系统被锁的事务时间？ </p>
<p>　　select * from v$locked_object ; </p>
<p>　　15. 如何以archivelog的方式运行oracle？ </p>
<p>　　init.ora <br>　　log_archive_start = true </p>
<p>　　RESTART DATABASE </p>
<p>　　16. 怎么获取有哪些用户在使用数据库 </p>
<p>　　select username from v$session; </p>
<p>　　17. 数据表中的字段最大数是多少? </p>
<p>　　表或视图中的最大列数为 1000 </p>
<p>　　18. 怎样查得数据库的SID ? </p>
<p>　　select name from v$database; <br>　　也可以直接查看 init.ora文件 </p>
<p>　　19. 如何在Oracle服务器上通过SQLPLUS查看本机IP地址 ? </p>
<p>　　select sys_context('userenv','ip_address') from dual; </p>
<p>　　如果是登陆本机数据库，只能返回127.0.0.1，呵呵 </p>
<p>　　20. unix 下怎么调整数据库的时间？ </p>
<p>　　su -root <br>　　date -u 08010000 </p>
<p>　　21. 在ORACLE TABLE中如何抓取MEMO類型欄位為空的資料記錄? </p>
<p>　　select remark from oms_flowrec where trim(' ' from remark) is not null ; </p>
<p><br>　　22. 如何用BBB表的資料去更新AAA表的資料(有關聯的字段) </p>
<p>　　UPDATE AAA SET BNS_SNM=(SELECT BNS_SNM FROM BBB WHERE AAA.DPT_NO=BBB.DPT_NO) WHERE BBB.DPT_NO IS NOT NULL; </p>
<p>　　23. P4電腦安裝方法 </p>
<p>　　將SYMCJIT.DLL改為SYSMCJIT.OLD </p>
<p>　　24. 何查詢SERVER是不是OPS? </p>
<p>　　SELECT *　FROM V$OPTION; </p>
<p>　　如果PARALLEL SERVER=TRUE則有OPS能 </p>
<p>　　25. 何查詢每個用戶的權限? </p>
<p>　　SELECT *　FROM DBA_SYS_PRIVS; </p>
<p>　　26. 如何將表移動表空間? </p>
<p>　　ALTER TABLE TABLE_NAME MOVE TABLESPACE_NAME; </p>
<p>　　27. 如何將索引移動表空間? </p>
<p>　 　ALTER INDEX INDEX_NAME REBUILD TABLESPACE TABLESPACE_NAME; </p>
<p>　　28. 在LINUX,UNIX下如何啟動DBA STUDIO? </p>
<p>　　OEMAPP　DBASTUDIO </p>
<p>　　29. 查詢鎖的狀況的對象有? </p>
<p>　　V$LOCK,　V$LOCKED_OBJECT,　V$SESSION,　V$SQLAREA,　V$PROCESS ; </p>
<p>　　查詢鎖的表的方法: </p>
<p>　　SELECT S.SID SESSION_ID, S.USERNAME, DECODE(LMODE, 0, 'None', 1, 'Null', 2, 'Row-S (SS)', 3, 'Row-X (SX)', 4, 'Share', 5, 'S/Row-X (SSX)', 6, 'Exclusive', TO_CHAR(LMODE)) MODE_HELD, DECODE(REQUEST, 0, 'None', 1, 'Null', 2, 'Row-S (SS)', 3, 'Row-X (SX)', 4, 'Share', 5, 'S/Row-X (SSX)', 6, 'Exclusive', TO_CHAR(REQUEST)) MODE_REQUESTED, O.OWNER||'.'||O.OBJECT_NAME||' ('||O.OBJECT_TYPE||')', S.TYPE LOCK_TYPE, L.ID1 LOCK_ID1, L.ID2 LOCK_ID2 FROM V$LOCK L, SYS.DBA_OBJECTS O, V$SESSION S WHERE L.SID = S.SID AND L.ID1 = O.OBJECT_ID ; </p>
<p>　　30. 如何解鎖? </p>
<p>　　ALTER SYSTEM KILL SESSION　&#8216;SID,SERIR#&#8217;; </p>
<p>　　31. SQLPLUS下如何修改編輯器? </p>
<p>　　DEFINE _EDITOR="&lt;编辑器的完整路经&gt;"　-- 必须加上双引号来定义新的编辑器，也可以把这个写在$ORACLE_HOME/sqlplus/admin/glogin.sql里面使它永久有效。 </p>
<p>　　32. ORACLE產生隨機函數是? </p>
<p>　　DBMS_RANDOM.RANDOM </p>
<p>　　33. LINUX下查詢磁盤競爭狀況命令? LINUX下查詢CPU競爭狀況命令?</p>
<p>　　Sar　-d<br>　　sar　-r </p>
<p>　　34. 查詢當前用戶對象? </p>
<p>　　SELECT *　FROM USER_OBJECTS; </p>
<p>　　SELECT *　FROM DBA_SEGMENTS; </p>
<p>　　35. 如何獲取錯誤信息? </p>
<p>　　SELECT *　FROM　USER_ERRORS; </p>
<p>　　36. 如何獲取鏈接狀況? </p>
<p>　　SELECT * FROM DBA_DB_LINKS; </p>
<p>　　37. 查看數據庫字符狀況? </p>
<p>　　SELECT *　FROM NLS_DATABASE_PARAMETERS; </p>
<p>　　SELECT *　FROM V$NLS_PARAMETERS; </p>
<p>　　38. 查詢表空間信息? </p>
<p>　　SELECT *　FROM　DBA_DATA_FILES; </p>
<p>　　39. ORACLE的INTERAL用戶要口令? </p>
<p>　　修改 SQLNET.ORA </p>
<p>　　SQLNET.AUTHENTICATION_SERVICES=(NTS) </p>
<p>　　40. 出現JAVA.EXE的解決辦法? </p>
<p>　　一般是將ORACLE ORAHOME XI HTTP SERVER改成手工啟動可以的 </p>
<p>　　X是8或9 </p>
<p>　　41. 如何给表、列加注释？ </p>
<p>　　SQL&gt;comment on table 表 is '表注释'; </p>
<p>　　注释已创建。 </p>
<p>　　SQL&gt;comment on column 表.列 is '列注释'; </p>
<p>　　注释已创建。 </p>
<p>　　SQL&gt; select * from user_tab_comments where comments is not null; </p>
<p>　　42. 如何查看各个表空间占用磁盘情况？ </p>
<p>　　SQL&gt; col tablespace format a20 <br>　　SQL&gt; select <br>　　　 　　b.file_id　　　　　　　　　　　　　　　文件ID号, <br>　　　 　　b.tablespace_name　　　　　　　　　　　表空间名, <br>　　　 　　b.bytes　　　　　　　　　　　　　　　　字节数, <br>　　　 　　(b.bytes-sum(nvl(a.bytes,0)))　　　　　已使用, <br>　　　 　　sum(nvl(a.bytes,0))　　　　　　　　　　剩余空间, <br>　　　 　　sum(nvl(a.bytes,0))/(b.bytes)*100　　　剩余百分比 <br>　　　 　from dba_free_space a,dba_data_files b <br>　　　 　where a.file_id=b.file_id <br>　　　 　group by b.tablespace_name,b.file_id,b.bytes <br>　　　 　order by b.file_id </p>
<p>　　43. 如把ORACLE设置为MTS或专用模式？ </p>
<p>　　#dispatchers="(PROTOCOL=TCP) (SERVICE=SIDXDB)" 加上就是MTS，注释就是专用模式，SID是指你的实例名。 </p>
<p>　　44. 如何才能得知系统当前的SCN号 ? </p>
<p>　　select max(ktuxescnw * power(2, 32) + ktuxescnb) from x$ktuxe; </p>
<p>　　45. 请问如何在ORACLE中取毫秒? </p>
<p>　　9i之前不支持,9i开始有timestamp. </p>
<p>　　9i可以用select systimestamp from dual; </p>
<p>---------------------------------------------------------------------------------------<br>46. 如何在字符串里加回车？ <br>　　select 'Welcome to visit'||chr(10)||'www.CSDN.NET' from dual ; </p>
<p>　　47. 中文是如何排序的？ </p>
<p>　　Oracle9i之前，中文是按照二进制编码进行排序的。 </p>
<p>　　在oracle9i中新增了按照拼音、部首、笔画排序功能。设置NLS_SORT值 </p>
<p>　　SCHINESE_RADICAL_M 按照部首（第一顺序）、笔划（第二顺序）排序 </p>
<p>　　SCHINESE_STROKE_M 按照笔划（第一顺序）、部首（第二顺序）排序 </p>
<p>　　SCHINESE_PINYIN_M 按照拼音排序 </p>
<p>　　48.　Oracle8i中对象名可以用中文吗？ </p>
<p>　　可以 </p>
<p>　　49. 如何改变WIN中SQL*Plus启动选项？ </p>
<p>　　SQL*PLUS自身的选项设置我们可以在$ORACLE_HOME/sqlplus/admin/glogin.sql中设置。 </p>
<p>　　50. 怎样修改oracel数据库的默认日期? </p>
<p>　　alter session set nls_date_format='yyyymmddhh24miss'; <br>　　OR </p>
<p>　　可以在init.ora中加上一行 nls_date_format='yyyymmddhh24miss' </p>
<p>　　51. 如何将小表放入keep池中? </p>
<p>　　alter table xxx storage(buffer_pool keep); </p>
<p>　　52. 如何检查是否安装了某个patch? </p>
<p>　　check that　oraInventory </p>
<p>　　53. 如何使select语句使查询结果自动生成序号? </p>
<p>　　select rownum,COL from table; </p>
<p>　　54. 如何知道数据裤中某个表所在的tablespace? </p>
<p>　　select tablespace_name from user_tables where table_name='TEST'; </p>
<p>　　select * from user_tables中有个字段TABLESPACE_NAME，（oracle）; </p>
<p>　　select * from dba_segments where &#8230;; </p>
<p>　　55. 怎么可以快速做一个和原表一样的备份表? </p>
<p>　　create table new_table as (select * from old_table); </p>
<p>　　　　 怎么在sqlplus下修改procedure? </p>
<p>　　select line,trim(text) t from user_source where name =&#8217;A&#8217; order by line; </p>
<p>　　56. 怎样解除PROCEDURE被意外锁定? </p>
<p>　　alter system kill session ,把那个session给杀掉，不过你要先查出她的session id </p>
<p>　　or </p>
<p>　　把该过程重新改个名字就可以了。 </p>
<p>　　57. SQL Reference是个什么东西？ </p>
<p>　　是一本sql的使用手册，包括语法、函数等等，oracle官方网站的文档中心有下载. </p>
<p>　　58. 如何查看数据库的状态? </p>
<p>　　unix下 <br>　　　ps -ef | grep ora <br>　　windows下 <br>　　　看服务是否起来，是否可以连上数据库 </p>
<p>　　59. 请问如何修改一张表的主键? </p>
<p>　　alter table aaa <br>　　drop constraint aaa_key ; <br>　　alter table aaa <br>　　add constraint aaa_key primary key(a1,b1) ; </p>
<p>　　60. 改变数据文件的大小? </p>
<p>　　用 ALTER DATABASE .... DATAFILE .... ; <br>　　手工改变数据文件的大小，对于原来的 数据文件有没有损害。 </p>
<p>　　61. 怎样查看ORACLE中有哪些程序在运行之中？ </p>
<p>　　查看v$sessions表 </p>
<p>　　62. 怎么可以看到数据库有多少个tablespace? </p>
<p>　　select　*　 from dba_tablespaces; </p>
<p>　　63. 如何修改oracle数据库的用户连接数？ </p>
<p>　　修改initSID.ora，将process加大，重启数据库. </p>
<p>　　64. 如何查出一条记录的最后更新时间? </p>
<p>　　可以用logminer 察看 </p>
<p>　　65. 如何在PL/SQL中读写文件？ </p>
<p>　　UTL_FILE包允许用户通过PL/SQL读写操作系统文件。 </p>
<p>　　66. 怎樣把&#8220;&amp;&#8221;放入一條記錄中？ </p>
<p>　　insert into a values (translate ('at{&amp;}t','at{}','at')); </p>
<p>　　67. EXP　如何加ＱＵＥＲＹ参数？ </p>
<p>　　EXP USER/PASS FILE=A.DMP TABLES(BSEMPMS) <br>　　QUERY='"WHERE EMP_NO=\'S09394\'\" ﹔ </p>
<p>　　68. 关于oracle8i支持简体和繁体的字符集问题？ </p>
<p>　　ZHS16GBK可以支持 </p>
<p>　　69. Data Guard是什么软件？ </p>
<p>　　就是Standby的换代产品 </p>
<p>　　70. 如何創建SPFILE? </p>
<p>　　SQL&gt; connect / as sysdba <br>　　SQL&gt; select * from v$version; <br>　　SQL&gt; create pfile from spfile; <br>　　SQL&gt; CREATE SPFILE FROM PFILE='E:\ora9i\admin\eygle\pfile\init.ora';<br>　　文件已创建。 <br>　　SQL&gt; CREATE SPFILE='E:\ora9i\database\SPFILEEYGLE.ORA' FROM PFILE='E:\ora9i\admin\eygle\pfile\init.ora'; <br>　　文件已创建。 </p>
<p>　　71. 內核參數的應用? </p>
<p>　　shmmax <br>　　　含义：这个设置并不决定究竟Oracle数据库或者操作系统使用多少物理内存，只决定了最多可以使用的内存数目。这个设置也不影响操作系统的内核资源。 <br>　　　设置方法：0.5*物理内存 <br>　　　例子：Set shmsys:shminfo_shmmax=10485760 <br>　　shmmin <br>　　　含义：共享内存的最小大小。 <br>　　　设置方法：一般都设置成为1。 <br>　　　例子：Set shmsys:shminfo_shmmin=1： <br>　　shmmni <br>　　　含义：系统中共享内存段的最大个数。 <br>　　　例子：Set shmsys:shminfo_shmmni=100 <br>　　shmseg <br>　　　含义：每个用户进程可以使用的最多的共享内存段的数目。 <br>　　　例子：Set shmsys:shminfo_shmseg=20： <br>　　semmni <br>　　　含义：系统中semaphore identifierer的最大个数。 <br>　　　设置方法：把这个变量的值设置为这个系统上的所有Oracle的实例的init.ora中的最大的那个processes的那个值加10。 <br>　　　例子：Set semsys:seminfo_semmni=100 <br>　　semmns <br>　　　含义：系统中emaphores的最大个数。 <br>　　　设置方法：这个值可以通过以下方式计算得到：各个Oracle实例的initSID.ora里边的processes的值的总和（除去最大的Processes参数）＋最大的那个Processes&#215;2＋10&#215;Oracle实例的个数。 <br>　　　例子：Set semsys:seminfo_semmns=200 <br>　　semmsl: <br>　　　含义：一个set中semaphore的最大个数。 <br>　　　设置方法：设置成为10＋所有Oracle实例的InitSID.ora中最大的Processes的值。 <br>　　　例子：Set semsys:seminfo_semmsl=-200 </p>
<p>　　72. 怎样查看哪些用户拥有SYSDBA、SYSOPER权限？ </p>
<p>　　SQL&gt;conn sys/change_on_install <br>　　SQL&gt;select * from V_$PWFILE_USERS; </p>
<p>　　73. 如何单独备份一个或多个表？ </p>
<p>　　exp 用户/密码 tables=(表1,&#8230;,表2) </p>
<p>　　74. 如何单独备份一个或多个用户？ </p>
<p>　　exp system/manager owner=(用户1,用户2,&#8230;,用户n) file=导出文件 </p>
<p>　　75. 如何对CLOB字段进行全文检索？ </p>
<p>　　SELECT * FROM A WHERE dbms_lob.instr(a.a,'K',1,1)&gt;0; </p>
<p>　　76. 如何显示当前连接用户? </p>
<p>　　SHOW　USER </p>
<p>　　77. 如何查看数据文件放置的路径 ? </p>
<p>　　col file_name format a50 <br>　　SQL&gt; select tablespace_name,file_id,bytes/1024/1024,file_name <br>　　　　 from dba_data_files 　　<br>　　　　 order by file_id; </p>
<p>　　78. 如何查看现有回滚段及其状态 ? </p>
<p>　　SQL&gt; col segment format a30 <br>　　SQL&gt; SELECT SEGMENT_NAME,OWNER,TABLESPACE_NAME,SEGMENT_ID,FILE_ID,STATUS FROM 　　DBA_ROLLBACK_SEGS </p>
<p>　　79. 如何改变一个字段初始定义的Check范围？ </p>
<p>　　SQL&gt; alter table xxx drop constraint constraint_name; <br>　　之后再创建新约束: <br>　　SQL&gt; alter table xxx add constraint constraint_name check(); </p>
<p>　　80. Oracle常用系统文件有哪些？ </p>
<p>　　通过以下视图显示这些文件信息：v$database,v$datafile,v$logfile v$controlfile v$parameter; </p>
<p>　　81. 內連接INNER JOIN? </p>
<p>　　Select a.* from bsempms a,bsdptms b where a.dpt_no=b.dpt_no; </p>
<p>　　82. 如何外連接? </p>
<p>　　Select a.* from bsempms a,bsdptms b where a.dpt_no=b.dpt_no(+); </p>
<p>　　Select a.* from bsempms a,bsdptms b wherea.dpt_no(+)=b.dpt_no; </p>
<p>　　83. 如何執行腳本SQL文件? </p>
<p>　　SQL&gt;@$PATH/filename.sql; </p>
<p>　　84. 如何快速清空一個大表? </p>
<p>　　SQL&gt;truncate table table_name; </p>
<p>　　85. 如何查有多少個數据庫實例? </p>
<p>　　SQL&gt;SELECT * FROM V$INSTANCE; </p>
<p>　　86. 如何查詢數据庫有多少表? </p>
<p>　　SQL&gt;select * from all_tables; </p>
<p>　　87. 如何測試SQL語句執行所用的時間? </p>
<p>　　SQL&gt;set timing on ; </p>
<p>　　SQL&gt;select * from tablename;</p>
<p>　　88. CHR()的反函數是? </p>
<p>　　ASCII() </p>
<p>　　SELECT CHAR(65) FROM DUAL;　 </p>
<p>　　SELECT ASCII('A') FROM DUAL; </p>
<p>　　89. 字符串的連接 </p>
<p>　　SELECT CONCAT(COL1,COL2) FROM TABLE ; </p>
<p>　　SELECT COL1||COL2 FROM TABLE ; </p>
<p>　　90. 怎么把select出来的结果导到一个文本文件中？ </p>
<p>　　SQL&gt;SPOOL　C:\ABCD.TXT; </p>
<p>　　SQL&gt;select *　from table; </p>
<p>　　SQL &gt;spool off;</p>
<p>----------------------------------------------------------------------------------------<br>91. 怎样估算SQL执行的I/O数 ? <br>　　SQL&gt;SET AUTOTRACE ON ; </p>
<p>　　SQL&gt;SELECT * FROM TABLE; </p>
<p>　　OR </p>
<p>　　SQL&gt;SELECT *　FROM　v$filestat ; </p>
<p>　　可以查看IO数 </p>
<p>　　92. 如何在sqlplus下改变字段大小? </p>
<p>　　alter table table_name modify (field_name varchar2(100)); </p>
<p>　　改大行，改小不行（除非都是空的） </p>
<p>　　93. 如何查询某天的数据? </p>
<p>　　select * from table_name where trunc(日期字段)＝to_date('2003-05-02','yyyy-mm-dd'); </p>
<p>　　94. sql 语句如何插入全年日期？ </p>
<p>　　create table BSYEAR (d date); <br>　　insert into BSYEAR <br>　　select to_date('20030101','yyyymmdd')+rownum-1 <br>　　from all_objects <br>　　where rownum &lt;= to_char(to_date('20031231','yyyymmdd'),'ddd'); </p>
<p>　　95. 如果修改表名? </p>
<p>　　alter table old_table_name rename to new_table_name; </p>
<p>　　96. 如何取得命令的返回状态值？ </p>
<p>　　sqlcode=0 </p>
<p>　　97. 如何知道用户拥有的权限? </p>
<p>　　SELECT * FROM dba_sys_privs ; </p>
<p>　　98. 从网上下载的ORACLE9I与市场上卖的标准版有什么区别？ </p>
<p>　　从功能上说没有区别，只不过oracle公司有明文规定；从网站上下载的oracle产品不得用于商业用途，否则侵权。 </p>
<p>　　99. 怎样判断数据库是运行在归档模式下还是运行在非归档模式下？ </p>
<p>　　进入dbastudio，历程--〉数据库---〉归档查看。 </p>
<p>　　100. sql&gt;startup pfile和ifile,spfiled有什么区别？ </p>
<p>　　pfile就是Oracle传统的初始化参数文件，文本格式的。 <br>　　ifile类似于c语言里的include，用于把另一个文件引入 <br>　　spfile是9i里新增的并且是默认的参数文件，二进制格式 <br>　　startup后应该只可接pfile </p>
<p>　　101. 如何搜索出前N条记录？ </p>
<p>　　SELECT * FROM empLOYEE WHERE ROWNUM &lt; n <br>　　ORDER BY empno; </p>
<p>　　102. 如何知道机器上的Oracle支持多少并发用户数? </p>
<p>　　SQL&gt;conn internal　; <br>　　SQL&gt;show parameter processes ; </p>
<p>　　103. db_block_size可以修改嗎? </p>
<p>　　一般不可以﹐不建議這樣做的。 </p>
<p>　　104. 如何统计两个表的记录总数? </p>
<p>　　select (select count(id) from aa)+(select count(id) from bb) 总数 from dual; </p>
<p>　　105. 怎样用Sql语句实现查找一列中第N大值？ </p>
<p>　　select * from (select t.*,dense_rank() over (order by sal) rank from employee) <br>　　where rank = N; </p>
<p>　　106. 如何在给现有的日期加上2年？</p>
<p>　　select add_months(sysdate,24) from dual; </p>
<p>　　107. USED_UBLK为负值表示什么意思? </p>
<p>　　It is "harmless". </p>
<p>　　108. Connect string是指什么? </p>
<p>　　应该是tnsnames.ora中的服务名后面的内容 </p>
<p>　　109. 怎样扩大REDO LOG的大小？ </p>
<p>　　建立一个临时的redolog组，然后切换日志，删除以前的日志，建立新的日志。 </p>
<p>　　110. tablespace 是否不能大于4G? </p>
<p>　　没有限制. </p>
<p>　　111. 返回大于等于N的最小整數值? </p>
<p>　　SELECT CEIL(N)　FROM DUAL; </p>
<p>　　112. 返回小于等于N的最小整數值? </p>
<p>　　SELECT FLOOR(N)　FROM DUAL; </p>
<p>　　113. 返回當前月的最后一天? </p>
<p>　　SELECT LAST_DAY(SYSDATE)　FROM DUAL; </p>
<p>　　114. 如何不同用戶間數據導入? </p>
<p>　　IMP SYSTEM/MANAGER FILE=AA.DMP FROMUSER=USER_OLD TOUSER=USER_NEW ROWS=Y INDEXES=Y; </p>
<p>　　115. 如何找数据库表的主键字段的名称? </p>
<p>　　SQL&gt;SELECT * FROM user_constraints WHERE CONSTRAINT_TYPE='P' and　 table_name='TABLE_NAME'; </p>
<p>　　116. 兩個結果集互加的函數? </p>
<p>　　SQL&gt;SELECT * FROM BSEMPMS_OLD INTERSECT SELECT * FROM BSEMPMS_NEW; <br>　　SQL&gt;SELECT * FROM BSEMPMS_OLD UNION SELECT * FROM BSEMPMS_NEW; <br>　　SQL&gt;SELECT * FROM BSEMPMS_OLD UNION ALL SELECT * FROM BSEMPMS_NEW; </p>
<p>　　117. 兩個結果集互減的函數? </p>
<p>　　SQL&gt;SELECT * FROM BSEMPMS_OLD MINUS SELECT * FROM BSEMPMS_NEW; </p>
<p>　　118. 如何配置Sequence? </p>
<p>　　建sequence seq_custid <br>　　create sequence seq_custid start 1 incrememt by 1; <br>　　建表时: <br>　　create table cust <br>　　{ cust_id smallint not null, <br>　　...} <br>　　insert 时: <br>　　insert into table cust <br>　　values( seq_cust.nextval, ...)</p>
<p>　　日期的各部分的常用的的寫法 </p>
<p>　　119.取時間點的年份的寫法:</p>
<p>　　SELECT TO_CHAR(SYSDATE,'YYYY') FROM DUAL; </p>
<p>　　120.取時間點的月份的寫法:</p>
<p>　　SELECT TO_CHAR(SYSDATE,'MM') FROM DUAL; </p>
<p>　　121.取時間點的日的寫法: </p>
<p>　　SELECT TO_CHAR(SYSDATE,'DD') FROM DUAL; </p>
<p>　　122.取時間點的時的寫法: </p>
<p>　　SELECT TO_CHAR(SYSDATE,'HH24') FROM DUAL; </p>
<p>　　123.取時間點的分的寫法: </p>
<p>　　SELECT TO_CHAR(SYSDATE,'MI') FROM DUAL; </p>
<p>　　124.取時間點的秒的寫法: </p>
<p>　　SELECT TO_CHAR(SYSDATE,'SS') FROM DUAL; </p>
<p>　　125.取時間點的日期的寫法: </p>
<p>　　SELECT TRUNC(SYSDATE) FROM DUAL; </p>
<p>　　126.取時間點的時間的寫法:</p>
<p>　　SELECT TO_CHAR(SYSDATE,'HH24:MI:SS') FROM DUAL; </p>
<p>　　127.日期,時間形態變為字符形態 </p>
<p>　　SELECT TO_CHAR(SYSDATE) FROM DUAL; </p>
<p>　　128.將字符串轉換成日期或時間形態: </p>
<p>　　SELECT TO_DATE('2003/08/01') FROM DUAL; </p>
<p>　　129.返回參數的星期几的寫法:</p>
<p>　　SELECT TO_CHAR(SYSDATE,'D') FROM DUAL; </p>
<p>　　130.返回參數一年中的第几天的寫法: </p>
<p>　　SELECT TO_CHAR(SYSDATE,'DDD') FROM DUAL; </p>
<p>　　131.返回午夜的寫法: </p>
<p>　　SELECT TO_CHAR(SYSDATE) FROM DUAL; </p>
<p>　　132.返回參數中指定的時間值之間的秒數的寫法： </p>
<p>　　SELECT TO_CHAR('SSSSS' ) FROM DUAL;</p>
<p>　　虚擬字段</p>
<p>　　133. CURRVAL 和 nextval <br>　　为表创建序列 <br>　　CREATE SEQUENCE EMPSEQ ... ; <br>　　SELECT empseq.currval FROM DUAL ; <br>　　自动插入序列的数值 <br>　　INSERT INTO emp <br>　　VALUES (empseq.nextval, 'LEWIS', 'CLERK', 7902, SYSDATE, 1200, NULL, 20) ; </p>
<p>　　134. ROWNUM <br>　　按设定排序的行的序号 <br>　　SELECT * FROM emp WHERE ROWNUM &lt; 10 ; </p>
<p>　　135. ROWID <br>　　返回行的物理地址 <br>　　SELECT ROWID, ename FROM emp　WHERE deptno = 20 ;</p>
<p>-----------------------------------------------------------------------------------------<br>136. 将N秒转换为时分秒格式？ </p>
<p>　　set serverout on <br>　　declare <br>　　N number := 1000000; <br>　　ret varchar2(100); <br>　　begin <br>　　ret := trunc(n/3600) || '小时' || to_char(to_date(mod(n,3600),'sssss'),'fmmi"分　 "ss"秒"') ; <br>　　dbms_output.put_line(ret); <br>　　end; <br>　　137. 如何查询做比较大的排序的进程？</p>
<p>　　SELECT b.tablespace, b.segfile#, b.segblk#, b.blocks, a.sid, a.serial#, a.username, a.osuser, a.status <br>　　FROM v$session a,v$sort_usage b <br>　　WHERE a.saddr = b.session_addr <br>　　ORDER BY b.tablespace, b.segfile#, b.segblk#, b.blocks ; </p>
<p>　　138. 如何查询做比较大的排序的进程的SQL语句？ </p>
<p>　　select /*+ ORDERED */ sql_text from v$sqltext a <br>　　where a.hash_value = ( <br>　　　select sql_hash_value from v$session b <br>　　　where b.sid = &amp;sid and b.serial# = &amp;serial) <br>　　order by piece asc ; </p>
<p>　　139. 如何查找重复记录？ </p>
<p>　　SELECT * FROM TABLE_NAME <br>　　WHERE ROWID!=(SELECT MAX(ROWID) FROM TABLE_NAME D <br>　　WHERE TABLE_NAME.COL1=D.COL1 AND TABLE_NAME.COL2=D.COL2); </p>
<p>　　140. 如何删除重复记录？ </p>
<p>　　DELETE FROM TABLE_NAME <br>　　WHERE ROWID!=(SELECT MAX(ROWID) FROM TABLE_NAME D <br>　　WHERE TABLE_NAME.COL1=D.COL1 AND TABLE_NAME.COL2=D.COL2); </p>
<p>　　141. 如何快速编译所有视图？ </p>
<p>　　SQL &gt;SPOOL VIEW1.SQL <br>　　SQL &gt;SELECT &#8216;ALTER VIEW &#8216;||TNAME||&#8217; <br>　　COMPILE;&#8217; FROM TAB; <br>　　SQL &gt;SPOOL OFF <br>　　然后执行VIEW1.SQL即可。 <br>　　SQL &gt;@VIEW1.SQL; </p>
<p>　　142. ORA-01555 SNAPSHOT TOO OLD的解决办法 </p>
<p>　　增加MINEXTENTS的值，增加区的大小，设置一个高的OPTIMAL值。 </p>
<p>　　143. 事务要求的回滚段空间不够，表现为表空间用满（ORA-01560错误），回滚段扩展到达参数MAXEXTENTS的值（ORA-01628）的解决办法. </p>
<p>　　向回滚段表空间添加文件或使已有的文件变大；增加MAXEXTENTS的值。 </p>
<p>　　144. 如何加密ORACLE的存储过程？ </p>
<p>　　下列存储过程内容放在AA.SQL文件中 <br>　　create or replace procedure testCCB(i in number) as <br>　　begin <br>　　dbms_output.put_line('输入参数是'||to_char(i)); <br>　　end; </p>
<p>　　SQL&gt;wrap iname=a.sql; <br>　　PL/SQL Wrapper: Release 8.1.7.0.0 - Production on Tue Nov 27 22:26:48 2001 <br>　　Copyright (c) Oracle Corporation 1993, 2000.　All Rights Reserved. <br>　　Processing AA.sql to AA.plb <br>　　运行AA.plb <br>　　SQL&gt; @AA.plb ; </p>
<p>　　145. 如何监控事例的等待？ </p>
<p>　　select event,sum(decode(wait_Time,0,0,1)) "Prev", <br>　　sum(decode(wait_Time,0,1,0)) "Curr",count(*) "Tot" <br>　　from v$session_Wait <br>　　group by event order by 4; </p>
<p>　　146. 如何回滚段的争用情况？ </p>
<p>　　select name, waits, gets, waits/gets "Ratio" <br>　　from v$rollstat C, v$rollname D <br>　　where C.usn = D.usn; </p>
<p>　　147. 如何监控表空间的 I/O 比例？ </p>
<p>　　select B.tablespace_name name,B.file_name "file",A.phyrds pyr, A.phyblkrd pbr,A.phywrts pyw, A.phyblkwrt pbw <br>　　from v$filestat A, dba_data_files B <br>　　where A.file# = B.file_id <br>　　order by B.tablespace_name; </p>
<p>　　148. 如何监控文件系统的 I/O 比例？ </p>
<p>　　select substr(C.file#,1,2) "#", substr(C.name,1,30) "Name", C.status, C.bytes, D.phyrds, D.phywrts <br>　　from v$datafile C, v$filestat D <br>　　where C.file# = D.file#; </p>
<p>　　149. 如何在某个用户下找所有的索引？ </p>
<p>　　select user_indexes.table_name, user_indexes.index_name,uniqueness, column_name <br>　　from user_ind_columns, user_indexes <br>　　where user_ind_columns.index_name = user_indexes.index_name <br>　　and user_ind_columns.table_name = user_indexes.table_name <br>　　order by user_indexes.table_type, user_indexes.table_name, user_indexes.index_name, column_position; </p>
<p>　　150. 如何监控 SGA 的命中率？</p>
<p>　　select a.value + b.value "logical_reads", c.value "phys_reads", <br>　　round(100 * ((a.value+b.value)-c.value) / (a.value+b.value)) "BUFFER HIT RATIO" <br>　　from v$sysstat a, v$sysstat b, v$sysstat c <br>　　where a.statistic# = 38 and b.statistic# = 39 <br>　　and c.statistic# = 40; </p>
<p>　　151. 如何监控 SGA 中字典缓冲区的命中率？ </p>
<p>　　select parameter, gets,Getmisses , getmisses/(gets+getmisses)*100 "miss ratio", (1-(sum(getmisses)/ (sum(gets)+sum(getmisses))))*100 "Hit ratio" <br>　　from v$rowcache <br>　　where gets+getmisses &lt;&gt;0 <br>　　group by parameter, gets, getmisses; </p>
<p>　　152. 如何监控 SGA 中共享缓存区的命中率，应该小于1% ？ </p>
<p>　　select sum(pins) "Total Pins", sum(reloads) "Total Reloads", <br>　　sum(reloads)/sum(pins) *100 libcache <br>　　from v$librarycache; </p>
<p>　　select sum(pinhits-reloads)/sum(pins) "hit radio",<br>sum(reloads)/sum(pins) "reload percent" <br>　　from v$librarycache; </p>
<p>　　153. 如何显示所有数据库对象的类别和大小？ </p>
<p>　　select count(name) num_instances ,type ,sum(source_size) source_size , sum(parsed_size) parsed_size ,sum(code_size) code_size,sum(error_size) error_size, <br>sum(source_size) +sum(parsed_size) +sum(code_size) +sum(error_size) size_required <br>　　from dba_object_size <br>　　group by type order by 2; </p>
<p>　　154. 监控 SGA 中重做日志缓存区的命中率，应该小于1% </p>
<p>　　SELECT name, gets, misses, immediate_gets, immediate_misses, <br>　　Decode(gets,0,0,misses/gets*100) ratio1, <br>　　Decode(immediate_gets+immediate_misses,0,0, <br>　　immediate_misses/(immediate_gets+immediate_misses)*100) ratio2 <br>　　FROM v$latch WHERE name IN ('redo allocation', 'redo copy'); </p>
<p>　　155. 监控内存和硬盘的排序比率，最好使它小于 .10，增加 sort_area_size </p>
<p>　　SELECT name, value FROM v$sysstat WHERE name IN ('sorts (memory)', 'sorts (disk)'); </p>
<p>　　156. 如何监控当前数据库谁在运行什么SQL语句？ </p>
<p>　　SELECT osuser, username, sql_text from v$session a, v$sqltext b <br>　　where a.sql_address =b.address order by address, piece; </p>
<p>　　157. 如何监控字典缓冲区？ </p>
<p>　　SELECT (SUM(PINS - RELOADS)) / SUM(PINS) "LIB CACHE" FROM V$LIBRARYCACHE; <br>　　SELECT (SUM(GETS - GETMISSES - USAGE - FIXED)) / SUM(GETS) "ROW CACHE" 　　FROM　V$ROWCACHE; <br>　　SELECT SUM(PINS) "EXECUTIONS", SUM(RELOADS) "CACHE MISSES WHILE EXECUTING" 　　FROM　V$LIBRARYCACHE; <br>　　后者除以前者,此比率小于1%,接近0%为好。<br>　　SELECT SUM(GETS) "DICTIONARY GETS",SUM(GETMISSES) "DICTIONARY CACHE GET MISSES" <br>　　FROM V$ROWCACHE </p>
<p>　　158. 监控 MTS </p>
<p>　　select busy/(busy+idle) "shared servers busy" from v$dispatcher; <br>　　此值大于0.5时，参数需加大 <br>　　select sum(wait)/sum(totalq) "dispatcher waits" from v$queue 　　where　type='dispatcher'; <br>　　select count(*) from v$dispatcher; <br>　　select servers_highwater from v$mts; <br>　　servers_highwater接近mts_max_servers时，参数需加大 </p>
<p>　　159. 如何知道当前用户的ID号? </p>
<p>　　SQL&gt;SHOW USER; <br>　　OR <br>　　SQL&gt;select user from dual; </p>
<p>　　160. 如何查看碎片程度高的表? </p>
<p>　　SELECT segment_name table_name , COUNT(*) extents <br>　　FROM dba_segments <br>　　WHERE owner NOT IN ('SYS', 'SYSTEM')<br>　　GROUP BY segment_name <br>　　HAVING COUNT(*) = (SELECT MAX( COUNT(*) ) FROM dba_segments <br>　　GROUP BY　segment_name); </p>
<p>　　161. 如何知道表在表空间中的存储情况? </p>
<p>　　select segment_name,sum(bytes),count(*) ext_quan from dba_extents<br>　　where tablespace_name='&amp;tablespace_name' and segment_type='TABLE' <br>　　group by　tablespace_name,segment_name; </p>
<p>　　162. 如何知道索引在表空间中的存储情况? </p>
<p>　　select segment_name,count(*) from dba_extents <br>　　where segment_type='INDEX' and　owner='&amp;owner' <br>　　group by segment_name; </p>
<p>　　163、如何知道使用CPU多的用户session? </p>
<p>　　11是cpu used by this session<br>　　select a.sid,spid,status,substr(a.program,1,40) prog,a.terminal,osuser,value/60/100 value <br>　　from v$session a,v$process b,v$sesstat c <br>　　where c.statistic#=11 and c.sid=a.sid and a.paddr=b.addr <br>　　order by value desc; </p>
<p>　　164. 如何知道监听器日志文件? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/NETWORK/LOG/LISTENER.LOG </p>
<p>　　165. 如何知道监听器参数文件? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/NETWORK/ADMIN/LISTENER.ORA </p>
<p>　　166. 如何知道TNS 连接文件? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/NETWORK/ADMIN/TNSNAMES.ORA </p>
<p>　　167. 如何知道Sql*Net 环境文件? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/NETWORK/ADMIN/SQLNET.ORA </p>
<p>　　168. 如何知道警告日志文件? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/ADMIN/SID/BDUMP/SIDALRT.LOG </p>
<p>　　169. 如何知道基本结构? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/RDBMS/ADMIN/STANDARD.SQL </p>
<p>　　170. 如何知道建立数据字典视图? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/RDBMS/ADMIN/CATALOG.SQL </p>
<p>　　171. 如何知道建立审计用数据字典视图? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/RDBMS/ADMIN/CATAUDIT.SQL </p>
<p>　　172. 如何知道建立快照用数据字典视图? </p>
<p>　　以8I为例 <br>　　$ORACLE_HOME/RDBMS/ADMIN/CATSNAP.SQL</p>
<p>-----------------------------------------------------------------------------------------</p>
<p>本讲主要讲的是SQL语句的优化方法! 主要基于ORACLE9I的.<br>　　173. /*+ALL_ROWS*/</p>
<p>　　表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化.例如:<br>　　SELECT /*+ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP'; <br>　　174. /*+FIRST_ROWS*/</p>
<p>　　表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化.例如:<br>　　SELECT /*+FIRST_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='CCBZZP';</p>
<p>　　175. /*+CHOOSE*/</p>
<p>　　表明如果数据字典中有访问表的统计信息,将基于开销的优化方法,并获得最佳的吞吐量;表明如果数据字典中没有访问表的统计信息,将基于规则开销的优化方法;例如:<br>　　SELECT /*+CHOOSE*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS <br>　　WHERE EMP_NO='CCBZZP';</p>
<p>　　176. /*+RULE*/</p>
<p>　　表明对语句块选择基于规则的优化方法.例如:<br>　　SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS <br>　　WHERE EMP_NO='CCBZZP'; </p>
<p>　　177. /*+FULL(TABLE)*/</p>
<p>　　表明对表选择全局扫描的方法.例如:<br>　　SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A <br>　　WHERE EMP_NO='CCBZZP';</p>
<p>　　178. /*+ROWID(TABLE)*/</p>
<p>　　提示明确表明对指定表根据ROWID进行访问.例如:<br>　　SELECT /*+ROWID(BSEMPMS)*/ * FROM BSEMPMS <br>　　WHERE ROWID&gt;='AAAAAAAAAAAAAA'<br>　　AND EMP_NO='CCBZZP';</p>
<p>　　179. /*+CLUSTER(TABLE)*/ </p>
<p>　　提示明确表明对指定表选择簇扫描的访问方法,它只对簇对象有效.例如:<br>　　SELECT /*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS<br>　　WHERE DPT_NO='TEC304' <br>　　AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;</p>
<p>　　180. /*+INDEX(TABLE INDEX_NAME)*/</p>
<p>　　表明对表选择索引的扫描方法.例如:<br>　　SELECT /*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ <br>　　FROM BSEMPMS WHERE SEX='M';</p>
<p>　　181. /*+INDEX_ASC(TABLE INDEX_NAME)*/</p>
<p>　　表明对表选择索引升序的扫描方法.例如:<br>　　SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS <br>　　WHERE DPT_NO='CCBZZP';</p>
<p>　　182. /*+INDEX_COMBINE*/</p>
<p>　　为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合方式.例如:<br>　　SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/ * FROM BSEMPMS<br>　　WHERE SAL&lt;5000000 AND HIREDATE&lt;SYSDATE;</p>
<p>　　183. /*+INDEX_JOIN(TABLE INDEX_NAME)*/</p>
<p>　　提示明确命令优化器使用索引作为访问路径.例如:<br>　　SELECT /*+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)*/ SAL,HIREDATE<br>　　FROM BSEMPMS WHERE SAL&lt;60000;</p>
<p>　　184. /*+INDEX_DESC(TABLE INDEX_NAME)*/</p>
<p>　　表明对表选择索引降序的扫描方法.例如:<br>　　SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS <br>　　WHERE DPT_NO='CCBZZP';</p>
<p>　　185. /*+INDEX_FFS(TABLE INDEX_NAME)*/</p>
<p>　　对指定的表执行快速全索引扫描,而不是全表扫描的办法.例如:<br>　　SELECT /*+INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305';</p>
<p>　　186. /*+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,...*/<br>　　提示明确进行执行规划的选择,将几个单列索引的扫描合起来.例如:<br>　　SELECT /*+INDEX_FFS(BSEMPMS IN_DPTNO,IN_EMPNO,IN_SEX)*/ * FROM BSEMPMS <br>　　WHERE EMP_NO='CCBZZP' AND DPT_NO='TDC306';</p>
<p>　　187. /*+USE_CONCAT*/</p>
<p>　　对查询中的WHERE后面的OR条件进行转换为UNION ALL的组合查询.例如:<br>　　SELECT /*+USE_CONCAT*/ * FROM BSEMPMS <br>　　WHERE DPT_NO='TDC506' AND SEX='M';</p>
<p>　　188. /*+NO_EXPAND*/</p>
<p>　　对于WHERE后面的OR 或者IN-LIST的查询语句,NO_EXPAND将阻止其基于优化器对其进行扩展.例如:<br>　　SELECT /*+NO_EXPAND*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';</p>
<p>　　189. /*+NOWRITE*/</p>
<p>　　禁止对查询块的查询重写操作.</p>
<p>　　190. /*+REWRITE*/</p>
<p>　　可以将视图作为参数.</p>
<p>　　191. /*+MERGE(TABLE)*/</p>
<p>　　能够对视图的各个查询进行相应的合并.例如:<br>　　SELECT /*+MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO <br>　　FROM BSEMPMS A (SELET DPT_NO,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V <br>　　WHERE A.DPT_NO=V.DPT_NO<br>　　AND A.SAL&gt;V.AVG_SAL;</p>
<p>　　192. /*+NO_MERGE(TABLE)*/</p>
<p>　　对于有可合并的视图不再合并.例如:<br>　　SELECT /*+NO_MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO <br>　　FROM BSEMPMS A (SELET DPT_NO,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V <br>　　WHERE A.DPT_NO=V.DPT_NO<br>　　AND A.SAL&gt;V.AVG_SAL;</p>
<p>　　193. /*+ORDERED*/</p>
<p>　　根据表出现在FROM中的顺序,ORDERED使ORACLE依此顺序对其连接.例如:<br>　　SELECT /*+ORDERED*/ A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C<br>　　WHERE A.COL1=B.COL1 AND B.COL1=C.COL1;</p>
<p>　　194. /*+USE_NL(TABLE)*/</p>
<p>　　将指定表与嵌套的连接的行源进行连接,并把指定表作为内部表.例如:<br>　　SELECT /*+ORDERED USE_NL(BSEMPMS)*/ BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM 　　FROM BSEMPMS,BSDPTMS <br>　　WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;</p>
<p>　　195. /*+USE_MERGE(TABLE)*/</p>
<p>　　将指定的表与其他行源通过合并排序连接方式连接起来.例如:<br>　　SELECT /*+USE_MERGE(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS <br>　　WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;</p>
<p>　　196. /*+USE_HASH(TABLE)*/</p>
<p>　　将指定的表与其他行源通过哈希连接方式连接起来.例如:<br>　　SELECT /*+USE_HASH(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS <br>　　WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;</p>
<p>　　197. /*+DRIVING_SITE(TABLE)*/</p>
<p>　　强制与ORACLE所选择的位置不同的表进行查询执行.例如:<br>　　SELECT /*+DRIVING_SITE(DEPT)*/ * FROM BSEMPMS,DEPT@BSDPTMS <br>　　WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;</p>
<p>　　198. /*+LEADING(TABLE)*/</p>
<p>　　将指定的表作为连接次序中的首表.</p>
<p>　　199. /*+CACHE(TABLE)*/</p>
<p>　　当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端。例如:<br>　　SELECT /*+FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;</p>
<p>　　200. /*+NOCACHE(TABLE)*/</p>
<p>　　当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端。例如:<br>　　SELECT /*+FULL(BSEMPMS) NOCAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;</p>
<p>　　201. /*+APPEND*/</p>
<p>　　直接插入到表的最后,可以提高速度.<br>　　insert /*+append*/ into test1 select * from test4 ;</p>
<p>　　202. /*+NOAPPEND*/</p>
<p>　　通过在插入语句生存期内停止并行模式来启动常规插入.<br>　　insert /*+noappend*/ into test1 select * from test4 ;</p>
<p>-----------------------------------------------------------------------------------------</p>
<p>ORACLE內部函數篇<br>　　203. 如何得到字符串的第一個字符的ASCII值?</p>
<p>　　ASCII(CHAR)<br>　　SELECT ASCII('ABCDE') FROM DUAL;<br>　　結果: 65 <br>　　204. 如何得到數值N指定的字符?</p>
<p>　　CHR(N)<br>　　SELECT CHR(68) FROM DUAL;<br>　　結果: D</p>
<p>　　205. 如何連接兩個字符串?</p>
<p>　　CONCAT(CHAR1,CHAR2)<br>　　SELECT CONCAT('ABC','DEFGH') FROM DUAL;<br>　　結果: 'ABCDEFGH'</p>
<p>　　206. 如何將列中的數值代替為字符串?</p>
<p>　　DECODE(CHAR,N1,CHAR1,N2,CHAR2...)<br>　　SELECT DECODE(DAY,1,'SUN',2,'MON') FROM DUAL;</p>
<p>　　207. INITCAP(CHAR)</p>
<p>　　將字符串CHAR的第一個字符為大寫,其余為小寫.<br>　　SELECT INITCAP('ABCDE') FROM DUAL;</p>
<p>　　208. LENGTH(CHAR)</p>
<p>　　取一字符串CHAR的長度.<br>　　SELECT LENGTH('ABCDE') FROM DUAL;</p>
<p>　　209. LOWER(CHAR)</p>
<p>　　將字符串CHAR全部變為小寫.<br>　　SELECT LOWER('ABCDE') FROM DUAL;</p>
<p>　　210. LPAD(CHAR1,N,CHAR2)</p>
<p>　　用字符串CHAR2包括的字符左填CHAR1,使其長度為N.<br>　　SELECT LPAD('ABCDEFG',10'123') FROM DUAL;<br>　　結果: '123ABCDEFG'</p>
<p>　　211. LTRIM(CHAR,SET)</p>
<p>　　從字符串CHAR的左邊移去字符串SET中的字符,直到第一個不是SET中的字符為止.<br>　　SELECT ('CDEFG','CD') FROM DUAL;<br>　　結果: 'EFG'</p>
<p>　　212. NLS_INITCAP(CHAR)</p>
<p>　　取字符CHAR的第一個字符大寫,其余字符為小寫.<br>　　SELECT NLS_INITCAP('ABCDE') FROM DUAL;</p>
<p>　　213. NLS_LOWER(CHAR)</p>
<p>　　將字符串CHAR包括的字符全部小寫.<br>　　SELECT NLS_LOWER('AAAA') FROM DUAL;</p>
<p>　　214. NLS_UPPER(CHAR)</p>
<p>　　將字符串CHAR包括的字符全部大寫.<br>　　SELECT NLS_UPPER('AAAA') FROM DUAL;</p>
<p>　　215. REPLACE(CHAR1,CHAR2,CHAR3)</p>
<p>　　用字符串CHAR3代替每一個列值為CHAR2的列,其結果放在CHAR1中.<br>　　SELECT REPLACE(EMP_NO,'123','456') FROM DUAL;</p>
<p>　　216. RPAD(CHAR1,N,CHAR2)</p>
<p>　　用字符串CHAR2右填字符串CHAR1,使其長度為N.<br>　　SELECT RPAD('234',8,'0') FROM DUAL;</p>
<p>　　217. RTRIM(CHAR,SET)</p>
<p>　　移去字符串CHAR右邊的字符串SET中的字符,直到最后一個不是SET中的字符為止.<br>　　SELECT RTRIM('ABCDE','DE') FROM DUAL;</p>
<p>　　218. SUBSTR(CHAR,M,N)</p>
<p>　　得到字符串CHAR從M處開始的N個字符. 雙字節字符,一個漢字為一個字符的.<br>　　SELECT SUBSTR('ABCDE',2,3) FROM DUAL;</p>
<p>　　219. SUBSTRB(CHAR,M,N)</p>
<p>　　得到字符串CHAR從M處開始的N個字符. 雙字節字符,一個漢字為二個字符的.<br>　　SELECT SUBSTRB('ABCDE',2,3) FROM DUAL;</p>
<p>　　220. TRANSLATE(CHAR1,CHAR2,CHAR3)</p>
<p>　　將CHAR1中的CHAR2的部分用CHAR3代替.<br>　　SELECT TRANSLATE('ABCDEFGH','DE','MN') FROM DUAL;</p>
<p>　　221. UPPER(CHAR)</p>
<p>　　將字符串CHAR全部為大寫.</p>
<p>　　222. ADD_MONTHS(D,N)</p>
<p>　　將N個月增加到D日期.<br>　　SELECT ADD_MONTHS(SYSDATE,5) FROM DUAL;</p>
<p>　　223. LAST_DAY(D)</p>
<p>　　得到包含D日期的月份的最后的一天的日期.<br>　　SELECT LAST_DAY(SYSDATE) FROM DUAL;</p>
<p>　　224. MONTH_BETWEEN(D1,D2)</p>
<p>　　得到兩個日期之間的月數.<br>　　SELECT MONTH_BETWEEN(D1,D2) FROM DUAL;</p>
<p>　　225. NEXT_DAY(D,CHAR)</p>
<p>　　得到比日期D晚的由CHAR命名的第一個周日的日期.<br>　　SELECT NEXT_DAY(TO_DATE('2003/09/20'),'SATDAY') FROM DUAL;</p>
<p>　　226. ROUNT(D,FMT)</p>
<p>　　得到按指定的模式FMT舍入到的最進的日期.<br>　　SELECT ROUNT('2003/09/20',MONTH) FROM DUAL;</p>
<p>　　227. SYSDATE</p>
<p>　　得到當前系統的日期和時間.<br>　　SELECT SYSDATE FROM DUAL;</p>
<p>　　228. TO_CHAR(D,FMT)</p>
<p>　　將日期D轉換為FMT的字符串.<br>　　SELECT TO_CHAR(SYSDATE,'YYYY/MM/DD') FROM DUAL;</p>
<p>　　229. TO_DATE(CHAR,FMT)</p>
<p>　　將字符串CHAR按FMT的格式轉換為日期.<br>　　SELECT TO_DATE('2003/09/20','YYYY/MM/DD') FROM DUAL;</p>
<p>　　230. ABS(N)</p>
<p>　　得到N的絕對值.<br>　　SELECT ABS(-6) FROM DUAL;</p>
<p>　　231. CEIL(N)</p>
<p>　　得到大于或等于N的最大整數.<br>　　SELECT CEIL(5.6) FROM DUAL;</p>
<p>　　232. COS(N)</p>
<p>　　得到N的余弦值.<br>　　SELECT COS(1) FROM DUAL;</p>
<p>　　233. SIN(N)</p>
<p>　　得到N的正弦值.<br>　　SELECT SIN(1) FROM DUAL;</p>
<p>　　234. COSH(N)</p>
<p>　　得到N的雙曲余弦值.<br>　　SELECT COSH(1) FROM DUAL;</p>
<p>　　235. EXP(N)</p>
<p>　　得到N的E的N次冪.<br>　　SELECT EXP(1) FROM DUAL;</p>
<p>　　236. FLOOR(N)</p>
<p>　　得到小于或等于N的最小整數.<br>　　SELECT FLOOR(5.6) FROM DUAL;</p>
<p>　　237. LN(N)</p>
<p>　　得到N的自然對數.<br>　　SELECT LN(1) FROM DUAL;</p>
<p>　　238. LOG(M,N)</p>
<p>　　得到以M為底N的對數.<br>　　SELECT LOG(2,8) FROM DUAL;</p>
<p>　　239. MOD(M,N)</p>
<p>　　得到M除以N的余數.<br>　　SELECT MOD(100,7) FROM DUAL;</p>
<p>　　240. POWER(M,N)</p>
<p>　　得到M的N冪.<br>　　SELECT POWER(4,3) FROM DUAL;</p>
<p>　　241. ROUND(N,M)</p>
<p>　　將N舍入到小數點后M位.<br>　　SELECT (78.87653,2) FROM DUAL;</p>
<p>　　242. SIGN(N)</p>
<p>　　當N&lt;0時,得到-1;<br>　　當N&gt;0時,得到1;<br>　　當N=0時,得到0;<br>　　SELECT SIGN(99) FROM DUAL;</p>
<p>　　243. SINH(N)</p>
<p>　　得到N的雙曲正弦值.<br>　　SELECT SINH(1) FROM DUAL;</p>
<p>　　244. SORT(N)</p>
<p>　　得到N的平方根,N&gt;=0<br>　　SELECT SORT(9) FROM DUAL;</p>
<p>　　245. TAN(N)</p>
<p>　　得到N的正切值.<br>　　SELECT TAN(0) FROM DUAL;</p>
<p>　　246. TANH(N)</p>
<p>　　得到N的雙曲正切值.<br>　　SELECT TANH(0) FROM DUAL;</p>
<p>　　247. TRUNC(N,M)</p>
<p>　　得到在M位截斷的N的值.<br>　　SELECT TRUNC(7.7788,2) FROM DUAL;</p>
<p>　　248. COUNT()</p>
<p>　　計算滿足條件的記錄數.<br>　　SELECT COUNT(*) FROM TABLE1 WHERE COL1='AAA';</p>
<p>　　249. MAX()</p>
<p>　　對指定的列求最大值.<br>　　SELECT MAX(COL1) FROM TABLE1;</p>
<p>　　250. MIN()</p>
<p>　　對指定的列求最小值.<br>　　SELECT MIN(COL1) FROM TABLE1;</p>
<p>　　251. AVG()</p>
<p>　　對指定的列求平均值.<br>　　SELECT AVG(COL1) FROM TABLE1;</p>
<p>　　252. SUM()</p>
<p>　　計算列的和.<br>　　SELECT SUM(COL1) FROM DUAL;</p>
<p>　　253. TO_NUMBER(CHAR) </p>
<p>　　將字符轉換為數值.<br>　　SELECT TO_NUMBER('999') FROM DUAL;</p>
<p>-----------------------------------------------------------------------------------------</p>
<p>ORACLE 内部函数篇<br>　　254. CHARTOROWID(CHAR) <br>　　将包含外部语法 ROWID 的 CHAR 或 VARCHAR2 数值转换为内部的二进制语法 , 参数 CHAR 必须是包含外部语法的 ROWID 的 18 字符的字符串 .<br>　　SELECT NAME FROM BSEMPMS WHERE ROWID=CHARTOROWID('AAAAfZAABAAACp8AAO');<br>　　NAME : LEIXUE </p>
<p>　　255. CONVERT(CHAR,DEST_CHAR_SET,SOURCE_CHAR_SET) </p>
<p>　　CONVERT 将字符串 CHAR 中的字符从 SOURCE_CHAR_SET 标识的字符集转换为由 DEST_CHAR_SET 标识的字符集<br>　　SELECT CONVERT('GroB','US7ASCII','WE8HP') 'CONVERSION' FROM PUBS;<br>　　CONVERSION: Gross </p>
<p>　　256. HEXTORAW(CHAR) </p>
<p>　　将包含十六进制的 CHAR 转换为一个 RAW 数值 .<br>　　INSERT INTO BSEMPMS(RAW_COLUMN) SELECT HEXTORAW('7D') FROM TEST; </p>
<p>　　257. RAWTOHEX(RAW) </p>
<p>　　将 RAW 数值转换为一个包含十六进制的 CHAR 值 .<br>　　SELECT RAWTOHEX(RAW_COLUMN) 'CONVERSION' FROM BSEMPMS;<br>　　CONVERSION: 7D </p>
<p>　　258. ROWIDTOCHAR(ROWID)</p>
<p>　　将一个 ROWID 数值转换为 VARCHAR2 数据类型 .<br>　　SELECT ROWID FROM BSEMPMS WHERE ROWIDTOCHAR(ROWID) LIKE '%BR1AAB%'; </p>
<p>　　259. TO_MULTI_BYTE(CHAR) </p>
<p>　　将 CHAR 中的单字节转换为等价的多字节字符 .<br>　　SELECT TO_MULTI_BYTE('ASFDFD') FROM TEST; </p>
<p>　　260. TO_SINGLE_BYTE(CHAR) </p>
<p>　　将 CHAR 中的多字节转换为等价的单字节字符 .<br>　　SELECT TO_SINGLE_BYTE('ASFDFD') FROM TEST; </p>
<p>　　261. TRANSLATE USING(TEXT USING {CHAR_CS|NCHAR_CS}) </p>
<p>　　将文本 TEXT 按照指定的转换方式转换成数据库字符集和民族字符集 .其中 TEXT 是待转换的 .<br>　　USING CHAR_CS 参数转换 TEXT 为数据库字符集 , 输出数据类型是 VARCHAR2.<br>　　USING NCHAR_CS 参数转换 TEXT 为数据库字符集 , 输出数据类型是 NVARCHAR2.<br>　　CREATE TABLE TEST(CHAR_COL CHAR(20),NCHAR_COL NCHAR(20));<br>　　INSERT INTO TEST VALUES('HI,N'BYE');<br>　　SELECT * FROM TEST; </p>
<p>　　262. DUMP(EXPR,RETURN_FORMAT,START_POSITION,LENGTH) </p>
<p>　　返回一个包含数据类型代码 , 字节长度等内部表示信息的 VARCHAR2 值 . 返回结果是当前数据库字符集 , 数据类型按照下面规定的内部数据类型的编码作为一个数字进行返回 :<br>　　代　码 　　　数据类型<br>　　　0 　　　　 VARCHAR2<br>　　　1 　　　　 NUMBER<br>　　　8 　　　　 LONG<br>　　　12 　　　　DATE<br>　　　23 　　　　RAW<br>　　　24 　　　　LONG RAW<br>　　　69 　　　　ROWID<br>　　　96 　　　　CHAR<br>　　　106 　　　 MSSLABEL </p>
<p>　　参数 RETUEN_FORMAT 指定按照下面的基数表示返回的数值 .<br>　　RETURN_FORMAT 　　RESULT<br>　　　　8 　　　　　　8 进制<br>　　　　10 　　　　　10 进制<br>　　　　16 　　　　　16 进制<br>　　　　17 　　　　　单字符表示 </p>
<p>　　如果参数 RETURN_FORMAT 没有指定 , 则按十进制表示返回 .<br>　　如果参数 START_POSITION 和 LENGTH 被指定 , 则从 START_POSITION 开始的长为 LENGTH 的字节将被返回 , 缺省是返回整数表示 .<br>　　SELECT DUMP('ABC',1016) FROM TEST;<br>　　select dump(ename,8,3,2) 'example' from emp where name='ccbzzp'; </p>
<p>　　263. empty_b|clob() </p>
<p>　　返回一个空的 LOB 定位符 , 用在初始化 LOB 变量 , 或用在 INSERT 及 UPDATE 声明去初始化 LOB 列或将其属性置为空 .<br>　　INSERT INTO TABLE1 VALUES(EMPTY_BLOB());<br>　　UPDATE TABLE1 SET CLOB_COL=EMPTY_BLOB(); </p>
<p>　　264. BFILENAME('DIRECTORY','FILENAME') </p>
<p>　　返回一个 BFILE 定位符 , 相关的二进制 LOB 物理文件在服务器的文件系统上 . 目录 DIRECTORY 是指在服务器的文件系统上实际搜索路径全名的别名 . FILENAME 是指服务器的文件系统的文件名 .<br>　　INSERT INTO FILE_TAB VALUES(BFILENAME('LOB_DIR','IMAGE1.GIF')); </p>
<p>　　265. GREATEST(EXPR,EXPR,...) </p>
<p>　　GREATEST 返回参数的最大值 .<br>　　SELECT GREATEST('HARRY','HARRIOT','HAROLD') 'SAMPLE' FROM TABLE1; </p>
<p>　　266. LEAST(EXPR,EXPR,...) </p>
<p>　　LEAST 返回参数的最小值 .<br>　　SELECT LEAST('HARRY','HARRIOT','HAROLD') 'SAMPLE' FROM TABLE1; </p>
<p>　　267. NLS_CHARSET_DECL_LEN(BYTECNT,CSID) </p>
<p>　　返回一个 NCHAR 列的宽度 .<br>　　SELECT NLS_CHARSET_DECL_LEN(200,NLS_CHARSET_ID('JA16EEFDFDF')) FROM TABLE1; </p>
<p>　　268. NLS_CHARSET_ID(TEXT) </p>
<p>　　返回相应于 NLS 字符集名字的 NLS 字符集 ID 数 .<br>　　SELECT NLS_CHARSET_D('JADFDFFDF') FROM TABLE1; </p>
<p>　　269. NLS_CHARSET_NAME(N) </p>
<p>　　返回相应于 ID 数 N 的 NLS 字符集名称 .<br>　　SELECT NLS_CHARSET_NAME(2) FROM TABLE1; </p>
<p>　　270. NVL(EXPR1,EXPR2) </p>
<p>　　若 EXPR1 是 NULL, 则返回 EXPR2, 否则返回 EXPR1.<br>　　SELECT NAME,NVL(TO_CHAR(COMM),'NOT APPLICATION') FROM TABLE1; </p>
<p>　　271. UID </p>
<p>　　返回唯一标识当前数据库用户的整数 .<br>　　SELECT UID FROM TABLE1; </p>
<p>　　272. USER </p>
<p>　　用 VARCHAR2 数据类型返回当前 ORACLE 用户的名称 .<br>　　SELECT USER,UID FROM TABLE1; </p>
<p>　　273. USERENV(OPTION) </p>
<p>　　返回当前的会话信息 .<br>　　OPTION='ISDBA' 若当前是 DBA 角色 , 则为 TRUE, 否则 FALSE.<br>　　OPTION='LANGUAGE' 返回数据库的字符集 .<br>　　OPTION='SESSIONID' 为当前会话标识符 .<br>　　OPTION='ENTRYID' 返回可审计的会话标识符 .<br>　　OPTION='LANG' 返回会话语言名称的 ISO 简记 .<br>　　OPTION='INSTANCE' 返回当前的实例 .<br>　　SELECT USERENV('LANGUAGE') FROM DUAL; </p>
<p>　　274. VSIZE(EXPR) </p>
<p>　　返回 EXPR 内部表示的字节数 .<br>　　SELECT NAME,VSIZE(NAME) FROM TABLE1; </p>
<p>　　275. DEREF(E) </p>
<p>　　返回参数 E 的对象引用 .<br>　　SELECT DEREF(C2) FROM TABLE1; </p>
<p>　　276. REFTOHEX(R) </p>
<p>　　将参数 R 转换为 16 进制 .<br>　　SELECT REFTOHEX(C2) FROM TABLE1; </p>
<p>　　277. MAKE_REF(TABLE,KEY,KEY...) </p>
<p>　　通过把给定的键作为主键来创建给定视图对象中一行的引用 .<br>　　CREATE TYPE T1 AS OBJECT(A NUMBER,B NUMBER);<br>　　CREATE TABLE TB1(C1 NUMBER,C2 NUMBER,PRIMARY KEY(C1,C2));<br>　　CREATE VIEW V1 OF T1 WITH OBJECT OID(A,B) AS SELECT * FROM TB1;<br>　　SELECT MAKE_REF(V1,1,3) FROM PUBS; </p>
<p>　　278. STDDEV(DISTINCT|ALL X) </p>
<p>　　STDDEV 给出一组行值的标准差 .<br>　　SELECT STDDEV(SALARY) AS EXAMPLE FROM EMPLOYEE; </p>
<p>　　279. VARIANCE(DISTINCT|ALL X) </p>
<p>　　VARIANCE 返回一组行中所有 VALUE 的方差 .<br>　　SELECT VARIANCE(SALARY) AS EXAMPLE FROM EMPLOYEE;</p>
<p>-----------------------------------------------------------------------------------------</p>
<p>　9I 管理的 V$ 视图<br>　　280. V$ACCESS <br>　　显示当前被锁定的数据库中的对象及正在访问他们的会话。</p>
<p>　　281. V$ACTIVE_INSTANCES </p>
<p>　　为当前安装的数据库中出现的所有实例建立从实例名到实例号的映像。</p>
<p>　　282. V$ACTIVE_SESS_POOL_MTH </p>
<p>　　所有活动的会话池资源分配方法。</p>
<p>　　283. V$AQ </p>
<p>　　当前数据库中的队列的统计量。</p>
<p>　　284. V$ARCHIVE </p>
<p>　　归档所需的重做日志文件中的信息。</p>
<p>　　285. V$ARCHIVE_DEST </p>
<p>　　当前实例的所有归档日志目的文件及它们的当前值 , 模式 , 状态。</p>
<p>　　286. V$ARCHIVE_PROCESSES </p>
<p>　　为一个实例提供不同的 ARCH 进程状态的信息。</p>
<p>　　287. V$ARCHIVE_LOG </p>
<p>　　控制文件中的归档日志信息。</p>
<p>　　288. V$BACKUP </p>
<p>　　所有联机数据文件的备份状态。</p>
<p>　　289. V$BACKUP_ASYNC_IO </p>
<p>　　从控制文件中显示备份集的信息。</p>
<p>　　290. V$BACKUP_CORRUPTION </p>
<p>　　从控制文件中显示数据文件备份中有关损坏的信息。</p>
<p>　　291. V$BACKUP_DATAFILE </p>
<p>　　从控制文件中显示备份数据文件和备份控制文件的信息。</p>
<p>　　292. V$BACKUP_DEVICE </p>
<p>　　显示关于支持备份设备的信息。</p>
<p>　　293. V$BACKUP_PIECE </p>
<p>　　从控制文件中显示备份块的信息。</p>
<p>　　294. V$BACKUP_REDOLOG </p>
<p>　　从控制文件中显示关于备份集中归档日志的信息。</p>
<p>　　295. V$BACKUP_SET </p>
<p>　　从控制文件中显示备份集的信息。</p>
<p>　　296. V$BACKUP_SYNC_IO </p>
<p>　　从控制文件中显示备份集的信息。</p>
<p>　　297. V$BGPROCESS </p>
<p>　　描述后台进程。</p>
<p>　　298. V$BH </p>
<p>　　是 9I 的实时应用集群视图。为系统全局区中的每一个缓冲区给出了状态和探查次数。</p>
<p>　　299. V$BSP </p>
<p>　　显示用在缓存中块服务器后台进程上的统计信息。</p>
<p>　　300. V$BUFFER_POOL </p>
<p>　　显示实例缓冲池的信息。</p>
<p>　　301. V$BUFFER_POOL_STATISTICS </p>
<p>　　显示实例缓冲池的信息。</p>
<p>　　302. V$CACHE </p>
<p>　　包含当前实例的 SGA 中的每一个块的头部信息。</p>
<p>　　303. V$CACHE_LOCK </p>
<p>　　包含当前实例的 SGA 中的每一个块的头部信息和 V$CACHE 非常相似 ,除特使平台锁管理器标识符号不同外。</p>
<p>　　304. V$CACHE_TRANSFER </p>
<p>　　除了只显示那些被探查了至少一次的块的信息外 , 和 V$CACHE 功能相同。</p>
<p>　　305. V$CIRCUIT </p>
<p>　　包含关于虚电路的信息 , 是用户通过调度程序和服务器到数据库的所有连接。</p>
<p>　　306. V$CLASS_PING </p>
<p>　　显示每一个块类中被探查块的数目。</p>
<p>　　307. V$COMPATIBILITY </p>
<p>　　显示数据库实例使用的特征 , 可以阻止数据库回到早期的版本中去。</p>
<p>　　308. V$COMPATSEG </p>
<p>　　显示数据库实例使用的永久性特征 , 可以阻止数据库回到早期的版本中去。</p>
<p>　　309. V$CONTEXT </p>
<p>　　列出当前对话的设置属性。</p>
<p>　　310. V$CONTROLFILE </p>
<p>　　列出控制文件的名称。</p>
<p>　　311. V$CONTROLFILE_RECORD_SECTION </p>
<p>　　显示控制文件记录部分的信息。</p>
<p>　　312. V$COPY_CORRUPTION </p>
<p>　　显示控制文件中数据文件损坏的信息。</p>
<p>　　313. V$CR_BLOCK_SERVER </p>
<p>　　显示用在缓存中块服务器后台进程上的统计信息。</p>
<p>　　314. V$DATABASE </p>
<p>　　包含控制文件中数据库的信息。</p>
<p>　　315. V$DATAFILE </p>
<p>　　包含控制文件中数据库文件的信息。</p>
<p>　　316. V$DATAFILE_COPY </p>
<p>　　包含控制文件中数据库文件副本的信息。</p>
<p>　　317. V$DATAFILE_HEADER </p>
<p>　　显示数据文件头部的数据文件信息。</p>
<p>　　318. V$DB_CACHE_ADVICE </p>
<p>　　根据缓存的大小估计出物理读的数量。</p>
<p>　　319. V$DB_OBJECT_CACHE </p>
<p>　　缓存在库缓存中的数据库对象。</p>
<p>　　320. V$DB_PIPES </p>
<p>　　显示实例中的共享池当前描绘的管道。</p>
<p>　　321. V$DBFILE </p>
<p>　　列出组成数据库的所有数据文件。</p>
<p>　　322. V$DBLINK </p>
<p>　　查询会话所打开的所有数据库连接。</p>
<p>　　323. V$DELETED_OBJECT </p>
<p>　　显示控制文件中被删除归档日志。</p>
<p>　　324. V$DISPATCHER </p>
<p>　　提供调度进程的信息。</p>
<p>　　325. V$DISPATCHER_RATE </p>
<p>　　为调度进程提供优质提供速率统计量。</p>
<p>　　326. V$DLM_ALL_LOCKS </p>
<p>　　列出当前所有锁的信息。</p>
<p>　　327. V$DLM_CONVERT_LOCAL </p>
<p>　　本地锁转换操作所消耗的时间。</p>
<p>　　328. V$DLM_CONVERT_REMOTE </p>
<p>　　远程锁转换操作所消耗的时间。</p>
<p>　　329. V$DLM_LATCH </p>
<p>　　它是过时的 , 参见 V$LATCH </p>
<p>　　330. V$DLM_LOCKS </p>
<p>　　这些是锁管理器已知的被阻塞或阻塞其它对象的锁信息。</p>
<p>　　331. V$DLM_MISC </p>
<p>　　显示多种 DLM 统计量。</p>
<p>　　332. V$DLM_RESS </p>
<p>　　显示当前锁管理器已知的全部资源的信息。</p>
<p>　　333. V$ENABLEDPRIVE </p>
<p>　　显示被授予的特权。</p>
<p>　　334. V$ENQUEUE_LOCK </p>
<p>　　显示排队对象所拥有的全部锁。</p>
<p>　　335. V$EVENT_NAME </p>
<p>　　包含等待事件的信息。</p>
<p>　　336. V$EXECUTION </p>
<p>　　显示并行执行中的信息。</p>
<p>　　337. V$FALSE_PING </p>
<p>　　可能得到探查失败的缓冲区。</p>
<p>　　338. V$FAST_START_SERVERS </p>
<p>　　执行并行操作事务恢复的所有从属操作的信息。</p>
<p>　　339. V$FAST_START_TRANSACTIONS </p>
<p>　　恢复中的事务进展信息。</p>
<p>　　340. V$FILE_CACHE_TRANSFER </p>
<p>　　显示每个数据文件中探查的块的数量。</p>
<p>　　341. V$FILE_PING </p>
<p>　　显示每个数据文件被探查的块数目。</p>
<p>　　342. V$FILESTAT </p>
<p>　　包含文件关于读 / 写统计量信息。</p>
<p>　　343. V$FIXED_TABLE </p>
<p>　　显示数据库中所有动态性能表和视图及导出表。</p>
<p>　　344. V$FIXED_VIEW_DEFINITION </p>
<p>　　显示所有固定视图的定义。</p>
<p>　　345. V$GC_ELEMENTS_WITH_COLLISIONS </p>
<p>　　可以找到保护多缓存的锁。</p>
<p>　　346. V$GES_BLOCKING_ENQUEUE </p>
<p>　　这些是锁管理器已知的被阻塞或阻塞其它对象的锁信息。</p>
<p>　　347. V$GES_CONVERT_LOCAL </p>
<p>　　本地锁转换操作所消耗的时间。</p>
<p>　　348. V$GES_CONVERT_REMOTE </p>
<p>　　远程锁转换操作所消耗的时间。</p>
<p>　　349. V$GES_ENQUEUE </p>
<p>　　显示当前锁管理员知道的所有的锁。</p>
<p>　　350. V$GES_LATCH </p>
<p>　　参见 V$LATCH </p>
<p>　　351. V$GES_RESOURCE </p>
<p>　　显示当前锁管理器已知的全部资源的信息。</p>
<p>　　352. V$GES_STATISTICS </p>
<p>　　显示多种 DLM 统计量。</p>
<p>　　353. V$GLOBAL_BLOCKED_LOCKS </p>
<p>　　显示全局块锁。</p>
<p>　　354. V$GLOBAL_TRANSACTION </p>
<p>　　显示当前激活的全局事务的信息。</p>
<p>　　355. V$HS_AGENT </p>
<p>　　标识当前运行在一个给定的主机上的 HS 代理的集合。</p>
<p>　　356. V$HS_SESSION </p>
<p>　　ORACLE 服务器打开的 HS 会话集。</p>
<p>　　357. V$INDEXED_FIXED_COLUMN </p>
<p>　　显示建立索引的动态性能表中的列 (X$ 表 )。</p>
<p>　　358. V$INSTANCE </p>
<p>　　显示当前实例的状态。</p>
<p>　　359. V$INSTANCE_RECOVERY </p>
<p>　　用来监视执行用户指定恢复读次数的限制机制。</p>
<p>　　360. V$LATCH </p>
<p>　　为非双亲简易锁列出统计量。</p>
<p>　　361. V$LATCH_CHILDREN </p>
<p>　　关于子简易锁的统计量。</p>
<p>　　362. V$LATCH_MISSES </p>
<p>　　试图获得一个简易锁失败的统计量。</p>
<p>　　363. V$LATCH_PARENT </p>
<p>　　包含关于双亲简易锁的统计量。</p>
<p>　　364. V$LATCHHOLDER </p>
<p>　　当前简易锁持有者的信息。</p>
<p>　　365. V$LATCHNAME </p>
<p>　　包含关于显示在 V$LATCH 中的简易锁的解码简易锁名字的信息。</p>
<p>　　366. V$LIBRARYCACHE </p>
<p>　　关于高速缓存性能和活动的统计量。</p>
<p>　　367. V$LICENSE </p>
<p>　　许可证限制的信息。</p>
<p>　　368. V$LOADCSTAT </p>
<p>　　包含在一个直接装载执行过程中所编译的 SQL*LOADER 统计量。</p>
<p>　　369. V$LOCK </p>
<p>　　当前 ORACLE 所持有的锁。</p>
<p>　　370. V$LOCK_ACTIVITY </p>
<p>　　显示当前实例的 DLM 锁操作活动。</p>
<p>　　371. V$LOCK_ELEMENT </p>
<p>　　每一个被缓存使用的 PCM 锁在 V$LOCK_ELEMENTS 中都有一个条目。</p>
<p>　　372. V$LOCKED_OBJECT </p>
<p>　　列出每个事务所获得的全部锁。</p>
<p>　　373. V$LOCK_WITH_COLLISIONS </p>
<p>　　可以查询出保护多缓冲区的锁。</p>
<p>　　374. V$LOG </p>
<p>　　控制文件中日志文件的信息。</p>
<p>　　375. V$LOG_HISTORY </p>
<p>　　控制文件中日志文件的历史信息。</p>
<p>　　376. V$LOGFILE </p>
<p>　　包含重做日志文件的信息 . </p>
<p>　　377. V$LOGHIST </p>
<p>　　控制文件中日志文件的日志历史信息。</p>
<p>　　378. V$LOGMNR_CONTENTS </p>
<p>　　日志历史信息。</p>
<p>　　379. V$LOGMNR_DICTIONARY </p>
<p>　　日志历史信息。</p>
<p>　　380. V$LOGMNR_LOGS </p>
<p>　　日志信息。</p>
<p>　　381. V$LOGMNR_PARAMETERS </p>
<p>　　日志信息。</p>
<p>　　382. V$MTS </p>
<p>　　包含调节多线程的服务器的信息。</p>
<p>　　383. V$MYSTAT </p>
<p>　　当前会话的统计量。</p>
<p>　　384. V$NLS_PARAMETERS </p>
<p>　　当前 NLS 参数信息。</p>
<p>　　385. V$NLS_VALID_VALUES </p>
<p>　　列出所有 NLS 参数的有效值。</p>
<p>　　386. V$OBJECT_DEPENDENCY </p>
<p>　　能够通过当前装载在共享池中的包 , 过程或游标来决定依赖哪一个对象。</p>
<p>　　387. V$OBJECT_USAGE </p>
<p>　　来监视索引的使用。</p>
<p>　　388. V$OBSOLETE_PARAMETER </p>
<p>　　列出陈旧的参数。</p>
<p>　　389. V$OFFINE_RANGE </p>
<p>　　显示控制文件中数据文件的脱机信息。</p>
<p>　　390. V$OPEN_CURSOR </p>
<p>　　列出每一个会话当前打开的和解析的游标。</p>
<p>　　391. V$OPTION </p>
<p>　　列出 ORACLE 服务安装的状况。</p>
<p>　　392. V$PARALLEL_DEGREE_LIMIT_MTH </p>
<p>　　显示所有有效的并行度限制资源分配的方法。</p>
<p>　　393. V$PARAMETER </p>
<p>　　列出关于初始化参数的信息。</p>
<p>　　394. V$PARAMETER2 </p>
<p>　　列出了当前影响会话的参数和参数值。</p>
<p>　　395. V$PGASTAT </p>
<p>　　列出 ORACLE 内存使用统计。</p>
<p>　　396. V$PING </p>
<p>　　与 V$CACHE 一样。</p>
<p>　　397. V$PQ_SESSTAT </p>
<p>　　列出并行查询会话的统计信息。</p>
<p>　　398. V$PQ_SLAVE </p>
<p>　　一个实例上每个活动并行执行服务器的统计量。</p>
<p>　　399. V$PQ_SYSSTAT </p>
<p>　　列出并行查询的系统的统计量。<br></p>
<img src ="http://www.blogjava.net/franlk/aggbug/128025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-07-04 09:50 <a href="http://www.blogjava.net/franlk/articles/128025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]SQL Server和Oracle的常用函数对比</title><link>http://www.blogjava.net/franlk/articles/128020.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Wed, 04 Jul 2007 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/128020.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/128020.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/128020.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/128020.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/128020.html</trackback:ping><description><![CDATA[<p><br>摘录地址:http://www.ccrun.com/article.asp?i=996&amp;d=dwn1rn<br><br>---------数学函数</p>
<p>1.绝对值<br>S:select abs(-1) value<br>O:select abs(-1) value from dual</p>
<p>2.取整(大)<br>S:select ceiling(-1.001) value<br>O:select ceil(-1.001) value from dual</p>
<p>3.取整（小）<br>S:select floor(-1.001) value<br>O:select floor(-1.001) value from dual</p>
<p>4.取整（截取）<br>S:select cast(-1.002 as int) value<br>O:select trunc(-1.002) value from dual</p>
<p>5.四舍五入<br>S:select round(1.23456,4) value 1.23460<br>O:select round(1.23456,4) value from dual 1.2346</p>
<p>6.e为底的幂<br>S:select Exp(1) value 2.7182818284590451<br>O:select Exp(1) value from dual 2.71828182</p>
<p>7.取e为底的对数<br>S:select log(2.7182818284590451) value 1<br>O:select ln(2.7182818284590451) value from dual; 1</p>
<p>8.取10为底对数<br>S:select log10(10) value 1<br>O:select log(10,10) value from dual; 1</p>
<p>9.取平方<br>S:select SQUARE(4) value 16<br>O:select power(4,2) value from dual 16</p>
<p>10.取平方根<br>S:select SQRT(4) value 2<br>O:select SQRT(4) value from dual 2</p>
<p>11.求任意数为底的幂<br>S:select power(3,4) value 81<br>O:select power(3,4) value from dual 81</p>
<p>12.取随机数<br>S:select rand() value<br>O:select sys.dbms_random.value(0,1) value from dual;</p>
<p>13.取符号<br>S:select sign(-8) value -1<br>O:select sign(-8) value from dual -1</p>
<p>----------三角函数相关</p>
<p>14.圆周率<br>S:SELECT PI() value 3.1415926535897931<br>O:不知道</p>
<p>15.sin,cos,tan 参数都以弧度为单位<br>例如：select sin(PI()/2) value 得到1（SQLServer）</p>
<p>16.Asin,Acos,Atan,Atan2 返回弧度</p>
<p>17.弧度角度互换(SQLServer，Oracle不知道)<br>DEGREES：弧度-〉角度<br>RADIANS：角度-〉弧度</p>
<p>---------数值间比较</p>
<p>18. 求集合最大值<br>S:select max(value) value from<br>(select 1 value<br>union<br>select -2 value<br>union<br>select 4 value<br>union<br>select 3 value)a</p>
<p>O:select greatest(1,-2,4,3) value from dual</p>
<p>19. 求集合最小值<br>S:select min(value) value from<br>(select 1 value<br>union<br>select -2 value<br>union<br>select 4 value<br>union<br>select 3 value)a</p>
<p>O:select least(1,-2,4,3) value from dual</p>
<p>20.如何处理null值(F2中的null以10代替)<br>S:select F1,IsNull(F2,10) value from Tbl<br>O:select F1,nvl(F2,10) value from Tbl</p>
<p>--------字符串函数</p>
<p>21.求字符序号<br>S:select ascii('a') value<br>O:select ascii('a') value from dual</p>
<p>22.从序号求字符<br>S:select char(97) value<br>O:select chr(97) value from dual</p>
<p>23.连接<br>S:select '11'+'22'+'33' value<br>O:select CONCAT('11','22')||33 value from dual</p>
<p>23.子串位置 --返回3<br>S:select CHARINDEX('s','sdsq',2) value<br>O:select INSTR('sdsq','s',2) value from dual</p>
<p>23.模糊子串的位置 --返回2,参数去掉中间%则返回7<br>// 本文转自 C++Builder 研究 - <a href="http://www.ccrun.com/article.asp?i=996&amp;d=dwn1rn">http://www.ccrun.com/article.asp?i=996&amp;d=dwn1rn</a><br>S:select patindex('%d%q%','sdsfasdqe') value<br>O:oracle没发现，但是instr可以通过第四个参数控制出现次数<br>select INSTR('sdsfasdqe','sd',1,2) value from dual 返回6</p>
<p>24.求子串<br>S:select substring('abcd',2,2) value<br>O:select substr('abcd',2,2) value from dual</p>
<p>25.子串代替 返回aijklmnef<br>S:SELECT STUFF('abcdef', 2, 3, 'ijklmn') value<br>O:SELECT Replace('abcdef', 'bcd', 'ijklmn') value from dual</p>
<p>26.子串全部替换<br>S:Replace<br>O:select Translate('fasdbfasegas','fa','我' ) value from dual</p>
<p>27.长度<br>S:len,datalength<br>O:length</p>
<p>28.大小写转换 lower,upper</p>
<p>29.单词首字母大写<br>S:没发现<br>O:select INITCAP('abcd dsaf df') value from dual</p>
<p>30.左补空格（LPAD的第一个参数为空格则同space函数）<br>S:select space(10)+'abcd' value<br>O:select LPAD('abcd',14) value from dual</p>
<p>31.右补空格（RPAD的第一个参数为空格则同space函数）<br>S:select 'abcd'+space(10) value<br>O:select RPAD('abcd',14) value from dual</p>
<p>32.删除空格<br>S:ltrim,rtrim<br>O:ltrim,rtrim,trim</p>
<p>33. 重复字符串<br>S:select REPLICATE('abcd',2) value<br>O:没发现</p>
<p>34.发音相似性比较(这两个单词返回值一样，发音相同)<br>S:SELECT SOUNDEX ('Smith'), SOUNDEX ('Smythe')<br>O:SELECT SOUNDEX ('Smith'), SOUNDEX ('Smythe') from dual<br>SQLServer中用SELECT DIFFERENCE('Smithers', 'Smythers') 比较soundex的差<br>返回0-4，4为同音，1最高</p>
<p>--------------日期函数</p>
<p>35.系统时间<br>S:select getdate() value<br>O:select sysdate value from dual</p>
<p>36.前后几日<br>直接与整数相加减</p>
<p>37.求日期<br>S:select convert(char(10),getdate(),20) value<br>O:select trunc(sysdate) value from dual<br>select to_char(sysdate,'yyyy-mm-dd') value from dual</p>
<p>38.求时间<br>S:select convert(char(8),getdate(),108) value<br>O:select to_char(sysdate,'hh24:mm:ss') value from dual</p>
<p>39.取日期时间的其他部分<br>S:DATEPART 和 DATENAME 函数 （第一个参数决定）<br>O:to_char函数 第二个参数决定</p>
<p>参数---------------------------------下表需要补充<br>year yy, yyyy<br>quarter qq, q (季度)<br>month mm, m (m O无效)<br>dayofyear dy, y (O表星期)<br>day dd, d (d O无效)<br>week wk, ww (wk O无效)<br>weekday dw (O不清楚)<br>Hour hh,hh12,hh24 (hh12,hh24 S无效)<br>minute mi, n (n O无效)<br>second ss, s (s O无效)<br>millisecond ms (O无效)<br>----------------------------------------------</p>
<p>40.当月最后一天<br>S:不知道<br>O:select LAST_DAY(sysdate) value from dual</p>
<p>41.本星期的某一天（比如星期日）<br>S:不知道<br>O:SELECT Next_day(sysdate,7) vaule FROM DUAL;</p>
<p>42.字符串转时间<br>S:可以直接转或者select cast('2004-09-08'as datetime) value<br>O:SELECT To_date('2004-01-05 22:09:38','yyyy-mm-dd hh24-mi-ss') vaule FROM DUAL;</p>
<p>43.求两日期某一部分的差（比如秒）<br>S:select datediff(ss,getdate(),getdate()+12.3) value<br>O:直接用两个日期相减（比如d1-d2=12.3）<br>SELECT (d1-d2)*24*60*60 vaule FROM DUAL;</p>
<p>44.根据差值求新的日期（比如分钟）<br>S:select dateadd(mi,8,getdate()) value<br>O:SELECT sysdate+8/60/24 vaule FROM DUAL;</p>
<p>45.求不同时区时间<br>S:不知道<br>O:SELECT New_time(sysdate,'ydt','gmt' ) vaule FROM DUAL;</p>
<p>-----时区参数,北京在东8区应该是Ydt-------<br>AST ADT 大西洋标准时间<br>BST BDT 白令海标准时间<br>CST CDT 中部标准时间<br>EST EDT 东部标准时间<br>GMT 格林尼治标准时间<br>HST HDT 阿拉斯加—夏威夷标准时间<br>MST MDT 山区标准时间<br>NST 纽芬兰标准时间<br>PST PDT 太平洋标准时间<br>YST YDT YUKON标准时间</p>
<p>Oracle支持的字符函数和它们的Microsoft SQL Server等价函数:</p>
<p>函数 Oracle Microsoft SQL　Server<br>把字符转换为ASCII ASCII ASCII<br>字串连接 CONCAT (expression + expression)<br>把ASCII转换为字符 CHR CHAR<br>返回字符串中的开始字符（左起） INSTR CHARINDEX<br>把字符转换为小写 LOWER LOWER<br>把字符转换为大写 UPPER UPPER<br>填充字符串的左边 LPAD N/A<br>清除开始的空白 LTRIM LTRIM<br>清除尾部的空白 RTRIM RTRIM<br>字符串中的起始模式（pattern） INSTR PATINDEX<br>多次重复字符串 RPAD REPLICATE<br>字符串的语音表示 SOUNDEX SOUNDEX<br>重复空格的字串 RPAD SPACE<br>从数字数据转换为字符数据 TO_CHAR STR<br>子串 SUBSTR SUBSTRING<br>替换字符 REPLACE STUFF<br>将字串中的每个词首字母大写 INITCAP N/A<br>翻译字符串 TRANSLATE N/A<br>字符串长度 LENGTH DATELENGTH or LEN<br>列表中最大的字符串 GREATEST N/A<br>列表中最小的字符串 LEAST N/A<br>如果为NULL则转换字串 NVL ISNULL</p>
<p>日期函数</p>
<p>函数 Oracle Microsoft SQL　Server<br>日期相加 (date column +/- value) or<br>ADD_MONTHS DATEADD<br>两个日期的差 (date column +/- value) or<br>MONTHS_BETWEEN DATEDIFF<br>当前日期和时间 SYSDATE GETDATE()<br>一个月的最后一天 LAST_DAY N/A<br>时区转换 NEW_TIME N/A<br>日期后的第一个周日 NEXT_DAY N/A<br>代表日期的字符串 TO_CHAR DATENAME<br>代表日期的整数 TO_NUMBER<br>(TO_CHAR)) DATEPART<br>日期舍入 ROUND CONVERT<br>日期截断 TRUNC CONVERT<br>字符串转换为日期 TO_DATE CONVERT<br>如果为NULL则转换日期 NVL ISNULL</p>
<p>转换函数</p>
<p>函数 Oracle Microsoft SQL　Server<br>数字转换为字符 TO_CHAR CONVERT<br>字符转换为数字 TO_NUMBER CONVERT<br>日期转换为字符 TO_CHAR CONVERT<br>字符转换为日期 TO_DATE CONVERT<br>16进制转换为2进制 HEX_TO_RAW CONVERT<br>2进制转换为16进制 RAW_TO_HEX CONVERT</p>
<p>其它行级别的函数</p>
<p>函数 Oracle Microsoft SQL　Server<br>返回第一个非空表达式 DECODE COALESCE<br>当前序列值 CURRVAL N/A<br>下一个序列值 NEXTVAL N/A<br>如果exp1 = exp2, 返回null DECODE NULLIF<br>用户登录账号ID数字 UID SUSER_ID<br>用户登录名 USER SUSER_NAME<br>用户数据库ID数字 UID USER_ID<br>用户数据库名 USER USER_NAME<br>当前用户 CURRENT_USER CURRENT_USER<br>用户环境(audit trail) USERENV N/A<br>在CONNECT BY子句中的级别 LEVEL N/A</p>
<p>合计函数</p>
<p>函数 Oracle Microsoft SQL　Server<br>Average AVG AVG<br>Count COUNT COUNT<br>Maximum MAX MAX<br>Minimum MIN MIN<br>Standard deviation STDDEV STDEV or STDEVP<br>Summation SUM SUM<br>Variance VARIANCE VAR or VARP</p>
<p>Oracle还有一个有用的函数EXTRACT,提取并且返回日期时间或时间间隔表达式中特定的时间域:<br>EXTRACT(YEAR FROM 日期)<br></p>
<img src ="http://www.blogjava.net/franlk/aggbug/128020.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-07-04 09:38 <a href="http://www.blogjava.net/franlk/articles/128020.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Temporary Tables临时表</title><link>http://www.blogjava.net/franlk/articles/126499.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Wed, 27 Jun 2007 02:41:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/126499.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/126499.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/126499.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/126499.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/126499.html</trackback:ping><description><![CDATA[<p><br>摘录地址:<br><br>Temporary Tables临时表<br>1简介<br>&nbsp;&nbsp; ORACLE数据库除了可以保存永久表外，还可以建立临时表temporary tables。这些临时表用来保存一个会话SESSION的数据，或者保存在一个事务中需要的数据。当会话退出或者用户提交commit和回滚rollback事务的时候，临时表的数据自动清空，但是临时表的结构以及元数据还存储在用户的数据字典中。<br>&nbsp;&nbsp; 临时表只在oracle8i以及以上产品中支持。<br>2详细介绍<br>&nbsp;&nbsp; Oracle临时表分为 会话级临时表 和 事务级临时表。<br>会话级临时表是指临时表中的数据只在会话生命周期之中存在，当用户退出会话结束的时候，Oracle自动清除临时表中数据。<br>事务级临时表是指临时表中的数据只在事务生命周期中存在。当一个事务结束（commit or rollback），Oracle自动清除临时表中数据。<br>临时表中的数据只对当前Session有效，每个Session都有自己的临时数据，并且不能访问其它Session的临时表中的数据。因此，临时表不需要DML锁。<br>&nbsp;&nbsp; 当一个会话结束(用户正常退出 用户不正常退出 ORACLE实例崩溃)或者一个事务结束的时候，Oracle对这个会话的表执行 TRUNCATE 语句清空临时表数据.但不会清空其它会话临时表中的数据.<br>你可以索引临时表和在临时表基础上建立视图.同样,建立在临时表上的索引也是临时的,也是只对当前会话或者事务有效.&nbsp;&nbsp; 临时表可以拥有触发器.<br>3建立临时表<br>&nbsp;&nbsp; 临时表的定义对所有会话SESSION都是可见的,但是表中的数据只对当前的会话或者事务有效. <br>&nbsp;&nbsp; 建立方法:<br>1) ON COMMIT DELETE ROWS 定义了建立事务级临时表的方法.<br>CREATE GLOBAL TEMPORARY TABLE admin_work_area<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (startdate DATE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enddate DATE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class CHAR(20))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ON COMMIT DELETE ROWS;<br>EXAMPLE:<br>SQL&gt; CREATE GLOBAL TEMPORARY TABLE admin_work_area<br>&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (startdate DATE,<br>&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enddate DATE,<br>&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class CHAR(20))<br>&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ON COMMIT DELETE ROWS;<br>SQL&gt; create table permernate( a number);<br>SQL&gt; insert into admin_work_area values(sysdate,sysdate,'temperary table');<br>SQL&gt; insert into permernate values(1);<br>SQL&gt; commit;<br>SQL&gt; select * from admin_work_area;<br>SQL&gt; select&nbsp; * from permernate;<br>A<br>1<br>2)ON COMMIT PRESERVE ROWS 定义了创建会话级临时表的方法.<br>CREATE GLOBAL TEMPORARY TABLE admin_work_area<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (startdate DATE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enddate DATE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class CHAR(20))<br>&nbsp;&nbsp;&nbsp;&nbsp; ON COMMIT PRESERVE ROWS;<br>EXAMPLE:</p>
<p>会话1:<br>SQL&gt; drop table admin_work_area;<br>SQL&gt; CREATE GLOBAL TEMPORARY TABLE admin_work_area<br>&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (startdate DATE,<br>&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enddate DATE,<br>&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class CHAR(20))<br>&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ON COMMIT PRESERVE ROWS;<br>SQL&gt; insert into permernate values(2);<br>SQL&gt; insert into admin_work_area values(sysdate,sysdate,'session temperary');<br>SQL&gt; commit;<br>SQL&gt; select * from permernate;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A<br>----------<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2</p>
<p>SQL&gt; select * from admin_work_area;</p>
<p>STARTDATE&nbsp; ENDDATE&nbsp;&nbsp;&nbsp; CLASS<br>---------- ---------- --------------------<br>17-1&#212;&#194; -03 17-1&#212;&#194; -03 session temperary</p>
<p>会话2:</p>
<p>SQL&gt; select * from permernate;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A<br>----------<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2</p>
<p>SQL&gt; select * from admin_work_area;</p>
<p>未选择行.</p>
<p>会话2看不见会话1中临时表的数据.</p>
<p>&nbsp;</p>
<p>4 ORACLE临时表和SQLSERVER临时表异同</p>
<p>SQL SERVER临时表<br>也可以创建临时表。临时表与永久表相似，但临时表存储在 tempdb 中，当不再使用时会自动删除。<br>有本地和全局两种类型的临时表，二者在名称、可见性和可用性上均不相同。本地临时表的名称以单个数字符号 (#) 打头；它们仅对当前的用户连接是可见的；当用户从 Microsoft&#174; SQL Server&#8482; 2000 实例断开连接时被删除。全局临时表的名称以数学符号 (##) 打头，创建后对任何用户都是可见的，当所有引用该表的用户从 SQL Server 断开连接时被删除。<br>例如，如果创建名为 employees 的表，则任何人只要在数据库中有使用该表的安全权限就可以使用该表，除非它已删除。如果创建名为 #employees 的本地临时表，只有您能对该表执行操作且在断开连接时该表删除。如果创建名为 ##employees 的全局临时表，数据表中的任何用户均可对该表执行操作。如果该表在您创建后没有其他用户使用，则当您断开连接时该表删除。如果该表在您创建后有其他用户使用，则 SQL Server在所有用户断开连接后删除该表<br>不同:<br>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SQL SERVER临时表是一种&#8221;内存表&#8221;,表是存储在内存中的.ORACLE临时表除非执行DROP TABLE,否则表定义会保留在数据字典中.<br>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SQL SERVER临时表不存在类似ORACLE临时表 事务级别 上的功能.<br>3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SQL SERVER本地临时表(#) 与 ORACLE的会话级别临时表类似,但是在会话退出的时候,ORACLE不会删除表.<br>4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SQL SERVER的全局临时表(##) 是指多个连接共享同一片内存.当没有指针引用该内存区域时,SQL SERVER自动释放全局临时表.<br>5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于ORACLE不是一种 内存中的数据库. 所以如果ORACLE类似SQL SERVER 频繁的对临时表进行建立和删除,必定会影响性能.所以ORACLE会保留临时表的定义直到用户DROP TABLE.<br>6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在ORACLE中,如果需要多个用户共享一个表(类似SQL SERVER的全局临时表##).则可以利用永久表,并且在表中添加一些可以唯一标识用户的列.利用触发器和视图.当用户退出的时候,根据该登陆用户的唯一信息删除相应的表中的数据. 这种方法给ORACLE带来了一定量的负载.</p>
<img src ="http://www.blogjava.net/franlk/aggbug/126499.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-06-27 10:41 <a href="http://www.blogjava.net/franlk/articles/126499.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ 摘录]ORACLE SQL性能优化系列 (三) </title><link>http://www.blogjava.net/franlk/articles/126162.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Mon, 25 Jun 2007 09:31:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/126162.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/126162.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/126162.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/126162.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/126162.html</trackback:ping><description><![CDATA[<p><br>&nbsp;摘录地址:http://www.dbonline.cn/source/oracle/20031218/oracle%20SQL%20performance%20tuning11.html<br><br>36. 用UNION替换OR (适用于索引列) </p>
<p>通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低. </p>
<p>在下面的例子中, LOC_ID 和REGION上都建有索引. </p>
<p>高效: </p>
<p>SELECT LOC_ID , LOC_DESC , REGION </p>
<p>FROM LOCATION </p>
<p>WHERE LOC_ID = 10 </p>
<p>UNION </p>
<p>SELECT LOC_ID , LOC_DESC , REGION </p>
<p>FROM LOCATION </p>
<p>WHERE REGION = &#8220;MELBOURNE&#8221; </p>
<p><br>低效: </p>
<p>SELECT LOC_ID , LOC_DESC , REGION </p>
<p>FROM LOCATION </p>
<p>WHERE LOC_ID = 10 OR REGION = &#8220;MELBOURNE&#8221; </p>
<p><br>如果你坚持要用OR, 那就需要返回记录最少的索引列写在最前面. </p>
<p><br>注意: </p>
<p><br>WHERE KEY1 = 10 (返回最少记录) </p>
<p>OR KEY2 = 20 (返回最多记录) </p>
<p><br>ORACLE 内部将以上转换为 </p>
<p>WHERE KEY1 = 10 AND </p>
<p>((NOT KEY1 = 10) AND KEY2 = 20) </p>
<p><br>译者按: </p>
<p><br>下面的测试数据仅供参考: (a = 1003 返回一条记录 , b = 1 返回1003条记录) </p>
<p>SQL&gt; select * from unionvsor /*1st test*/ </p>
<p>2 where a = 1003 or b = 1; </p>
<p>1003 rows selected. </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 CONCATENATION </p>
<p>2 1 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR' </p>
<p>3 2 INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE) </p>
<p>4 1 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR' </p>
<p>5 4 INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE) </p>
<p>Statistics </p>
<p>---------------------------------------------------------- </p>
<p>0 recursive calls </p>
<p>0 db block gets </p>
<p>144 consistent gets </p>
<p>0 physical reads </p>
<p>0 redo size </p>
<p>63749 bytes sent via SQL*Net to client </p>
<p>7751 bytes received via SQL*Net from client </p>
<p>68 SQL*Net roundtrips to/from client </p>
<p>0 sorts (memory) </p>
<p>0 sorts (disk) </p>
<p>1003 rows processed </p>
<p>SQL&gt; select * from unionvsor /*2nd test*/ </p>
<p>2 where b = 1 or a = 1003 ; </p>
<p>1003 rows selected. </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 CONCATENATION </p>
<p>2 1 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR' </p>
<p>3 2 INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE) </p>
<p>4 1 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR' </p>
<p>5 4 INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE) </p>
<p>Statistics </p>
<p>---------------------------------------------------------- </p>
<p>0 recursive calls </p>
<p>0 db block gets </p>
<p>143 consistent gets </p>
<p>0 physical reads </p>
<p>0 redo size </p>
<p>63749 bytes sent via SQL*Net to client </p>
<p>7751 bytes received via SQL*Net from client </p>
<p>68 SQL*Net roundtrips to/from client </p>
<p>0 sorts (memory) </p>
<p>0 sorts (disk) </p>
<p>1003 rows processed </p>
<p>&nbsp;</p>
<p>SQL&gt; select * from unionvsor /*3rd test*/ </p>
<p>2 where a = 1003 </p>
<p>3 union </p>
<p>4 select * from unionvsor </p>
<p>5 where b = 1; </p>
<p>1003 rows selected. </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 SORT (UNIQUE) </p>
<p>2 1 UNION-ALL </p>
<p>3 2 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR' </p>
<p>4 3 INDEX (RANGE SCAN) OF 'UA' (NON-UNIQUE) </p>
<p>5 2 TABLE ACCESS (BY INDEX ROWID) OF 'UNIONVSOR' </p>
<p>6 5 INDEX (RANGE SCAN) OF 'UB' (NON-UNIQUE) </p>
<p>Statistics </p>
<p>---------------------------------------------------------- </p>
<p>0 recursive calls </p>
<p>0 db block gets </p>
<p>10 consistent gets </p>
<p>0 physical reads </p>
<p>0 redo size </p>
<p>63735 bytes sent via SQL*Net to client </p>
<p>7751 bytes received via SQL*Net from client </p>
<p>68 SQL*Net roundtrips to/from client </p>
<p>1 sorts (memory) </p>
<p>0 sorts (disk) </p>
<p>1003 rows processed </p>
<p>用UNION的效果可以从consistent gets和 SQL*NET的数据交换量的减少看出 </p>
<p>&nbsp;</p>
<p>37. 用IN来替换OR </p>
<p><br>下面的查询可以被更有效率的语句替换: </p>
<p><br>低效: </p>
<p><br>SELECT&#8230;. </p>
<p>FROM LOCATION </p>
<p>WHERE LOC_ID = 10 </p>
<p>OR LOC_ID = 20 </p>
<p>OR LOC_ID = 30 </p>
<p><br>高效 </p>
<p>SELECT&#8230; </p>
<p>FROM LOCATION </p>
<p>WHERE LOC_IN IN (10,20,30); </p>
<p><br>译者按: </p>
<p>这是一条简单易记的规则，但是实际的执行效果还须检验，在ORACLE8i下，两者的执行路径似乎是相同的．　 </p>
<p>&nbsp;</p>
<p>38. 避免在索引列上使用IS NULL和IS NOT NULL </p>
<p>避免在索引中使用任何可以为空的列，ORACLE将无法使用该索引 ．对于单列索引，如果列包含空值，索引中将不存在此记录. 对于复合索引，如果每个列都为空，索引中同样不存在此记录.　如果至少有一个列不为空，则记录存在于索引中． </p>
<p>举例: </p>
<p>如果唯一性索引建立在表的A列和B列上, 并且表中存在一条记录的A,B值为(123,null) , ORACLE将不接受下一条具有相同A,B值（123,null）的记录(插入). 然而如果 </p>
<p>所有的索引列都为空，ORACLE将认为整个键值为空而空不等于空. 因此你可以插入1000 </p>
<p>条具有相同键值的记录,当然它们都是空! </p>
<p><br>因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引. </p>
<p>举例: </p>
<p><br>低效: (索引失效) </p>
<p>SELECT &#8230; </p>
<p>FROM DEPARTMENT </p>
<p>WHERE DEPT_CODE IS NOT NULL; </p>
<p><br>高效: (索引有效) </p>
<p>SELECT &#8230; </p>
<p>FROM DEPARTMENT </p>
<p>WHERE DEPT_CODE &gt;=0; <br><br>39. 总是使用索引的第一个列 </p>
<p>如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引. </p>
<p><br>译者按: </p>
<p>这也是一条简单而重要的规则. 见以下实例. </p>
<p><br>SQL&gt; create table multiindexusage ( inda number , indb number , descr varchar2(10)); </p>
<p>Table created. </p>
<p>SQL&gt; create index multindex on multiindexusage(inda,indb); </p>
<p>Index created. </p>
<p>SQL&gt; set autotrace traceonly </p>
<p><br>SQL&gt; select * from multiindexusage where inda = 1; </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 TABLE ACCESS (BY INDEX ROWID) OF 'MULTIINDEXUSAGE' </p>
<p>2 1 INDEX (RANGE SCAN) OF 'MULTINDEX' (NON-UNIQUE) </p>
<p><br>SQL&gt; select * from multiindexusage where indb = 1; </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 TABLE ACCESS (FULL) OF 'MULTIINDEXUSAGE' </p>
<p><br>很明显, 当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引 </p>
<p>&nbsp;</p>
<p>40. ORACLE内部操作 </p>
<p>当执行查询时,ORACLE采用了内部的操作. 下表显示了几种重要的内部操作. </p>
<p>ORACLE Clause <br>内部操作 </p>
<p>ORDER BY <br>SORT ORDER BY </p>
<p>UNION <br>UNION-ALL </p>
<p>MINUS <br>MINUS </p>
<p>INTERSECT <br>INTERSECT </p>
<p>DISTINCT,MINUS,INTERSECT,UNION <br>SORT UNIQUE </p>
<p>MIN,MAX,COUNT <br>SORT AGGREGATE </p>
<p>GROUP BY <br>SORT GROUP BY </p>
<p>ROWNUM <br>COUNT or COUNT STOPKEY </p>
<p>Queries involving Joins <br>SORT JOIN,MERGE JOIN,NESTED LOOPS </p>
<p>CONNECT BY <br>CONNECT BY </p>
<p>&nbsp;</p>
<p><br>41. 用UNION-ALL 替换UNION ( 如果有可能的话) </p>
<p><br>当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最终结果前进行排序. </p>
<p>如果用UNION ALL替代UNION, 这样排序就不是必要了. 效率就会因此得到提高. </p>
<p><br>举例: </p>
<p>低效： </p>
<p>　　　　 SELECT ACCT_NUM, BALANCE_AMT </p>
<p>FROM DEBIT_TRANSACTIONS </p>
<p>WHERE TRAN_DATE = '31-DEC-95' </p>
<p>UNION </p>
<p>SELECT ACCT_NUM, BALANCE_AMT </p>
<p>FROM DEBIT_TRANSACTIONS </p>
<p>WHERE TRAN_DATE = '31-DEC-95' </p>
<p>高效: </p>
<p>SELECT ACCT_NUM, BALANCE_AMT </p>
<p>FROM DEBIT_TRANSACTIONS </p>
<p>WHERE TRAN_DATE = '31-DEC-95' </p>
<p>UNION ALL </p>
<p>SELECT ACCT_NUM, BALANCE_AMT </p>
<p>FROM DEBIT_TRANSACTIONS </p>
<p>WHERE TRAN_DATE = '31-DEC-95' </p>
<p><br>译者按: </p>
<p>需要注意的是，UNION ALL 将重复输出两个结果集合中相同记录. 因此各位还是 </p>
<p>要从业务需求分析使用UNION ALL的可行性. </p>
<p>UNION 将对结果集合排序,这个操作会使用到SORT_AREA_SIZE这块内存. 对于这 </p>
<p>块内存的优化也是相当重要的. 下面的SQL可以用来查询排序的消耗量 </p>
<p><br>Select substr(name,1,25) "Sort Area Name", </p>
<p>substr(value,1,15) "Value" </p>
<p>from v$sysstat </p>
<p>where name like 'sort%' </p>
<p>&nbsp;</p>
<p>42. 使用提示(Hints) </p>
<p>对于表的访问,可以使用两种Hints. </p>
<p>FULL 和 ROWID </p>
<p><br>FULL hint 告诉ORACLE使用全表扫描的方式访问指定表. </p>
<p>例如: </p>
<p>SELECT /*+ FULL(EMP) */ * </p>
<p>FROM EMP </p>
<p>WHERE EMPNO = 7893; </p>
<p><br>ROWID hint 告诉ORACLE使用TABLE ACCESS BY ROWID的操作访问表. </p>
<p><br>通常, 你需要采用TABLE ACCESS BY ROWID的方式特别是当访问大表的时候, 使用这种方式, 你需要知道ROIWD的值或者使用索引. </p>
<p>如果一个大表没有被设定为缓存(CACHED)表而你希望它的数据在查询结束是仍然停留 </p>
<p>在SGA中,你就可以使用CACHE hint 来告诉优化器把数据保留在SGA中. 通常CACHE hint 和 FULL hint 一起使用. </p>
<p>例如: </p>
<p>SELECT /*+ FULL(WORKER) CACHE(WORKER)*/ * </p>
<p>FROM WORK; </p>
<p><br>索引hint 告诉ORACLE使用基于索引的扫描方式. 你不必说明具体的索引名称 </p>
<p>例如: </p>
<p>SELECT /*+ INDEX(LODGING) */ LODGING </p>
<p>FROM LODGING </p>
<p>WHERE MANAGER = &#8216;BILL GATES'; </p>
<p><br>在不使用hint的情况下, 以上的查询应该也会使用索引,然而,如果该索引的重复值过多而你的优化器是CBO, 优化器就可能忽略索引. 在这种情况下, 你可以用INDEX hint强制ORACLE使用该索引. </p>
<p><br>ORACLE hints 还包括ALL_ROWS, FIRST_ROWS, RULE,USE_NL, USE_MERGE, USE_HASH 等等. </p>
<p><br>译者按: </p>
<p>使用hint , 表示我们对ORACLE优化器缺省的执行路径不满意,需要手工修改. </p>
<p>这是一个很有技巧性的工作. 我建议只针对特定的,少数的SQL进行hint的优化. </p>
<p>对ORACLE的优化器还是要有信心(特别是CBO) <br><br>43. 用WHERE替代ORDER BY </p>
<p>ORDER BY 子句只在两种严格的条件下使用索引. </p>
<p><br>ORDER BY中所有的列必须包含在相同的索引中并保持在索引中的排列顺序. </p>
<p>ORDER BY中所有的列必须定义为非空. </p>
<p><br>WHERE子句使用的索引和ORDER BY子句中所使用的索引不能并列. </p>
<p><br>例如: </p>
<p>表DEPT包含以下列: </p>
<p>DEPT_CODE PK NOT NULL </p>
<p>DEPT_DESC NOT NULL </p>
<p>DEPT_TYPE NULL </p>
<p><br>非唯一性的索引(DEPT_TYPE) </p>
<p><br>低效: (索引不被使用) </p>
<p>SELECT DEPT_CODE </p>
<p>FROM DEPT </p>
<p>ORDER BY DEPT_TYPE </p>
<p><br>EXPLAIN PLAN: </p>
<p>SORT ORDER BY </p>
<p>TABLE ACCESS FULL </p>
<p><br>高效: (使用索引) </p>
<p><br>SELECT DEPT_CODE </p>
<p>FROM DEPT </p>
<p>WHERE DEPT_TYPE &gt; 0 </p>
<p><br>EXPLAIN PLAN: </p>
<p>TABLE ACCESS BY ROWID ON EMP </p>
<p>INDEX RANGE SCAN ON DEPT_IDX </p>
<p>译者按: </p>
<p>ORDER BY 也能使用索引! 这的确是个容易被忽视的知识点. 我们来验证一下: </p>
<p>SQL&gt; select * from emp order by empno; </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' </p>
<p>2 1 INDEX (FULL SCAN) OF 'EMPNO' (UNIQUE) </p>
<p>&nbsp;</p>
<p>44. 避免改变索引列的类型. </p>
<p>当比较不同数据类型的数据时, ORACLE自动对列进行简单的类型转换. </p>
<p><br>假设 EMPNO是一个数值类型的索引列. </p>
<p><br>SELECT &#8230; </p>
<p>FROM EMP </p>
<p>WHERE EMPNO = &#8216;123' </p>
<p><br>实际上,经过ORACLE类型转换, 语句转化为: </p>
<p>SELECT &#8230; </p>
<p>FROM EMP </p>
<p>WHERE EMPNO = TO_NUMBER(&#8216;123') </p>
<p><br>幸运的是,类型转换没有发生在索引列上,索引的用途没有被改变. </p>
<p><br>现在,假设EMP_TYPE是一个字符类型的索引列. </p>
<p>SELECT &#8230; </p>
<p>FROM EMP </p>
<p>WHERE EMP_TYPE = 123 </p>
<p><br>这个语句被ORACLE转换为: </p>
<p>SELECT &#8230; </p>
<p>FROM EMP </p>
<p>WHERE TO_NUMBER(EMP_TYPE)=123 </p>
<p><br>因为内部发生的类型转换, 这个索引将不会被用到! </p>
<p>译者按: </p>
<p>为了避免ORACLE对你的SQL进行隐式的类型转换, 最好把类型转换用显式表现出来. 注意当字符和数值比较时, ORACLE会优先转换数值类型到字符类型. </p>
<p>&nbsp;</p>
<p>45. 需要当心的WHERE子句 </p>
<p>某些SELECT 语句中的WHERE子句不使用索引. 这里有一些例子. </p>
<p>在下面的例子里, &#8216;!=' 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中. </p>
<p>不使用索引: </p>
<p>SELECT ACCOUNT_NAME </p>
<p>FROM TRANSACTION </p>
<p>WHERE AMOUNT !=0; </p>
<p>使用索引: </p>
<p>SELECT ACCOUNT_NAME </p>
<p>FROM TRANSACTION </p>
<p>WHERE AMOUNT &gt;0; </p>
<p><br>下面的例子中, &#8216;||'是字符连接函数. 就象其他函数那样, 停用了索引. </p>
<p>不使用索引: </p>
<p>SELECT ACCOUNT_NAME,AMOUNT </p>
<p>FROM TRANSACTION </p>
<p>WHERE ACCOUNT_NAME||ACCOUNT_TYPE='AMEXA'; </p>
<p>使用索引: </p>
<p>SELECT ACCOUNT_NAME,AMOUNT </p>
<p>FROM TRANSACTION </p>
<p>WHERE ACCOUNT_NAME = &#8216;AMEX' </p>
<p>AND ACCOUNT_TYPE=' A'; </p>
<p><br>下面的例子中, &#8216;+'是数学函数. 就象其他数学函数那样, 停用了索引. </p>
<p>不使用索引: </p>
<p>SELECT ACCOUNT_NAME, AMOUNT </p>
<p>FROM TRANSACTION </p>
<p>WHERE AMOUNT + 3000 &gt;5000; </p>
<p>使用索引: </p>
<p>SELECT ACCOUNT_NAME, AMOUNT </p>
<p>FROM TRANSACTION </p>
<p>WHERE AMOUNT &gt; 2000 ; </p>
<p>下面的例子中,相同的索引列不能互相比较,这将会启用全表扫描. </p>
<p>不使用索引: </p>
<p>SELECT ACCOUNT_NAME, AMOUNT </p>
<p>FROM TRANSACTION </p>
<p>WHERE ACCOUNT_NAME = NVL(:ACC_NAME,ACCOUNT_NAME); </p>
<p>使用索引: </p>
<p>SELECT ACCOUNT_NAME, AMOUNT </p>
<p>FROM TRANSACTION </p>
<p>WHERE ACCOUNT_NAME LIKE NVL(:ACC_NAME,'%'); </p>
<p><br>译者按: </p>
<p>如果一定要对使用函数的列启用索引, ORACLE新的功能: 基于函数的索引(Function-Based Index) 也许是一个较好的方案. </p>
<p>CREATE INDEX EMP_I ON EMP (UPPER(ename)); /*建立基于函数的索引*/ </p>
<p>SELECT * FROM emp WHERE UPPER(ename) = &#8216;BLACKSNAIL'; /*将使用索引*/ <br><br>46. 连接多个扫描 </p>
<p>如果你对一个列和一组有限的值进行比较, 优化器可能执行多次扫描并对结果进行合并连接. </p>
<p>举例: </p>
<p>SELECT * </p>
<p>FROM LODGING </p>
<p>WHERE MANAGER IN (&#8216;BILL GATES','KEN MULLER'); </p>
<p><br>优化器可能将它转换成以下形式 </p>
<p>SELECT * </p>
<p>FROM LODGING </p>
<p>WHERE MANAGER = &#8216;BILL GATES' </p>
<p>OR MANAGER = 'KEN MULLER'; </p>
<p><br>当选择执行路径时, 优化器可能对每个条件采用LODGING$MANAGER上的索引范围扫描. 返回的ROWID用来访问LODGING表的记录 (通过TABLE ACCESS BY ROWID 的方式). 最后两组记录以连接(CONCATENATION)的形式被组合成一个单一的集合. </p>
<p><br>Explain Plan : </p>
<p><br>SELECT STATEMENT Optimizer=CHOOSE </p>
<p>CONCATENATION </p>
<p>TABLE ACCESS (BY INDEX ROWID) OF LODGING </p>
<p>INDEX (RANGE SCAN ) OF LODGING$MANAGER (NON-UNIQUE) </p>
<p>TABLE ACCESS (BY INDEX ROWID) OF LODGING </p>
<p>INDEX (RANGE SCAN ) OF LODGING$MANAGER (NON-UNIQUE) </p>
<p>译者按: </p>
<p>本节和第37节似乎有矛盾之处. </p>
<p>&nbsp;</p>
<p>47. CBO下使用更具选择性的索引 </p>
<p>基于成本的优化器(CBO, Cost-Based Optimizer)对索引的选择性进行判断来决定索引的使用是否能提高效率. </p>
<p>如果索引有很高的选择性, 那就是说对于每个不重复的索引键值,只对应数量很少的记录. </p>
<p>比如, 表中共有100条记录而其中有80个不重复的索引键值. 这个索引的选择性就是80/100 = 0.8 . 选择性越高, 通过索引键值检索出的记录就越少. </p>
<p>如果索引的选择性很低, 检索数据就需要大量的索引范围查询操作和ROWID 访问表的 </p>
<p>操作. 也许会比全表扫描的效率更低. </p>
<p><br>译者按: </p>
<p>下列经验请参阅: </p>
<p>a. 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高. </p>
<p>b. 在特定情况下, 使用索引也许会比全表扫描慢, 但这是同一个数量级上的 </p>
<p>区别. 而通常情况下,使用索引比全表扫描要块几倍乃至几千倍! </p>
<p>&nbsp;</p>
<p>48. 避免使用耗费资源的操作 </p>
<p>带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL语句会启动SQL引擎 </p>
<p>执行耗费资源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要执行两次排序. </p>
<p>例如,一个UNION查询,其中每个查询都带有GROUP BY子句, GROUP BY会触发嵌入排序(NESTED SORT) ; 这样, 每个查询需要执行一次排序, 然后在执行UNION时, 又一个唯一排序(SORT UNIQUE)操作被执行而且它只能在前面的嵌入排序结束后才能开始执行. 嵌入的排序的深度会大大影响查询的效率. </p>
<p>通常, 带有UNION, MINUS , INTERSECT的SQL语句都可以用其他方式重写. </p>
<p>译者按: </p>
<p>如果你的数据库的SORT_AREA_SIZE调配得好, 使用UNION , MINUS, INTERSECT也是可以考虑的, 毕竟它们的可读性很强 </p>
<p>&nbsp;</p>
<p>49. 优化GROUP BY </p>
<p>提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉.下面两个查询返回相同结果但第二个明显就快了许多. </p>
<p><br>低效: </p>
<p>SELECT JOB , AVG(SAL) </p>
<p>FROM EMP </p>
<p>GROUP JOB </p>
<p>HAVING JOB = &#8216;PRESIDENT' </p>
<p>OR JOB = &#8216;MANAGER' </p>
<p>高效: </p>
<p>SELECT JOB , AVG(SAL) </p>
<p>FROM EMP </p>
<p>WHERE JOB = &#8216;PRESIDENT' </p>
<p>OR JOB = &#8216;MANAGER' </p>
<p>GROUP JOB </p>
<p><br>译者按: </p>
<p>本节和14节相同. 可略过. </p>
<p>&nbsp;</p>
<p>50. 使用日期 </p>
<p>当使用日期是,需要注意如果有超过5位小数加到日期上, 这个日期会进到下一天! </p>
<p><br>例如: </p>
<p>1. </p>
<p>SELECT TO_DATE(&#8216;01-JAN-93'+.99999) </p>
<p>FROM DUAL; </p>
<p><br>Returns: </p>
<p>'01-JAN-93 23:59:59' </p>
<p>2. </p>
<p>SELECT TO_DATE(&#8216;01-JAN-93'+.999999) </p>
<p>FROM DUAL; </p>
<p><br>Returns: </p>
<p>'02-JAN-93 00:00:00' </p>
<p><br>译者按: </p>
<p>虽然本节和SQL性能优化没有关系, 但是作者的功力可见一斑 </p>
<p>&nbsp;</p>
<p>51. 使用显式的游标(CURSORs) </p>
<p>使用隐式的游标,将会执行两次操作. 第一次检索记录, 第二次检查TOO MANY ROWS 这个exception . 而显式游标不执行第二次操作. </p>
<p>&nbsp;</p>
<p>52. 优化EXPORT和IMPORT </p>
<p>使用较大的BUFFER(比如10MB , 10,240,000)可以提高EXPORT和IMPORT的速度. </p>
<p>ORACLE将尽可能地获取你所指定的内存大小,即使在内存不满足,也不会报错.这个值至少要和表中最大的列相当,否则列值会被截断. </p>
<p>译者按: </p>
<p>可以肯定的是, 增加BUFFER会大大提高EXPORT , IMPORT的效率. (曾经碰到过一个CASE, 增加BUFFER后,IMPORT/EXPORT快了10倍!) </p>
<p>作者可能犯了一个错误: &#8220;这个值至少要和表中最大的列相当,否则列值会被截断. &#8220; </p>
<p>其中最大的列也许是指最大的记录大小. </p>
<p>关于EXPORT/IMPORT的优化,CSDN论坛中有一些总结性的贴子,比如关于BUFFER参数, COMMIT参数等等, 详情请查. </p>
<p>&nbsp;</p>
<p>53. 分离表和索引 </p>
<p>总是将你的表和索引建立在不同的表空间内(TABLESPACES). 决不要将不属于ORACLE内部系统的对象存放到SYSTEM表空间里. 同时,确保数据表空间和索引表空间置于不同的硬盘上. </p>
<p><br>译者按: </p>
<p>&#8220;同时,确保数据表空间和索引表空间置与不同的硬盘上.&#8221;可能改为如下更为准确 &#8220;同时,确保数据表空间和索引表空间置与不同的硬盘控制卡控制的硬盘上.&#8221; </p>
<p><br>(全文完) </p>
<p>Black_Snail </p>
<p><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#108;&#105;&#103;&#97;&#110;&#103;&#49;&#48;&#48;&#48;&#64;&#104;&#111;&#116;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">ligang1000@hotmail.com</a> </p>
<p>4/Sep/2003 <br><br><br></p>
<img src ="http://www.blogjava.net/franlk/aggbug/126162.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-06-25 17:31 <a href="http://www.blogjava.net/franlk/articles/126162.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ 摘录]ORACLE SQL性能优化系列 (二) </title><link>http://www.blogjava.net/franlk/articles/126151.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Mon, 25 Jun 2007 08:48:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/126151.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/126151.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/126151.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/126151.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/126151.html</trackback:ping><description><![CDATA[<p><br>摘录地址: <a href="http://www.dbonline.cn/source/oracle/20031218/oracle%20SQL%20performance%20tuning6.html">http://www.dbonline.cn/source/oracle/20031218/oracle%20SQL%20performance%20tuning6.html</a><br><br>20. 用表连接替换EXISTS </p>
<p><br>通常来说 , 采用表连接的方式比EXISTS更有效率 </p>
<p>SELECT ENAME </p>
<p>FROM EMP E </p>
<p>WHERE EXISTS (SELECT &#8216;X' </p>
<p>FROM DEPT </p>
<p>WHERE DEPT_NO = E.DEPT_NO </p>
<p>AND DEPT_CAT = &#8216;A'); </p>
<p><br>(更高效) </p>
<p>SELECT ENAME </p>
<p>FROM DEPT D,EMP E </p>
<p>WHERE E.DEPT_NO = D.DEPT_NO </p>
<p>AND DEPT_CAT = &#8216;A' ; </p>
<p><br>(译者按: 在RBO的情况下,前者的执行路径包括FILTER,后者使用NESTED LOOP) </p>
<p>&nbsp;</p>
<p>21. 用EXISTS替换DISTINCT </p>
<p>当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换 </p>
<p><br>例如: </p>
<p>低效: </p>
<p>SELECT DISTINCT DEPT_NO,DEPT_NAME </p>
<p>FROM DEPT D,EMP E </p>
<p>WHERE D.DEPT_NO = E.DEPT_NO </p>
<p>高效: </p>
<p>SELECT DEPT_NO,DEPT_NAME </p>
<p>FROM DEPT D </p>
<p>WHERE EXISTS ( SELECT &#8216;X' </p>
<p>FROM EMP E </p>
<p>WHERE E.DEPT_NO = D.DEPT_NO); </p>
<p><br>EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果. </p>
<p>&nbsp;</p>
<p>22. 识别'低效执行'的SQL语句 </p>
<p><br>用下列SQL工具找出低效SQL: </p>
<p>SELECT EXECUTIONS , DISK_READS, BUFFER_GETS, </p>
<p>ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio, </p>
<p>ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run, </p>
<p>SQL_TEXT </p>
<p>FROM V$SQLAREA </p>
<p>WHERE EXECUTIONS&gt;0 </p>
<p>AND BUFFER_GETS &gt; 0 </p>
<p>AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS &lt; 0.8 </p>
<p>ORDER BY 4 DESC; </p>
<p><br>(译者按: 虽然目前各种关于SQL优化的图形化工具层出不穷,但是写出自己的SQL工具来解决问题始终是一个最好的方法) </p>
<p>&nbsp;</p>
<p>23. 使用TKPROF 工具来查询SQL性能状态 </p>
<p><br>SQL trace 工具收集正在执行的SQL的性能状态数据并记录到一个跟踪文件中. 这个跟踪文件提供了许多有用的信息,例如解析次数.执行次数,CPU使用时间等.这些数据将可以用来优化你的系统. </p>
<p><br>设置SQL TRACE在会话级别: 有效 </p>
<p><br>ALTER SESSION SET SQL_TRACE TRUE </p>
<p><br>设置SQL TRACE 在整个数据库有效仿, 你必须将SQL_TRACE参数在init.ora中设为TRUE, USER_DUMP_DEST参数说明了生成跟踪文件的目录 </p>
<p><br>(译者按: 这一节中,作者并没有提到TKPROF的用法, 对SQL TRACE的用法也不够准确, 设置SQL TRACE首先要在init.ora中设定TIMED_STATISTICS, 这样才能得到那些重要的时间状态. 生成的trace文件是不可读的,所以要用TKPROF工具对其进行转换,TKPROF有许多执行参数. 大家可以参考ORACLE手册来了解具体的配置. ) <br><br>24. 用EXPLAIN PLAN 分析SQL语句 </p>
<p><br>EXPLAIN PLAN 是一个很好的分析SQL语句的工具,它甚至可以在不执行SQL的情况下分析语句. 通过分析,我们就可以知道ORACLE是怎么样连接表,使用什么方式扫描表(索引扫描或全表扫描)以及使用到的索引名称. </p>
<p>你需要按照从里到外,从上到下的次序解读分析的结果. EXPLAIN PLAN分析的结果是用缩进的格式排列的, 最内部的操作将被最先解读, 如果两个操作处于同一层中,带有最小操作号的将被首先执行. </p>
<p>NESTED LOOP是少数不按照上述规则处理的操作, 正确的执行路径是检查对NESTED LOOP提供数据的操作,其中操作号最小的将被最先处理. </p>
<p><br>译者按: </p>
<p>通过实践, 感到还是用SQLPLUS中的SET TRACE 功能比较方便. </p>
<p>举例: </p>
<p><br>SQL&gt; list </p>
<p>1 SELECT * </p>
<p>2 FROM dept, emp </p>
<p>3* WHERE emp.deptno = dept.deptno </p>
<p>SQL&gt; set autotrace traceonly /*traceonly 可以不显示执行结果*/ </p>
<p>SQL&gt; / </p>
<p>14 rows selected. </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 NESTED LOOPS </p>
<p>2 1 TABLE ACCESS (FULL) OF 'EMP' </p>
<p>3 1 TABLE ACCESS (BY INDEX ROWID) OF 'DEPT' </p>
<p>4 3 INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE) </p>
<p><br>Statistics </p>
<p>---------------------------------------------------------- </p>
<p>0 recursive calls </p>
<p>2 db block gets </p>
<p>30 consistent gets </p>
<p>0 physical reads </p>
<p>0 redo size </p>
<p>2598 bytes sent via SQL*Net to client </p>
<p>503 bytes received via SQL*Net from client </p>
<p>2 SQL*Net roundtrips to/from client </p>
<p>0 sorts (memory) </p>
<p>0 sorts (disk) </p>
<p>14 rows processed </p>
<p><br>通过以上分析,可以得出实际的执行步骤是: </p>
<p>1. TABLE ACCESS (FULL) OF 'EMP' </p>
<p>2. INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE) </p>
<p>3. TABLE ACCESS (BY INDEX ROWID) OF 'DEPT' </p>
<p>4. NESTED LOOPS (JOINING 1 AND 3) </p>
<p>&nbsp;</p>
<p>注: 目前许多第三方的工具如TOAD和ORACLE本身提供的工具如OMS的SQL Analyze都提供了极其方便的EXPLAIN PLAN工具.也许喜欢图形化界面的朋友们可以选用它们. </p>
<p><br>25. 用索引提高效率 </p>
<p><br>索引是表的一个概念部分,用来提高检索数据的效率. 实际上,ORACLE使用了一个复杂的自平衡B-tree结构. 通常,通过索引查询数据比全表扫描要快. 当ORACLE找出执行查询和Update语句的最佳路径时, ORACLE优化器将使用索引. 同样在联结多个表时使用索引也可以提高效率. 另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证. </p>
<p>除了那些LONG或LONG RAW数据类型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,你也会发现, 在扫描小表时,使用索引同样能提高效率. </p>
<p>虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价. 索引需要空间来 </p>
<p>存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢. </p>
<p><br>译者按: </p>
<p>定期的重构索引是有必要的. </p>
<p>ALTER INDEX &lt;INDEXNAME&gt; REBUILD &lt;TABLESPACENAME&gt; </p>
<p>&nbsp;</p>
<p>26. 索引的操作 </p>
<p><br>ORACLE对索引有两种访问模式. </p>
<p><br>索引唯一扫描 ( INDEX UNIQUE SCAN) </p>
<p><br>大多数情况下, 优化器通过WHERE子句访问INDEX. </p>
<p><br>例如: </p>
<p>表LODGING有两个索引 : 建立在LODGING列上的唯一性索引LODGING_PK和建立在MANAGER列上的非唯一性索引LODGING$MANAGER. </p>
<p>&nbsp;</p>
<p>SELECT * </p>
<p>FROM LODGING </p>
<p>WHERE LODGING = &#8216;ROSE HILL'; </p>
<p><br>在内部 , 上述SQL将被分成两步执行, 首先 , LODGING_PK 索引将通过索引唯一扫描的方式被访问 , 获得相对应的ROWID, 通过ROWID访问表的方式 执行下一步检索. </p>
<p>如果被检索返回的列包括在INDEX列中,ORACLE将不执行第二步的处理(通过ROWID访问表). 因为检索数据保存在索引中, 单单访问索引就可以完全满足查询结果. </p>
<p>下面SQL只需要INDEX UNIQUE SCAN 操作. </p>
<p><br>SELECT LODGING </p>
<p>FROM LODGING </p>
<p>WHERE LODGING = &#8216;ROSE HILL'; </p>
<p><br>索引范围查询(INDEX RANGE SCAN) </p>
<p>适用于两种情况: </p>
<p>1. 基于一个范围的检索 </p>
<p>2. 基于非唯一性索引的检索 </p>
<p><br>例1: </p>
<p><br>SELECT LODGING </p>
<p>FROM LODGING </p>
<p>WHERE LODGING LIKE &#8216;M%'; </p>
<p><br>WHERE子句条件包括一系列值, ORACLE将通过索引范围查询的方式查询LODGING_PK . 由于索引范围查询将返回一组值, 它的效率就要比索引唯一扫描 </p>
<p>低一些. </p>
<p><br>例2: </p>
<p><br>SELECT LODGING </p>
<p>FROM LODGING </p>
<p>WHERE MANAGER = &#8216;BILL GATES'; </p>
<p><br>这个SQL的执行分两步, LODGING$MANAGER的索引范围查询(得到所有符合条件记录的ROWID) 和下一步同过ROWID访问表得到LODGING列的值. 由于LODGING$MANAGER是一个非唯一性的索引,数据库不能对它执行索引唯一扫描. </p>
<p><br>由于SQL返回LODGING列,而它并不存在于LODGING$MANAGER索引中, 所以在索引范围查询后会执行一个通过ROWID访问表的操作. </p>
<p><br>WHERE子句中, 如果索引列所对应的值的第一个字符由通配符(WILDCARD)开始, 索引将不被采用. </p>
<p><br>SELECT LODGING </p>
<p>FROM LODGING </p>
<p>WHERE MANAGER LIKE &#8216;％HANMAN'; </p>
<p><br>在这种情况下，ORACLE将使用全表扫描.&nbsp;<br>&nbsp;<br></p>
<p>27. 基础表的选择 </p>
<p><br>基础表(Driving Table)是指被最先访问的表(通常以全表扫描的方式被访问). 根据优化器的不同, SQL语句中基础表的选择是不一样的. </p>
<p>如果你使用的是CBO (COST BASED OPTIMIZER),优化器会检查SQL语句中的每个表的物理大小,索引的状态,然后选用花费最低的执行路径. </p>
<p>如果你用RBO (RULE BASED OPTIMIZER) , 并且所有的连接条件都有索引对应, 在这种情况下, 基础表就是FROM 子句中列在最后的那个表. </p>
<p>举例: </p>
<p>SELECT A.NAME , B.MANAGER </p>
<p>FROM　WORKER A, </p>
<p>LODGING B </p>
<p>WHERE　A.LODGING = B.LODING; </p>
<p>由于LODGING表的LODING列上有一个索引, 而且WORKER表中没有相比较的索引, WORKER表将被作为查询中的基础表. </p>
<p>&nbsp;</p>
<p>28. 多个平等的索引 </p>
<p>当SQL语句的执行路径可以使用分布在多个表上的多个索引时, ORACLE会同时使用多个索引并在运行时对它们的记录进行合并, 检索出仅对全部索引有效的记录. </p>
<p>在ORACLE选择执行路径时,唯一性索引的等级高于非唯一性索引. 然而这个规则只有 </p>
<p>当WHERE子句中索引列和常量比较才有效.如果索引列和其他表的索引类相比较. 这种子句在优化器中的等级是非常低的. </p>
<p>如果不同表中两个想同等级的索引将被引用, FROM子句中表的顺序将决定哪个会被率先使用. FROM子句中最后的表的索引将有最高的优先级. </p>
<p>如果相同表中两个想同等级的索引将被引用, WHERE子句中最先被引用的索引将有最高的优先级. </p>
<p>举例: </p>
<p>DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引. </p>
<p>SELECT ENAME, </p>
<p>FROM EMP </p>
<p>WHERE DEPT_NO = 20 </p>
<p>AND EMP_CAT = &#8216;A'; </p>
<p>这里,DEPTNO索引将被最先检索,然后同EMP_CAT索引检索出的记录进行合并. 执行路径如下: </p>
<p>&nbsp;</p>
<p>TABLE ACCESS BY ROWID ON EMP </p>
<p>AND-EQUAL </p>
<p>INDEX RANGE SCAN ON DEPT_IDX </p>
<p>INDEX RANGE SCAN ON CAT_IDX </p>
<p>&nbsp;</p>
<p>29. 等式比较和范围比较 </p>
<p>当WHERE子句中有索引列, ORACLE不能合并它们,ORACLE将用范围比较. </p>
<p><br>举例: </p>
<p>DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引. </p>
<p>SELECT ENAME </p>
<p>FROM EMP </p>
<p>WHERE DEPTNO &gt; 20 </p>
<p>AND EMP_CAT = &#8216;A'; </p>
<p>&nbsp;</p>
<p>这里只有EMP_CAT索引被用到,然后所有的记录将逐条与DEPTNO条件进行比较. 执行路径如下: </p>
<p>TABLE ACCESS BY ROWID ON EMP </p>
<p>INDEX RANGE SCAN ON CAT_IDX </p>
<p>&nbsp;</p>
<p>30. 不明确的索引等级 </p>
<p><br>当ORACLE无法判断索引的等级高低差别,优化器将只使用一个索引,它就是在WHERE子句中被列在最前面的. </p>
<p>举例: </p>
<p>DEPTNO上有一个非唯一性索引,EMP_CAT也有一个非唯一性索引. </p>
<p><br>SELECT ENAME </p>
<p>FROM EMP </p>
<p>WHERE DEPTNO &gt; 20 </p>
<p>AND EMP_CAT &gt; &#8216;A'; </p>
<p><br>这里, ORACLE只用到了DEPT_NO索引. 执行路径如下: </p>
<p><br>TABLE ACCESS BY ROWID ON EMP </p>
<p>INDEX RANGE SCAN ON DEPT_IDX </p>
<p><br>译者按: </p>
<p>我们来试一下以下这种情况: </p>
<p>SQL&gt; select index_name, uniqueness from user_indexes where table_name = 'EMP'; </p>
<p><br>INDEX_NAME UNIQUENES </p>
<p>------------------------------ --------- </p>
<p>EMPNO UNIQUE </p>
<p>EMPTYPE NONUNIQUE </p>
<p><br>SQL&gt; select * from emp where empno &gt;= 2 and emp_type = 'A' ; </p>
<p><br>no rows selected </p>
<p>&nbsp;</p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' </p>
<p>2 1 INDEX (RANGE SCAN) OF 'EMPTYPE' (NON-UNIQUE) </p>
<p><br>虽然EMPNO是唯一性索引,但是由于它所做的是范围比较, 等级要比非唯一性索引的等式比较低!&nbsp;<br><br>31. 强制索引失效 </p>
<p><br>如果两个或以上索引具有相同的等级,你可以强制命令ORACLE优化器使用其中的一个(通过它,检索出的记录数量少) . </p>
<p><br>举例: </p>
<p><br>SELECT ENAME </p>
<p>FROM EMP </p>
<p>WHERE EMPNO = 7935 </p>
<p>AND DEPTNO + 0 = 10 /*DEPTNO上的索引将失效*/ </p>
<p>AND EMP_TYPE || &#8216;' = &#8216;A' /*EMP_TYPE上的索引将失效*/ </p>
<p><br>这是一种相当直接的提高查询效率的办法. 但是你必须谨慎考虑这种策略,一般来说,只有在你希望单独优化几个SQL时才能采用它. </p>
<p><br>这里有一个例子关于何时采用这种策略, </p>
<p><br>假设在EMP表的EMP_TYPE列上有一个非唯一性的索引而EMP_CLASS上没有索引. </p>
<p><br>SELECT ENAME </p>
<p>FROM EMP </p>
<p>WHERE EMP_TYPE = &#8216;A' </p>
<p>AND EMP_CLASS = &#8216;X'; </p>
<p><br>优化器会注意到EMP_TYPE上的索引并使用它. 这是目前唯一的选择. 如果,一段时间以后, 另一个非唯一性建立在EMP_CLASS上,优化器必须对两个索引进行选择,在通常情况下,优化器将使用两个索引并在他们的结果集合上执行排序及合并. 然而,如果其中一个索引（EMP_TYPE）接近于唯一性而另一个索引（EMP_CLASS）上有几千个重复的值. 排序及合并就会成为一种不必要的负担. 在这种情况下,你希望使优化器屏蔽掉EMP_CLASS索引. </p>
<p>用下面的方案就可以解决问题. </p>
<p>SELECT ENAME </p>
<p>FROM EMP </p>
<p>WHERE EMP_TYPE = &#8216;A' </p>
<p>AND EMP_CLASS||'' = &#8216;X'; </p>
<p>&nbsp;</p>
<p>32. 避免在索引列上使用计算． </p>
<p>WHERE子句中，如果索引列是函数的一部分．优化器将不使用索引而使用全表扫描． </p>
<p><br>举例: </p>
<p><br>低效： </p>
<p>SELECT &#8230; </p>
<p>FROM DEPT </p>
<p>WHERE SAL * 12 &gt; 25000; </p>
<p><br>高效: </p>
<p>SELECT &#8230; </p>
<p>FROM DEPT </p>
<p>WHERE SAL &gt; 25000/12; </p>
<p><br>译者按: </p>
<p>这是一个非常实用的规则，请务必牢记 </p>
<p>&nbsp;</p>
<p>33. 自动选择索引 </p>
<p>如果表中有两个以上（包括两个）索引，其中有一个唯一性索引，而其他是非唯一性． </p>
<p>在这种情况下，ORACLE将使用唯一性索引而完全忽略非唯一性索引． </p>
<p><br>举例: </p>
<p>SELECT ENAME </p>
<p>FROM EMP </p>
<p>WHERE EMPNO = 2326 </p>
<p>AND DEPTNO = 20 ; </p>
<p><br>这里，只有EMPNO上的索引是唯一性的，所以EMPNO索引将用来检索记录． </p>
<p>TABLE ACCESS BY ROWID ON EMP </p>
<p>INDEX UNIQUE SCAN ON EMP_NO_IDX </p>
<p>&nbsp;</p>
<p>34. 避免在索引列上使用NOT </p>
<p>通常，　我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的 </p>
<p>影响. 当ORACLE&#8221;遇到&#8221;NOT,他就会停止使用索引转而执行全表扫描. </p>
<p>举例: </p>
<p><br>低效: (这里,不使用索引) </p>
<p><br>SELECT &#8230; </p>
<p>FROM DEPT </p>
<p>WHERE DEPT_CODE NOT = 0; </p>
<p><br>高效: (这里,使用了索引) </p>
<p><br>SELECT &#8230; </p>
<p>FROM DEPT </p>
<p>WHERE DEPT_CODE &gt; 0; </p>
<p><br>需要注意的是,在某些时候, ORACLE优化器会自动将NOT转化成相对应的关系操作符. </p>
<p>NOT &gt; to &lt;= </p>
<p>NOT &gt;= to &lt; </p>
<p>NOT &lt; to &gt;= </p>
<p>NOT &lt;= to &gt; </p>
<p>&nbsp;</p>
<p>译者按: </p>
<p>在这个例子中,作者犯了一些错误. 例子中的低效率SQL是不能被执行的. </p>
<p>我做了一些测试: </p>
<p><br>SQL&gt; select * from emp where NOT empno &gt; 1; </p>
<p>no rows selected </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' </p>
<p>2 1 INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE) </p>
<p><br>SQL&gt; select * from emp where empno &lt;= 1; </p>
<p>no rows selected </p>
<p>Execution Plan </p>
<p>---------------------------------------------------------- </p>
<p>0 SELECT STATEMENT Optimizer=CHOOSE </p>
<p>1 0 TABLE ACCESS (BY INDEX ROWID) OF 'EMP' </p>
<p>2 1 INDEX (RANGE SCAN) OF 'EMPNO' (UNIQUE) </p>
<p><br>两者的效率完全一样，也许这符合作者关于&#8221; 在某些时候, ORACLE优化器会自动将NOT转化成相对应的关系操作符&#8221; 的观点． </p>
<p>&nbsp;</p>
<p>35. 用&gt;=替代&gt; </p>
<p><br>如果DEPTNO上有一个索引, </p>
<p><br>高效: </p>
<p><br>SELECT * </p>
<p>FROM EMP </p>
<p>WHERE DEPTNO &gt;=4 </p>
<p><br>低效: </p>
<p><br>SELECT * </p>
<p>FROM EMP </p>
<p>WHERE DEPTNO &gt;3 </p>
<p><br>两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录. </p>
<p>&nbsp;</p>
<p><br>&nbsp;</p>
<img src ="http://www.blogjava.net/franlk/aggbug/126151.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-06-25 16:48 <a href="http://www.blogjava.net/franlk/articles/126151.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ 摘录]ORACLE SQL性能优化系列 (一)</title><link>http://www.blogjava.net/franlk/articles/126117.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Mon, 25 Jun 2007 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/126117.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/126117.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/126117.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/126117.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/126117.html</trackback:ping><description><![CDATA[<p><br>摘录地址:http://www.dbonline.cn/source/oracle/20031218/oracle%20SQL%20performance%20tuning1.html<br><br>关键字 ORACEL SQL Performance tuning </p>
<p>出处 <a href="http://www.dbasupport.com/">http://www.dbasupport.com</a> </p>
<p><br>1. 选用适合的ORACLE优化器 </p>
<p>&nbsp;</p>
<p>ORACLE的优化器共有3种: </p>
<p>a. RULE (基于规则) b. COST (基于成本) c. CHOOSE (选择性) </p>
<p>&nbsp;</p>
<p>设置缺省的优化器,可以通过对init.ora文件中OPTIMIZER_MODE参数的各种声明,如RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS . 你当然也在SQL句级或是会话(session)级对其进行覆盖. </p>
<p>为了使用基于成本的优化器(CBO, Cost-Based Optimizer) , 你必须经常运行analyze 命令,以增加数据库中的对象统计信息(object statistics)的准确性. </p>
<p>如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关. 如果table已经被analyze过, 优化器模式将自动成为CBO , 反之,数据库将采用RULE形式的优化器. </p>
<p>&nbsp;</p>
<p>在缺省情况下,ORACLE采用CHOOSE优化器, 为了避免那些不必要的全表扫描(full table scan) , 你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或者基于成本的优化器. </p>
<p>&nbsp;</p>
<p>2. 访问Table的方式 </p>
<p>&nbsp;</p>
<p>ORACLE 采用两种访问表中记录的方式: </p>
<p>&nbsp;</p>
<p>a. 全表扫描 </p>
<p>全表扫描就是顺序地访问表中每条记录. ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描. </p>
<p>&nbsp;</p>
<p>b. 通过ROWID访问表 </p>
<p>你可以采用基于ROWID的访问方式情况,提高访问表的效率, , ROWID包含了表中记录的物理位置信息..ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系. 通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高. </p>
<p>&nbsp;</p>
<p>3. 共享SQL语句 </p>
<p>&nbsp;</p>
<p>为了不重复解析相同的SQL语句,在第一次解析之后, ORACLE将SQL语句存放在内存中.这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享. 因此,当你执行一个SQL语句(有时被称为一个游标)时,如果它 </p>
<p>和之前的执行过的语句完全相同, ORACLE就能很快获得已经被解析的语句以及最好的 </p>
<p>执行路径. ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用. </p>
<p>可惜的是ORACLE只对简单的表提供高速缓冲(cache buffering) ,这个功能并不适用于多表连接查询. </p>
<p>数据库管理员必须在init.ora中为这个区域设置合适的参数,当这个内存区域越大,就可以保留更多的语句,当然被共享的可能性也就越大了. </p>
<p>当你向ORACLE 提交一个SQL语句,ORACLE会首先在这块内存中查找相同的语句. </p>
<p>这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语句必须 </p>
<p>完全相同(包括空格,换行等). </p>
<p>共享的语句必须满足三个条件: </p>
<p>&nbsp;</p>
<p>A. 字符级的比较: </p>
<p>当前被执行的语句和共享池中的语句必须完全相同. </p>
<p>例如: </p>
<p>SELECT * FROM EMP; </p>
<p>和下列每一个都不同 </p>
<p>SELECT * from EMP; </p>
<p>Select * From Emp; </p>
<p>SELECT * FROM EMP; </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>B. 两个语句所指的对象必须完全相同: </p>
<p>例如: </p>
<p>用户 对象名 如何访问 </p>
<p>Jack sal_limit private synonym </p>
<p>Work_city public synonym </p>
<p>Plant_detail public synonym </p>
<p>&nbsp;</p>
<p>Jill sal_limit private synonym </p>
<p>Work_city public synonym </p>
<p>Plant_detail table owner </p>
<p><br>考虑一下下列SQL语句能否在这两个用户之间共享. </p>
<p>&nbsp;</p>
<p>SQL <br>能否共享 <br>原因 </p>
<p>select max(sal_cap) from sal_limit; <br>不能 <br>每个用户都有一个private synonym - sal_limit , 它们是不同的对象 </p>
<p>select count(*0 from work_city where sdesc like 'NEW%'; <br>能 <br>两个用户访问相同的对象public synonym - work_city </p>
<p>select a.sdesc,b.location from work_city a , plant_detail b where a.city_id = b.city_id <br>不能 <br>用户jack 通过private synonym访问plant_detail 而jill 是表的所有者,对象不同. </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>C. 两个SQL语句中必须使用相同的名字的绑定变量(bind variables) </p>
<p><br>例如： </p>
<p><br>第一组的两个SQL语句是相同的(可以共享),而第二组中的两个语句是不同的(即使在运行时,赋于不同的绑定变量相同的值) </p>
<p>a. </p>
<p>select pin , name from people where pin = :blk1.pin; </p>
<p>select pin , name from people where pin = :blk1.pin; </p>
<p><br>b. </p>
<p>select pin , name from people where pin = :blk1.ot_ind; </p>
<p>select pin , name from people where pin = :blk1.ov_ind; <br><br>4. 选择最有效率的表名顺序(只在基于规则的优化器中有效) </p>
<p><br>ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并. </p>
<p><br>例如: </p>
<p>表 TAB1 16,384 条记录 </p>
<p>表 TAB2 1 条记录 </p>
<p><br>选择TAB2作为基础表 (最好的方法) </p>
<p>select count(*) from tab1,tab2 执行时间0.96秒 </p>
<p><br>选择TAB2作为基础表 (不佳的方法) </p>
<p>select count(*) from tab2,tab1 执行时间26.09秒 </p>
<p><br>如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表. </p>
<p><br>例如: </p>
<p>EMP表描述了LOCATION表和CATEGORY表的交集. </p>
<p>SELECT * </p>
<p>FROM LOCATION L , </p>
<p>CATEGORY C, </p>
<p>EMP E </p>
<p>WHERE E.EMP_NO BETWEEN 1000 AND 2000 </p>
<p>AND E.CAT_NO = C.CAT_NO </p>
<p>AND E.LOCN = L.LOCN </p>
<p><br>将比下列SQL更有效率 </p>
<p><br>SELECT * </p>
<p>FROM EMP E , </p>
<p>LOCATION L , </p>
<p>CATEGORY C </p>
<p>WHERE E.CAT_NO = C.CAT_NO </p>
<p>AND E.LOCN = L.LOCN </p>
<p>AND E.EMP_NO BETWEEN 1000 AND 2000 </p>
<p>&nbsp;</p>
<p>5. WHERE子句中的连接顺序． </p>
<p><br>ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾. </p>
<p><br>例如: </p>
<p>(低效,执行时间156.3秒) </p>
<p>SELECT &#8230; </p>
<p>FROM EMP E </p>
<p>WHERE SAL &gt; 50000 </p>
<p>AND JOB = &#8216;MANAGER' </p>
<p>AND 25 &lt; (SELECT COUNT(*) FROM EMP </p>
<p>WHERE MGR=E.EMPNO); </p>
<p><br>(高效,执行时间10.6秒) </p>
<p>SELECT &#8230; </p>
<p>FROM EMP E </p>
<p>WHERE 25 &lt; (SELECT COUNT(*) FROM EMP </p>
<p>WHERE MGR=E.EMPNO) </p>
<p>AND SAL &gt; 50000 </p>
<p>AND JOB = &#8216;MANAGER'; </p>
<p>&nbsp;</p>
<p>6. SELECT子句中避免使用 &#8216; * &#8216; </p>
<p>当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 &#8216;*' 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间. </p>
<p>&nbsp;</p>
<p>7. 减少访问数据库的次数 </p>
<p>当执行每条SQL语句时, ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等等. 由此可见, 减少访问数据库的次数 , 就能实际上减少ORACLE的工作量. </p>
<p><br>例如, </p>
<p>以下有三种方法可以检索出雇员号等于0342或0291的职员. </p>
<p><br>方法1 (最低效) </p>
<p>SELECT EMP_NAME , SALARY , GRADE </p>
<p>FROM EMP </p>
<p>WHERE EMP_NO = 342; </p>
<p><br>SELECT EMP_NAME , SALARY , GRADE </p>
<p>FROM EMP </p>
<p>WHERE EMP_NO = 291; </p>
<p><br>方法2 (次低效) </p>
<p>DECLARE </p>
<p>CURSOR C1 (E_NO NUMBER) IS </p>
<p>SELECT EMP_NAME,SALARY,GRADE </p>
<p>FROM EMP </p>
<p>WHERE EMP_NO = E_NO; </p>
<p>BEGIN </p>
<p>OPEN C1(342); </p>
<p>FETCH C1 INTO &#8230;,..,.. ; </p>
<p>&#8230;.. </p>
<p>OPEN C1(291); </p>
<p>FETCH C1 INTO &#8230;,..,.. ; </p>
<p>CLOSE C1; </p>
<p>END; </p>
<p><br>方法3 (高效) </p>
<p>SELECT A.EMP_NAME , A.SALARY , A.GRADE, </p>
<p>B.EMP_NAME , B.SALARY , B.GRADE </p>
<p>FROM EMP A,EMP B </p>
<p>WHERE A.EMP_NO = 342 </p>
<p>AND B.EMP_NO = 291; </p>
<p><br>注意: </p>
<p>在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200 <br><br>8. 使用DECODE函数来减少处理时间 </p>
<p><br>使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表. </p>
<p><br>例如: </p>
<p>SELECT COUNT(*)，SUM(SAL) </p>
<p>FROM　EMP </p>
<p>WHERE DEPT_NO = 0020 </p>
<p>AND ENAME LIKE　&#8216;SMITH%'; </p>
<p><br>SELECT COUNT(*)，SUM(SAL) </p>
<p>FROM　EMP </p>
<p>WHERE DEPT_NO = 0030 </p>
<p>AND ENAME LIKE　&#8216;SMITH%'; </p>
<p><br>你可以用DECODE函数高效地得到相同结果 </p>
<p><br>SELECT COUNT(DECODE(DEPT_NO,0020,'X',NULL)) D0020_COUNT, </p>
<p>COUNT(DECODE(DEPT_NO,0030,'X',NULL)) D0030_COUNT, </p>
<p>SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL, </p>
<p>SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL </p>
<p>FROM EMP WHERE ENAME LIKE &#8216;SMITH%'; </p>
<p><br>类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中. </p>
<p>&nbsp;</p>
<p>9. 整合简单,无关联的数据库访问 </p>
<p><br>如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系) </p>
<p>例如: </p>
<p><br>SELECT NAME </p>
<p>FROM EMP </p>
<p>WHERE EMP_NO = 1234; </p>
<p><br>SELECT NAME </p>
<p>FROM DPT </p>
<p>WHERE DPT_NO = 10 ; </p>
<p><br>SELECT NAME </p>
<p>FROM CAT </p>
<p>WHERE CAT_TYPE = &#8216;RD'; </p>
<p><br>上面的3个查询可以被合并成一个: </p>
<p><br>SELECT E.NAME , D.NAME , C.NAME </p>
<p>FROM CAT C , DPT D , EMP E,DUAL X </p>
<p>WHERE NVL(&#8216;X',X.DUMMY) = NVL(&#8216;X',E.ROWID(+)) </p>
<p>AND NVL(&#8216;X',X.DUMMY) = NVL(&#8216;X',D.ROWID(+)) </p>
<p>AND NVL(&#8216;X',X.DUMMY) = NVL(&#8216;X',C.ROWID(+)) </p>
<p>AND E.EMP_NO(+) = 1234 </p>
<p>AND D.DEPT_NO(+) = 10 </p>
<p>AND C.CAT_TYPE(+) = &#8216;RD'; </p>
<p><br>(译者按: 虽然采取这种方法,效率得到提高,但是程序的可读性大大降低,所以读者 还是要权衡之间的利弊) </p>
<p><br>10. 删除重复记录 </p>
<p>最高效的删除重复记录方法 ( 因为使用了ROWID) </p>
<p><br>DELETE FROM EMP E </p>
<p>WHERE E.ROWID &gt; (SELECT MIN(X.ROWID) </p>
<p>FROM EMP X </p>
<p>WHERE X.EMP_NO = E.EMP_NO); </p>
<p><br>11. 用TRUNCATE替代DELETE </p>
<p>当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是 </p>
<p>恢复到执行删除命令之前的状况) </p>
<p><br>而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. </p>
<p><br>(译者按: TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML) </p>
<p>&nbsp;</p>
<p>12. 尽量多使用COMMIT </p>
<p><br>只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少: </p>
<p>COMMIT所释放的资源: </p>
<p>a. 回滚段上用于恢复数据的信息. </p>
<p>b. 被程序语句获得的锁 </p>
<p>c. redo log buffer 中的空间 </p>
<p>d. ORACLE为管理上述3种资源中的内部花费 </p>
<p><br>(译者按: 在使用COMMIT时必须要注意到事务的完整性,现实中效率和事务完整性往往是鱼和熊掌不可得兼) </p>
<p>&nbsp;</p>
<p>对该文的评论 人气：4369 <br>black_snail (2003-9-7 19:16:56) </p>
<p>如果DECODE取值为NULL，SUM（NULL）的值是NULL --&gt;如果所有的值都是NULL , SUM(NULL) = NULL 但是只要有一个值不是NULL,SUM() &lt;&gt; NULL 所以原SQL应该没有什么逻辑上的问题 </p>
<p>menlion (2003-9-4 12:38:01) </p>
<p>关于第八点的个人看法：如果DECODE取值为NULL，SUM（NULL）的值是NULL，不会正常求和的。可以改成如下所示就好了： SELECT COUNT(DECODE(DEPT_NO,0020,'X',NULL)) D0020_COUNT, COUNT(DECODE(DEPT_NO,0030,'X',NULL)) D0030_COUNT, SUM(DECODE(DEPT_NO,0020,SAL,0)) D0020_SAL, SUM(DECODE(DEPT_NO,0030,SAL,0)) D0030_SAL FROM EMP WHERE ENAME LIKE &#8216;SMITH%'; <br><br>13. 计算记录条数 </p>
<p>和一般的观点相反, count(*) 比count(1)稍快 , 当然如果可以通过索引检索,对索引列的计数仍旧是最快的. 例如 COUNT(EMPNO) </p>
<p><br>(译者按: 在CSDN论坛中,曾经对此有过相当热烈的讨论, 作者的观点并不十分准确,通过实际的测试,上述三种方法并没有显著的性能差别) </p>
<p><br>14. 用Where子句替换HAVING子句 </p>
<p><br>避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销. </p>
<p><br>例如: </p>
<p><br>低效: </p>
<p>SELECT REGION，AVG(LOG_SIZE) </p>
<p>FROM LOCATION </p>
<p>GROUP BY REGION </p>
<p>HAVING REGION REGION != &#8216;SYDNEY' </p>
<p>AND REGION != &#8216;PERTH' </p>
<p><br>高效 </p>
<p>SELECT REGION，AVG(LOG_SIZE) </p>
<p>FROM LOCATION </p>
<p>WHERE REGION REGION != &#8216;SYDNEY' </p>
<p>AND REGION != &#8216;PERTH' </p>
<p>GROUP BY REGION </p>
<p>(译者按: HAVING 中的条件一般用于对一些集合函数的比较,如COUNT() 等等. 除此而外,一般的条件应该写在WHERE子句中) </p>
<p><br>15. 减少对表的查询 </p>
<p>在含有子查询的SQL语句中,要特别注意减少对表的查询. </p>
<p><br>例如: </p>
<p>低效 </p>
<p>SELECT TAB_NAME </p>
<p>FROM TABLES </p>
<p>WHERE TAB_NAME = ( SELECT TAB_NAME </p>
<p>FROM TAB_COLUMNS </p>
<p>WHERE VERSION = 604) </p>
<p>AND　DB_VER= ( SELECT DB_VER </p>
<p>FROM TAB_COLUMNS </p>
<p>WHERE VERSION = 604) </p>
<p><br>高效 </p>
<p>SELECT TAB_NAME </p>
<p>FROM TABLES </p>
<p>WHERE (TAB_NAME,DB_VER) </p>
<p>= ( SELECT TAB_NAME,DB_VER) </p>
<p>FROM TAB_COLUMNS </p>
<p>WHERE VERSION = 604) </p>
<p><br>Update 多个Column 例子: </p>
<p>低效: </p>
<p>UPDATE EMP </p>
<p>SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES), </p>
<p>SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES) </p>
<p>WHERE EMP_DEPT = 0020; </p>
<p><br>高效: </p>
<p>UPDATE EMP </p>
<p>SET (EMP_CAT, SAL_RANGE) </p>
<p>= (SELECT MAX(CATEGORY) , MAX(SAL_RANGE) </p>
<p>FROM EMP_CATEGORIES) </p>
<p>WHERE EMP_DEPT = 0020; </p>
<p>&nbsp;</p>
<p>16. 通过内部函数提高SQL效率. </p>
<p><br>SELECT H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC,COUNT(*) </p>
<p>FROM HISTORY_TYPE T,EMP E,EMP_HISTORY H </p>
<p>WHERE H.EMPNO = E.EMPNO </p>
<p>AND H.HIST_TYPE = T.HIST_TYPE </p>
<p>GROUP BY H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC; </p>
<p><br>通过调用下面的函数可以提高效率. </p>
<p>FUNCTION LOOKUP_HIST_TYPE(TYP IN NUMBER) RETURN VARCHAR2 </p>
<p>AS </p>
<p>TDESC VARCHAR2(30); </p>
<p>CURSOR C1 IS </p>
<p>SELECT TYPE_DESC </p>
<p>FROM HISTORY_TYPE </p>
<p>WHERE HIST_TYPE = TYP; </p>
<p>BEGIN </p>
<p>OPEN C1; </p>
<p>FETCH C1 INTO TDESC; </p>
<p>CLOSE C1; </p>
<p>RETURN (NVL(TDESC,'?')); </p>
<p>END; </p>
<p><br>FUNCTION LOOKUP_EMP(EMP IN NUMBER) RETURN VARCHAR2 </p>
<p>AS </p>
<p>ENAME VARCHAR2(30); </p>
<p>CURSOR C1 IS </p>
<p>SELECT ENAME </p>
<p>FROM EMP </p>
<p>WHERE EMPNO=EMP; </p>
<p>BEGIN </p>
<p>OPEN C1; </p>
<p>FETCH C1 INTO ENAME; </p>
<p>CLOSE C1; </p>
<p>RETURN (NVL(ENAME,'?')); </p>
<p>END; </p>
<p><br>SELECT H.EMPNO,LOOKUP_EMP(H.EMPNO), </p>
<p>H.HIST_TYPE,LOOKUP_HIST_TYPE(H.HIST_TYPE),COUNT(*) </p>
<p>FROM EMP_HISTORY H </p>
<p>GROUP BY H.EMPNO , H.HIST_TYPE; </p>
<p><br>(译者按: 经常在论坛中看到如 '能不能用一个SQL写出&#8230;.' 的贴子, 殊不知复杂的SQL往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的) <br><br>17. 使用表的别名(Alias) </p>
<p>当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误. </p>
<p><br>(译者注: Column歧义指的是由于SQL中不同的表具有相同的Column名,当SQL语句中出现这个Column时,SQL解析器无法判断这个Column的归属) </p>
<p><br>18. 用EXISTS替代IN </p>
<p>在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率. </p>
<p><br>低效: </p>
<p>SELECT * </p>
<p>FROM EMP (基础表) </p>
<p>WHERE EMPNO &gt; 0 </p>
<p>AND DEPTNO IN (SELECT DEPTNO </p>
<p>FROM DEPT </p>
<p>WHERE LOC = &#8216;MELB') </p>
<p><br>高效: </p>
<p>SELECT * </p>
<p>FROM EMP (基础表) </p>
<p>WHERE EMPNO &gt; 0 </p>
<p>AND EXISTS (SELECT &#8216;X' </p>
<p>FROM DEPT </p>
<p>WHERE DEPT.DEPTNO = EMP.DEPTNO </p>
<p>AND LOC = &#8216;MELB') </p>
<p><br>(译者按: 相对来说,用NOT EXISTS替换NOT IN 将更显著地提高效率,下一节中将指出) </p>
<p>&nbsp;</p>
<p>19. 用NOT EXISTS替代NOT IN </p>
<p>在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS. </p>
<p><br>例如: </p>
<p>SELECT &#8230; </p>
<p>FROM EMP </p>
<p>WHERE DEPT_NO NOT IN (SELECT DEPT_NO </p>
<p>FROM DEPT </p>
<p>WHERE DEPT_CAT='A'); </p>
<p><br>为了提高效率.改写为: </p>
<p><br>(方法一: 高效) </p>
<p>SELECT &#8230;. </p>
<p>FROM EMP A,DEPT B </p>
<p>WHERE A.DEPT_NO = B.DEPT(+) </p>
<p>AND B.DEPT_NO IS NULL </p>
<p>AND B.DEPT_CAT(+) = &#8216;A' </p>
<p>&nbsp;</p>
<p>(方法二: 最高效) </p>
<p>SELECT &#8230;. </p>
<p>FROM EMP E </p>
<p>WHERE NOT EXISTS (SELECT &#8216;X' </p>
<p>FROM DEPT D </p>
<p>WHERE D.DEPT_NO = E.DEPT_NO </p>
<p>AND DEPT_CAT = &#8216;A'); <br><br><br><br></p>
<img src ="http://www.blogjava.net/franlk/aggbug/126117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-06-25 15:25 <a href="http://www.blogjava.net/franlk/articles/126117.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]oracle中的树型查询</title><link>http://www.blogjava.net/franlk/articles/122176.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 05 Jun 2007 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/122176.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/122176.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/122176.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/122176.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/122176.html</trackback:ping><description><![CDATA[<br>摘录地址:http://lw.upschool.cn/edu/1834/2007/16/10du262264_1.shtml<br><br>在项目开发中树型结构是经常被使用的，通常情况下我们对查询的结果集使用一些免费的js文件就能达到很好的显示效果，比如<br>　　<br>　　但是有时候我们需要对下拉列表也提供树型结构（比如论坛的板块跳转），这个时候我们就可以使用oracle9i以上版本提供的CONNECT BY 子句了。<br>　　<br>　　SELECT kindid,kindname,fatherid<br>　　FROM kn_kind<br>　　CONNECT BY PRIOR kindid=fatherid<br>　　START WITH kindid='0';<br>　　<br>　　再稍加处理即可以得到需要的效果：<br>　　<br>　　SELECT lpad('|-',(level-1)*4,' ')||lpad('『',2)||kindname||rpad('』',2) kindname<br>　　FROM kn_kind<br>　　CONNECT BY PRIOR kindid=fatherid<br>　　START WITH kindid='0'; 
<img src ="http://www.blogjava.net/franlk/aggbug/122176.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-06-05 17:14 <a href="http://www.blogjava.net/franlk/articles/122176.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Oracle数据库关于SQL的执行计划</title><link>http://www.blogjava.net/franlk/articles/122173.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 05 Jun 2007 08:59:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/122173.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/122173.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/122173.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/122173.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/122173.html</trackback:ping><description><![CDATA[<br>摘录地址:http://lw.upschool.cn/edu/1834/2007/16/10du262259_1.shtml<br><br><strong>本文的目的：<br></strong>　　<br>　　1、说一说Oracle的Optimizer及其相关的一些知识。<br>　　<br>　　2、回答一下为什么有时一个表的某个字段明明有索引,当观察一些SQL的执行计划时,发现确不走索引的问题。<br>　　<br>　　3、如果你对 FIRST_ROWS、 ALL_ROWS这两种模式有疑惑时也可以看一下这篇文章。<br>　　<br>　　<strong>开始吧:</strong><br>　　<br>　　Oracle在执行一个SQL之前,首先要分析一下语句的执行计划,然后再按执行计划去执行。分析语句的执行计划的工作是由优化器(Optimizer)来完成的。不同的情况,一条SQL可能有多种执行计划,但在某一时点,一定只有一种执行计划是最优的,花费时间是最少的。相信你一定会用Pl/sql Developer、Toad等工具去看一个语句的执行计划,不过你可能对Rule、Choose、First rows、All rows这几项有疑问,因为我当初也是这样的,那时我也疑惑为什么选了以上的不同的项,执行计划就变了?<br>　　<br>　　1、优化器的优化方式<br>　　<br>　　Oracle的优化器共有两种的优化方式,即基于规则的优化方式(Rule-Based Optimization,简称为RBO)和基于代价的优化方式(Cost-Based Optimization,简称为CBO)。<br>　　<br>　　A、RBO方式：优化器在分析SQL语句时,所遵循的是Oracle内部预定的一些规则。比如我们常见的,当一个where子句中的一列有索引时去走索引。<br>　　<br>　　B、CBO方式：依词义可知,它是看语句的代价(Cost)了,这里的代价主要指Cpu和内存。优化器在判断是否用这种方式时,主要参照的是表及索引的统计信息。统计信息给出表的大小 、有少行、每行的长度等信息。这些统计信息起初在库内是没有的,是你在做analyze后才出现的,很多的时侯过期统计信息会令优化器做出一个错误的执行计划,因些我们应及时更新这些信息。在Oracle8及以后的版本,Oracle列推荐用CBO的方式。<br>　　<br>　　我们要明了,不一定走索引就是优的 ,比如一个表只有两行数据,一次IO就可以完成全表的检索,而此时走索引时则需要两次IO,这时对这个表做全表扫描(full table scan)是最好的。<br>　　<br>　　2、优化器的优化模式(Optermizer Mode)<br>　　<br>　　优化模式包括Rule,Choose,First rows,All rows这四种方式,也就是我们以上所提及的。如下我解释一下：<br>　　<br>　　Rule:不用多说,即走基于规则的方式。<br>　　<br>　　Choolse:这是我们应观注的,默认的情况下Oracle用的便是这种方式。指的是当一个表或或索引有统计信息,则走CBO的方式,如果表或索引没统计信息,表又不是特别的小,而且相应的列有索引时,那么就走索引,走RBO的方式。<br>　　<br>　　First Rows:它与Choose方式是类似的,所不同的是当一个表有统计信息时,它将是以最快的方式返回查询的最先的几行,从总体上减少了响应时间。<br>　　<br>　　All Rows:也就是我们所说的Cost的方式,当一个表有统计信息时,它将以最快的方式返回表的所有的行,从总体上提高查询的吞吐量。没有统计信息则走基于规则的方式。<br>　　<br>　　3、如何设定选用哪种优化模式<br>　　<br>　　A、Instance级别<br>　　<br>　　我们可以通过在init&lt;SID&gt;.ora文件中设定OPTIMIZER_MODE=RULE、OPTIMIZER_MODE=CHOOSE、OPTIMIZER_MODE=FIRST_ROWS、OPTIMIZER_MODE=ALL_ROWS去选用3所提的四种方式,如果你没设定OPTIMIZER_MODE参数则默认用的是Choose这种方式。<br>　　<br>　　B、Sessions级别<br>　　<br>　　通过SQL&gt; ALTER SESSION SET OPTIMIZER_MODE=&lt;Mode&gt;;来设定。<br>　　<br>　　C、语句级别<br>　　<br>　　这些需要用到Hint,比如:<br>　　<br>　　SQL&gt; SELECT /*+ RULE */ a.userid,<br>　　2 b.name,<br>　　3 b.depart_name<br>　　4 FROM tf_f_yhda a,<br>　　5 tf_f_depart b<br>　　6 WHERE a.userid=b.userid;<br>　　<br>　　4、为什么有时一个表的某个字段明明有索引,当观察一些语的执行计划确不走索引呢？如何解决呢 ？<br>　　<br>　　A、不走索引大体有以下几个原因<br>　　♀你在Instance级别所用的是all_rows的方式<br>　　♀你的表的统计信息(最可能的原因)<br>　　♀你的表很小,上文提到过的,Oracle的优化器认为不值得走索引。<br>　　<br>　　B、解决方法<br>　　♀可以修改init&lt;SID&gt;.ora中的OPTIMIZER_MODE这个参数,把它改为Rule或Choose,重起数据库。也可以使用4中所提的Hint.<br>　　♀删除统计信息<br>　　SQL&gt;analyze table table_name delete statistics;<br>　　♀表小不走索引是对的,不用调的。<br>　　<br>　　5、其它相关<br>　　<br>　　A、如何看一个表或索引是否是统计信息<br>　　<br>　　SQL&gt;SELECT * FROM user_tables<br>　　2 WHERE table_name=&lt;table_name&gt;<br>　　3 AND num_rows is not null;<br>　　SQL&gt;SELECT * FROM user_indexes<br>　　2 WHERE table_name=&lt;table_name&gt;<br>　　3 AND num_rows is not null;<br>　　<br>　　b、如果我们先用CBO的方式,我们应及时去更新表和索引的统计信息,以免生形不切合实的执行计划。<br>　　<br>　　SQL&gt; ANALYZE TABLE table_name COMPUTE STATISTICS;<br>　　SQL&gt; ANALYZE INDEX index_name ESTIMATE STATISTICS;<br>　　<br>　　具体的ANALYZE语句请参照Oracle8i/9i 的refrence文档。<br>　　&lt;================end of file&#8220;Oracle的优化器(Optimizer)&#8221;=====================&gt;<br>　　<br>　　<strong>下面的是我的关于一点执行计划的理解</strong>：<br>　　<br>　　1。首先要启动trace的选项：<br>　　set autotrace trace explain<br>　　如果出现下面的错误：<br>　　<br>　　SQL&gt;　set autotrace trace explain<br>　　SP2-0613: Unable to verify PLAN_TABLE format or existence<br>　　SP2-0611: Error enabling EXPLAIN report<br>　　<br>　　那么要先运行下面的语句：<br>　　 @?/rdbms/admin/utlxplan.sql；<br>　　<br>　　2。分析下面的执行计划：<br>　　<br>　　SQL&gt; select ename,dname　　from emp, dept　 where emp.deptno=dept.deptno　　 and dept.dname in ('ACCOUNTING','RESEARCH','SALES','OPERATIONS');<br>　　<br>　　Execution Plan<br>　　----------------------------------------------------------<br>　　0　　　SELECT STATEMENT Optimizer=CHOOSE<br>　　1　　0　 NESTED LOOPS<br>　　2　　1　　 TABLE ACCESS (FULL) OF 'EMP'<br>　　3　　1　　 TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'<br>　　4　　3　　　 INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)<br>　　<br>　　关于前面的两个数字，第一个是状态ID,第二个是父ID。<br>　　<br>　　就是如下所示：0--&gt;1--&gt;2<br>　　　　　　　　　　　　 |<br>　　　　　　　　　　　　 |--&gt;3--&gt;4<br>　　在上图里，0的执行依靠1，1的执行又依赖2和3，2是没有子ID的，所以2最先执行，然后是4，在然后是3；然后2和3的结果传回1。<br>　　<br>　　在这个里面0行有个字&#8220;Optimizer=CHOOSE&#8221;，这个就是上文说的那个oracle的优化器了。<br>　　<br>　　还有，看这个&#8220; INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)&#8221;，就知道这个语句运行的时候是走INDEX的。<br>　　<br>　　可以猜测这个SQL是使用的RBO，而不是CBO.<br>　　<br>　　如果让它变成CBO的话，可以这样：<br>　　analyze table emp compute statistics;<br>　　analyze table dept compute statistics;<br>　　<br>　　<strong>然后再执行一次：</strong><br>　　<br>　　SQL&gt; select ename,dname　　from emp, dept　 where emp.deptno=dept.deptno　　 and<br>　　 dept.dname in ('ACCOUNTING','RESEARCH','SALES','OPERATIONS');<br>　　<br>　　Execution Plan<br>　　----------------------------------------------------------<br>　　0　　　SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=14 Bytes=252)<br>　　1　　0　 HASH JOIN (Cost=3 Card=14 Bytes=252)<br>　　2　　1　　 TABLE ACCESS (FULL) OF 'DEPT' (Cost=1 Card=3 Bytes=33)<br>　　3　　1　　 TABLE ACCESS (FULL) OF 'EMP' (Cost=1 Card=14 Bytes=98)<br>　　<br>　　这次执行的时候，就不会走INDEX,而是全表扫描了，因为这个表一共就只有14个记录。<br>　　<br>　　好了，就先试到这里吧。
<p align=right>来源:upschool.com.cn<br>作者:<br>关键字：执行计划<br>发表日期：2007-1-6 0:29:56</p>
<img src ="http://www.blogjava.net/franlk/aggbug/122173.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-06-05 16:59 <a href="http://www.blogjava.net/franlk/articles/122173.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Oracle数据库执行计划的一些基本概念 （2）</title><link>http://www.blogjava.net/franlk/articles/122147.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 05 Jun 2007 07:28:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/122147.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/122147.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/122147.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/122147.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/122147.html</trackback:ping><description><![CDATA[<br>摘录地址:http://www.pcdog.com/edu/oracle/2006/11/b174438.html<br><br>
<p style="TEXT-INDENT: 2em"><strong>三.表之间的连接</strong>
<p style="TEXT-INDENT: 2em">Join是一种试图将两个表结合在一起的谓词，一次只能连接2个表，表连接也可以被称为表关联。 在后面的叙述中，我们将会使用&#8221;row source&#8221;来代替&#8221;表&#8221;，因为使用row source更严谨一些，并且将参与连接的2个row source分别称为row source1和row source 2。Join过程的各个步骤经常是串行操作，即使相关的row source可以被并行访问，即可以并行的读取做join连接的两个row source的数据，但是在将表中符合限制条件的数据读入到内存形成row source后，join的其它步骤一般是串行的。有多种方法可以将2个表连接起来，当然每种方法都有自己的优缺点，每种连接类型只有在特定的条件下才会发挥出其最大优势。
<p style="TEXT-INDENT: 2em">row source(表)之间的连接顺序对于查询的效率有非常大的影响。通过首先存取特定的表，即将该表作为驱动表，这样可以先应用某些限制条件，从而得到一个较小的row source，使连接的效率较高，这也就是我们常说的要先执行限制条件的原因。一般是在将表读入内存时，应用where子句中对该表的限制条件。
<p style="TEXT-INDENT: 2em">根据2个row source的连接条件的中操作符的不同，可以将连接分为等值连接(如WHERE A.COL3 = B.COL4)、非等值连接(WHERE A.COL3 &gt; B.COL4)、外连接(WHERE A.COL3 = B.COL4(+))。上面的各个连接的连接原理都基本一样，所以为了简单期间，下面以等值连接为例进行介绍。
<p style="TEXT-INDENT: 2em">在后面的介绍中，都已：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SELECT A.COL1, B.COL2
            FROM A, B
            WHERE A.COL3 = B.COL4;</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">为例进行说明，假设A表为Row Soruce1，则其对应的连接操作关联列为COL 3；B表为Row Soruce2，则其对应的连接操作关联列为COL 4；
<p style="TEXT-INDENT: 2em">连接类型：
<p style="TEXT-INDENT: 2em">目前为止，无论连接操作符如何，典型的连接类型共有3种：
<p style="TEXT-INDENT: 2em">排序 - - 合并连接(Sort Merge Join (SMJ) )
<p style="TEXT-INDENT: 2em">嵌套循环(Nested Loops (NL) )
<p style="TEXT-INDENT: 2em">哈希连接(Hash Join)
<p style="TEXT-INDENT: 2em">排序 - - 合并连接(Sort Merge Join, SMJ)
<p style="TEXT-INDENT: 2em">内部连接过程：
<p style="TEXT-INDENT: 2em">1) 首先生成row source1需要的数据，然后对这些数据按照连接操作关联列(如A.col3)进行排序。
<p style="TEXT-INDENT: 2em">2) 随后生成row source2需要的数据，然后对这些数据按照与sort source1对应的连接操作关联列(如B.col4)进行排序。
<p style="TEXT-INDENT: 2em">3) 最后两边已排序的行被放在一起执行合并操作，即将2个row source按照连接条件连接起来
<p style="TEXT-INDENT: 2em">下面是连接步骤的图形表示：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>MERGE
            /\
            SORTSORT
            ||
            Row Source 1Row Source 2</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">如果row source已经在连接关联列上被排序，则该连接操作就不需要再进行sort操作，这样可以大大提高这种连接操作的连接速度，因为排序是个极其费资源的操作，特别是对于较大的表。预先排序的row source包括已经被索引的列(如a.col3或b.col4上有索引)或row source已经在前面的步骤中被排序了。尽管合并两个row source的过程是串行的，但是可以并行访问这两个row source(如并行读入数据，并行排序).
<p style="TEXT-INDENT: 2em">SMJ连接的例子：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan forselect /*+ ordered */ e.deptno,
            d.deptnofrom emp e,
            dept dwhere e.deptno = d.deptnoorder by e.deptno,
            d.deptno;
            Query Plan-------------------------------------
            SELECT STATEMENT [CHOOSE] Cost=17
            MERGE JOINSORT JOINTABLE ACCESS FULL EMP
            [ANALYZED]SORT JOINTABLE ACCESS FULL DEPT [ANALYZED]</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">排序是一个费时、费资源的操作，特别对于大表。基于这个原因，SMJ经常不是一个特别有效的连接方法，但是如果2个row source都已经预先排序，则这种连接方法的效率也是蛮高的。
<p style="TEXT-INDENT: 2em">嵌套循环(Nested Loops, NL)
<p style="TEXT-INDENT: 2em">这个连接方法有驱动表(外部表)的概念。其实，该连接过程就是一个2层嵌套循环，所以外层循环的次数越少越好，这也就是我们为什么将小表或返回较小row source的表作为驱动表(用于外层循环)的理论依据。但是这个理论只是一般指导原则，因为遵循这个理论并不能总保证使语句产生的I/O次数最少。有时不遵守这个理论依据，反而会获得更好的效率。如果使用这种方法，决定使用哪个表作为驱动表很重要。有时如果驱动表选择不正确，将会导致语句的性能很差、很差。
<p style="TEXT-INDENT: 2em">内部连接过程：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>Row source1的Row 1 ---------------- Probe -&gt;Row source 2
            Row source1的Row 2 ---------------- Probe -&gt;Row source 2
            Row source1的Row 3 ---------------- Probe -&gt;Row source 2
            &#8230;&#8230;.
            Row source1的Row n ---------------- Probe -&gt;Row source 2</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">从内部连接过程来看，需要用row source1中的每一行，去匹配row source2中的所有行，所以此时保持row source1尽可能的小与高效的访问row source2(一般通过索引实现)是影响这个连接效率的关键问题。这只是理论指导原则，目的是使整个连接操作产生最少的物理I/O次数，而且如果遵守这个原则，一般也会使总的物理I/O数最少。但是如果不遵从这个指导原则，反而能用更少的物理I/O实现连接操作，那尽管违反指导原则吧！因为最少的物理I/O次数才是我们应该遵从的真正的指导原则，在后面的具体案例分析中就给出这样的例子。
<p style="TEXT-INDENT: 2em">在上面的连接过程中，我们称Row source1为驱动表或外部表。Row Source2被称为被探查表或内部表。
<p style="TEXT-INDENT: 2em">在NESTED LOOPS连接中，Oracle读取row source1中的每一行，然后在row sourc2中检查是否有匹配的行，所有被匹配的行都被放到结果集中，然后处理row source1中的下一行。这个过程一直继续，直到row source1中的所有行都被处理。这是从连接操作中可以得到第一个匹配行的最快的方法之一，这种类型的连接可以用在需要快速响应的语句中，以响应速度为主要目标。
<p style="TEXT-INDENT: 2em">如果driving row source(外部表)比较小，并且在inner row source(内部表)上有唯一索引，或有高选择性非唯一索引时，使用这种方法可以得到较好的效率。NESTED LOOPS有其它连接方法没有的的一个优点是：可以先返回已经连接的行，而不必等待所有的连接操作处理完才返回数据，这可以实现快速的响应时间。
<p style="TEXT-INDENT: 2em">如果不使用并行操作，最好的驱动表是那些应用了where 限制条件后，可以返回较少行数据的的表，所以大表也可能称为驱动表，关键看限制条件。对于并行查询，我们经常选择大表作为驱动表，因为大表可以充分利用并行功能。当然，有时对查询使用并行操作并不一定会比查询不使用并行操作效率高，因为最后可能每个表只有很少的行符合限制条件，而且还要看你的硬件配置是否可以支持并行(如是否有多个CPU，多个硬盘控制器)，所以要具体问题具体对待。
<p style="TEXT-INDENT: 2em">NL连接的例子：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan forselect a.dname,
            b.sqlfrom dept a,emp bwhere a.deptno = b.deptno;
            Query Plan-------------------------
            SELECT STATEMENT [CHOOSE]
            Cost=5NESTED LOOPSTABLE ACCESS FULL DEPT
            [ANALYZED]TABLE ACCESS FULL EMP [ANALYZED]</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>哈希连接(Hash Join, HJ)
<p style="TEXT-INDENT: 2em">这种连接是在oracle 7.3以后引入的，从理论上来说比NL与SMJ更高效，而且只用在CBO优化器中。
<p style="TEXT-INDENT: 2em">较小的row source被用来构建hash table与bitmap，第2个row source被用来被hansed，并与第一个row source生成的hash table进行匹配，以便进行进一步的连接。Bitmap被用来作为一种比较快的查找方法，来检查在hash table中是否有匹配的行。特别的，当hash table比较大而不能全部容纳在内存中时，这种查找方法更为有用。这种连接方法也有NL连接中所谓的驱动表的概念，被构建为hash table与bitmap的表为驱动表，当被构建的hash table与bitmap能被容纳在内存中时，这种连接方式的效率极高。
<p style="TEXT-INDENT: 2em">HASH连接的例子：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan forselect /*+ use_hash(emp) */
            empno from emp, deptwhere emp.deptno = dept.deptno;
            Query Plan----------------------------
            SELECT STATEMENT[CHOOSE] Cost=3
            HASH JOINTABLE ACCESS FULL DEPTTABLE ACCESS FULL EMP</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">要使哈希连接有效，需要设置HASH_JOIN_ENABLED=TRUE，缺省情况下该参数为TRUE，另外，不要忘了还要设置hash_area_size参数，以使哈希连接高效运行，因为哈希连接会在该参数指定大小的内存中运行，过小的参数会使哈希连接的性能比其他连接方式还要低。
<p style="TEXT-INDENT: 2em">总结一下，在哪种情况下用哪种连接方法比较好：
<p style="TEXT-INDENT: 2em">排序 - - 合并连接(Sort Merge Join, SMJ)：
<p style="TEXT-INDENT: 2em">a) 对于非等值连接，这种连接方式的效率是比较高的。
<p style="TEXT-INDENT: 2em">b) 如果在关联的列上都有索引，效果更好。
<p style="TEXT-INDENT: 2em">c) 对于将2个较大的row source做连接，该连接方法比NL连接要好一些。
<p style="TEXT-INDENT: 2em">d) 但是如果sort merge返回的row source过大，则又会导致使用过多的rowid在表中查询数据时，数据库性能下降，因为过多的I/O。
<p style="TEXT-INDENT: 2em">嵌套循环(Nested Loops, NL)：
<p style="TEXT-INDENT: 2em">a) 如果driving row source(外部表)比较小，并且在inner row source(内部表)上有唯一索引，或有高选择性非唯一索引时，使用这种方法可以得到较好的效率。
<p style="TEXT-INDENT: 2em">b) NESTED LOOPS有其它连接方法没有的的一个优点是：可以先返回已经连接的行，而不必等待所有的连接操作处理完才返回数据，这可以实现快速的响应时间。
<p style="TEXT-INDENT: 2em">哈希连接(Hash Join, HJ)：
<p style="TEXT-INDENT: 2em">a) 这种方法是在oracle7后来引入的，使用了比较先进的连接理论，一般来说，其效率应该好于其它2种连接，但是这种连接只能用在CBO优化器中，而且需要设置合适的hash_area_size参数，才能取得较好的性能。
<p style="TEXT-INDENT: 2em">b) 在2个较大的row source之间连接时会取得相对较好的效率，在一个row source较小时则能取得更好的效率。
<p style="TEXT-INDENT: 2em">c) 只能用于等值连接中
<p style="TEXT-INDENT: 2em">笛卡儿乘积(Cartesian Product)
<p style="TEXT-INDENT: 2em">当两个row source做连接，但是它们之间没有关联条件时，就会在两个row source中做笛卡儿乘积，这通常由编写代码疏漏造成(即程序员忘了写关联条件)。笛卡尔乘积是一个表的每一行依次与另一个表中的所有行匹配。在特殊情况下我们可以使用笛卡儿乘积，如在星形连接中，除此之外，我们要尽量使用笛卡儿乘积，否则，自己想结果是什么吧！
<p style="TEXT-INDENT: 2em">注意在下面的语句中，在2个表之间没有连接。
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan forselect emp.deptno,dept,deptno from emp,dept
            Query Plan------------------------
            SLECT STATEMENT [CHOOSE] Cost=5
            MERGE JOIN CARTESIANTABLE ACCESS FULL DEPTSORT JOINTABLE ACCESS FULL EMP</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">CARTESIAN关键字指出了在2个表之间做笛卡尔乘积。假如表emp有n行，dept表有m行，笛卡尔乘积的结果就是得到n * m行结果</p>
<img src ="http://www.blogjava.net/franlk/aggbug/122147.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-06-05 15:28 <a href="http://www.blogjava.net/franlk/articles/122147.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Oracle数据库执行计划的一些基本概念 （1）</title><link>http://www.blogjava.net/franlk/articles/122144.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 05 Jun 2007 07:27:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/122144.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/122144.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/122144.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/122144.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/122144.html</trackback:ping><description><![CDATA[<br>摘录地址:http://www.pcdog.com/edu/oracle/2006/11/b174439.html<br><br>
<p style="TEXT-INDENT: 2em"><strong>一．相关的概念</strong>
<p style="TEXT-INDENT: 2em">Rowid的概念：rowid是一个伪列，既然是伪列，那么这个列就不是用户定义，而是系统自己给加上的。对每个表都有一个rowid的伪列，但是表中并不物理存储ROWID列的值。 不过你可以像使用其它列那样使用它，但是不能删除改列，也不能对该列的值进行修改、插入。一旦一行数据插入数据库，则rowid在该行的生命周期内是唯一的，即即使该行产生行迁移，行的rowid也不会改变。
<p style="TEXT-INDENT: 2em">Recursive SQL概念：有时为了执行用户发出的一个sql语句，Oracle必须执行一些额外的语句，我们将这些额外的语句称之为'recursive calls'或'recursive SQL statements'。如当一个DDL语句发出后，ORACLE总是隐含的发出一些recursive SQL语句，来修改数据字典信息，以便用户可以成功的执行该DDL语句。当需要的数据字典信息没有在共享内存中时，经常会发生Recursive calls，这些Recursive calls会将数据字典信息从硬盘读入内存中。用户不比关心这些recursive SQL语句的执行情况，在需要的时候，ORACLE会自动的在内部执行这些语句。当然DML语句与SELECT都可能引起recursive SQL。简单的说，我们可以将触发器视为recursive SQL。
<p style="TEXT-INDENT: 2em">Row Source(行源)：用在查询中，由上一操作返回的符合条件的行的集合，即可以是表的全部行数据的集合；也可以是表的部分行数据的集合；也可以为对上2个row source进行连接操作(如join连接)后得到的行数据集合。
<p style="TEXT-INDENT: 2em">Predicate(谓词)：一个查询中的WHERE限制条件
<p style="TEXT-INDENT: 2em">Driving Table(驱动表)：该表又称为外层表(OUTER TABLE)。这个概念用于嵌套与HASH连接中。如果该row source返回较多的行数据，则对所有的后续操作有负面影响。注意此处虽然翻译为驱动表，但实际上翻译为驱动行源(driving row source)更为确切。一般说来，是应用查询的限制条件后，返回较少行源的表作为驱动表，所以如果一个大表在WHERE条件有有限制条件(如等值限制)，则该大表作为驱动表也是合适的，所以并不是只有较小的表可以作为驱动表，正确说法应该为应用查询的限制条件后，返回较少行源的表作为驱动表。在执行计划中，应该为靠上的那个row source，后面会给出具体说明。在我们后面的描述中，一般将该表称为连接操作的row source 1。
<p style="TEXT-INDENT: 2em">Probed Table(被探查表)：该表又称为内层表(INNER TABLE)。在我们从驱动表中得到具体一行的数据后，在该表中寻找符合连接条件的行。所以该表应当为大表(实际上应该为返回较大row source的表)且相应的列上应该有索引。在我们后面的描述中，一般将该表称为连接操作的row source 2。
<p style="TEXT-INDENT: 2em">组合索引(concatenated index)：由多个列构成的索引，如create index idx_emp on emp(col1, col2, col3, &#8230;&#8230;)，则我们称idx_emp索引为组合索引。在组合索引中有一个重要的概念：引导列(leading column)，在上面的例子中，col1列为引导列。当我们进行查询时可以使用&#8221;where col1 = ? &#8221;，也可以使用&#8221;where col1 = ? and col2 = ?&#8221;，这样的限制条件都会使用索引，但是&#8221;where col2 = ? &#8221;查询就不会使用该索引。所以限制条件中包含先导列时，该限制条件才会使用该组合索引。
<p style="TEXT-INDENT: 2em">可选择性(selectivity)：比较一下列中唯一键的数量和表中的行数，就可以判断该列的可选择性。如果该列的&#8221;唯一键的数量/表中的行数&#8221;的比值越接近1，则该列的可选择性越高，该列就越适合创建索引，同样索引的可选择性也越高。在可选择性高的列上进行查询时，返回的数据就较少，比较适合使用索引查询。
<p style="TEXT-INDENT: 2em"><strong>二．oracle访问数据的存取方法</strong>
<p style="TEXT-INDENT: 2em">1) 全表扫描（Full Table Scans, FTS）
<p style="TEXT-INDENT: 2em">为实现全表扫描，Oracle读取表中所有的行，并检查每一行是否满足语句的WHERE限制条件一个多块读操作可以使一次I/O能读取多块数据块(db_block_multiblock_read_count参数设定)，而不是只读取一个数据块，这极大的减少了I/O总次数，提高了系统的吞吐量，所以利用多块读的方法可以十分高效地实现全表扫描，而且只有在全表扫描的情况下才能使用多块读操作。在这种访问模式下，每个数据块只被读一次。
<p style="TEXT-INDENT: 2em">使用FTS的前提条件：在较大的表上不建议使用全表扫描，除非取出数据的比较多，超过总量的5% -- 10%，或你想使用并行查询功能时。
<p style="TEXT-INDENT: 2em">使用全表扫描的例子：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan for select * from dual;
            Query Plan-------------------------------
            SELECT STATEMENT[CHOOSE]
            Cost=TABLE ACCESS FULL DUAL</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">2) 通过ROWID的表存取（Table Access by ROWID或rowid lookup）
<p style="TEXT-INDENT: 2em">行的ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置，所以通过ROWID来存取数据可以快速定位到目标数据上，是Oracle存取单行数据的最快方法。
<p style="TEXT-INDENT: 2em">这种存取方法不会用到多块读操作，一次I/O只能读取一个数据块。我们会经常在执行计划中看到该存取方法，如通过索引查询数据。
<p style="TEXT-INDENT: 2em">使用ROWID存取的方法：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan for select * from dept
            where rowid = 'AAAAyGAADAAAAATAAF';
            Query Plan------------------------------------
            SELECT STATEMENT [CHOOSE] Cost=1
            TABLE ACCESS BY ROWID DEPT [ANALYZED]</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">3）索引扫描（Index Scan或index lookup）
<p style="TEXT-INDENT: 2em">我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值)，然后根据rowid直接从表中得到具体的数据，这种查找方式称为索引扫描或索引查找(index lookup)。一个rowid唯一的表示一行数据，该行对应的数据块是通过一次i/o得到的，在此情况下该次i/o只会读取一个数据库块。
<p style="TEXT-INDENT: 2em">在索引中，除了存储每个索引的值外，索引还存储具有此值的行对应的ROWID值。索引扫描可以由2步组成：(1) 扫描索引得到对应的rowid值。 (2) 通过找到的rowid从表中读出具体的数据。每步都是单独的一次I/O，但是对于索引，由于经常使用，绝大多数都已经CACHE到内存中，所以第1步的I/O经常是逻辑I/O，即数据可以从内存中得到。但是对于第2步来说，如果表比较大，则其数据不可能全在内存中，所以其I/O很有可能是物理I/O，这是一个机械操作，相对逻辑I/O来说，是极其费时间的。所以如果多大表进行索引扫描，取出的数据如果大于总量的5% -- 10%，使用索引扫描会效率下降很多。如下列所示：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan for select empno,
            ename from emp where empno=10;
            Query Plan-------------------------
            SELECT STATEMENT [CHOOSE] Cost=1
            TABLE ACCESS BY ROWID EMP [ANALYZED]
            INDEX UNIQUE SCAN EMP_I1</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">但是如果查询的数据能全在索引中找到，就可以避免进行第2步操作，避免了不必要的I/O，此时即使通过索引扫描取出的数据比较多，效率还是很高的
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan for select empno from emp where empno=10;
            -- 只查询empno列值
            Query Plan------------------------------------
            SELECT STATEMENT [CHOOSE] Cost=1INDEX UNIQUE SCAN EMP_I1</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">进一步讲，如果sql语句中对索引列进行排序，因为索引已经预先排序好了，所以在执行计划中不需要再对索引列进行排序
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan for select empno,
            ename from empwhere empno &gt; 7876 order by empno;
            Query Plan--------------------------------------
            SELECT STATEMENT[CHOOSE] Cost=1
            TABLE ACCESS BY ROWID EMP [ANALYZED]
            INDEX RANGE SCAN EMP_I1 [ANALYZED]</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">从这个例子中可以看到：因为索引是已经排序了的，所以将按照索引的顺序查询出符合条件的行，因此避免了进一步排序操作。
<p style="TEXT-INDENT: 2em">根据索引的类型与where限制条件的不同，有4种类型的索引扫描：
<p style="TEXT-INDENT: 2em">索引唯一扫描(index unique scan)
<p style="TEXT-INDENT: 2em">索引范围扫描(index range scan)
<p style="TEXT-INDENT: 2em">索引全扫描(index full scan)
<p style="TEXT-INDENT: 2em">索引快速扫描(index fast full scan)
<p style="TEXT-INDENT: 2em">(1) 索引唯一扫描(index unique scan)
<p style="TEXT-INDENT: 2em">通过唯一索引查找一个数值经常返回单个ROWID。如果存在UNIQUE 或PRIMARY KEY 约束（它保证了语句只存取单行）的话，Oracle经常实现唯一性扫描。
<p style="TEXT-INDENT: 2em">使用唯一性约束的例子：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan for
            select empno,ename from emp where empno=10;
            Query Plan
            ------------------------------------
            SELECT STATEMENT [CHOOSE] Cost=1
            TABLE ACCESS BY ROWID EMP [ANALYZED]
            INDEX UNIQUE SCAN EMP_I1</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">(2) 索引范围扫描(index range scan)
<p style="TEXT-INDENT: 2em">使用一个索引存取多行数据，在唯一索引上使用索引范围扫描的典型情况下是在谓词(where限制条件)中使用了范围操作符(如&gt;、&lt;、&lt;&gt;、&gt;=、&lt;=、between)
<p style="TEXT-INDENT: 2em">使用索引范围扫描的例子：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan for select empno,
            ename from empwhere empno &gt; 7876 order by empno;
            Query Plan-------------------------------------
            SELECT STATEMENT[CHOOSE] Cost=1
            TABLE ACCESS BY ROWID EMP [ANALYZED]
            INDEX RANGE SCAN EMP_I1 [ANALYZED]</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">在非唯一索引上，谓词col = 5可能返回多行数据，所以在非唯一索引上都使用索引范围扫描。
<p style="TEXT-INDENT: 2em">使用index rang scan的3种情况：
<p style="TEXT-INDENT: 2em">(a) 在唯一索引列上使用了range操作符(&gt; &lt; &lt;&gt; &gt;= &lt;= between)
<p style="TEXT-INDENT: 2em">(b) 在组合索引上，只使用部分列进行查询，导致查询出多行
<p style="TEXT-INDENT: 2em">(c) 对非唯一索引列上进行的任何查询。
<p style="TEXT-INDENT: 2em">(3) 索引全扫描(index full scan)
<p style="TEXT-INDENT: 2em">与全表扫描对应，也有相应的全索引扫描。而且此时查询出的数据都必须从索引中可以直接得到。
<p style="TEXT-INDENT: 2em">全索引扫描的例子：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>An Index full scan will not perform single block
            i/o's and so it may prove to be inefficient.
            e.g.Index BE_IX is a concatenated index on big_emp (empno, ename)
            SQL&gt; explain plan for select empno, ename from big_emp order by empno,
            ename;Query Plan--------------------------
            SELECT STATEMENT[CHOOSE] Cost=26
            INDEX FULL SCAN BE_IX [ANALYZED]</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">(4) 索引快速扫描(index fast full scan)
<p style="TEXT-INDENT: 2em">扫描索引中的所有的数据块，与 index full scan很类似，但是一个显著的区别就是它不对查询出的数据进行排序，即数据不是以排序顺序被返回。在这种存取方法中，可以使用多块读功能，也可以使用并行读入，以便获得最大吞吐量与缩短执行时间。
<p style="TEXT-INDENT: 2em">索引快速扫描的例子：
<p style="TEXT-INDENT: 2em">BE_IX索引是一个多列索引：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>big_emp (empno,ename)
            SQL&gt; explain plan for select empno,
            ename from big_emp;
            Query Plan--------------------------
            SELECT STATEMENT[CHOOSE] Cost=1
            INDEX FAST FULL SCAN BE_IX [ANALYZED]</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p style="TEXT-INDENT: 2em">只选择多列索引的第2列：
<p style="TEXT-INDENT: 2em">
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>SQL&gt; explain plan for select ename from big_emp;
            Query Plan--------------------------------------
            SELECT STATEMENT[CHOOSE] Cost=1
            INDEX FAST FULL SCAN BE_IX [ANALYZED]</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<img src ="http://www.blogjava.net/franlk/aggbug/122144.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-06-05 15:27 <a href="http://www.blogjava.net/franlk/articles/122144.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]oracle函数手册(1)</title><link>http://www.blogjava.net/franlk/articles/121072.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Thu, 31 May 2007 01:46:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/121072.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/121072.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/121072.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/121072.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/121072.html</trackback:ping><description><![CDATA[&nbsp;摘录地址：<a href="http://www.channel7.cn/2004/10-20/203215.html">http://www.channel7.cn/2004/10-20/203215.html</a><br><br>PL/SQL单行函数和组函数详解<br>　函数是一种有零个或多个参数并且有一个返回值的程序。在SQL中Oracle内建了一系列函数，这些函数都可被称为SQL或PL/SQL语句，函数主要分为两大类：
<p>　　 单行函数</p>
<p>　　 组函数 </p>
<p>　　本文将讨论如何利用单行函数以及使用规则。</p>
<p>　　SQL中的单行函数</p>
<p>　　SQL和PL/SQL中自带很多类型的函数，有字符、数字、日期、转换、和混合型等多种函数用于处理单行数据，因此这些都可被统称为单行函数。这些函数均可用于SELECT,WHERE、ORDER BY等子句中，例如下面的例子中就包含了TO_CHAR,UPPER,SOUNDEX等单行函数。<br>SELECT ename,TO_CHAR(hiredate,'day,DD-Mon-YYYY')FROM empWhere UPPER(ename) Like 'AL%'ORDER BY SOUNDEX(ename)</p>
<p>　　单行函数也可以在其他语句中使用，如update的SET子句，INSERT的VALUES子句，DELET的WHERE子句,认证考试特别注意在SELECT语句中使用这些函数，所以我们的注意力也集中在SELECT语句中。</p>
<p>　　NULL和单行函数</p>
<p>　　在如何理解NULL上开始是很困难的，就算是一个很有经验的人依然对此感到困惑。NULL值表示一个未知数据或者一个空值，算术操作符的任何一个操作数为NULL值，结果均为提个NULL值,这个规则也适合很多函数，只有CONCAT,DECODE,DUMP,NVL,REPLACE在调用了NULL参数时能够返回非NULL值。在这些中NVL函数时最重要的，因为他能直接处理NULL值，NVL有两个参数：NVL(x1,x2),x1和x2都式表达式，当x1为null时返回X2,否则返回x1。</p>
<p>　　下面我们看看emp数据表它包含了薪水、奖金两项，需要计算总的补偿<br>column name emp_id salary bonuskey type pk nulls/unique nn,u nnfk table datatype number number numberlength 11.2 11.2</p>
<p>　　不是简单的将薪水和奖金加起来就可以了，如果某一行是null值那么结果就将是null，比如下面的例子：<br>update empset salary=(salary+bonus)*1.1</p>
<p>　　这个语句中，雇员的工资和奖金都将更新为一个新的值，但是如果没有奖金，即 salary + null,那么就会得出错误的结论，这个时候就要使用nvl函数来排除null值的影响。<br>所以正确的语句是：<br>update empset salary=(salary+nvl(bonus,0)*1.1<br>单行字符串函数</p>
<p>　　单行字符串函数用于操作字符串数据，他们大多数有一个或多个参数，其中绝大多数返回字符串</p>
<p>　　ASCII()<br>　　c1是一字符串，返回c1第一个字母的ASCII码，他的逆函数是CHR()<br>SELECT ASCII('A') BIG_A,ASCII('z') BIG_z FROM empBIG_A BIG_z65 122</p>
<p>　　CHR(＜i＞)[NCHAR_CS]<br>　　i是一个数字，函数返回十进制表示的字符<br>select CHR(65),CHR(122),CHR(223) FROM empCHR65 CHR122 CHR223A z B</p>
<p>　　CONCAT(,)<br>　　c1,c2均为字符串，函数将c2连接到c1的后面，如果c1为null,将返回c2.如果c2为null,则返回c1，如果c1、c2都为null，则返回null。他和操作符||返回的结果相同<br>select concat('slobo ','Svoboda') username from dualusernameslobo Syoboda</p>
<p>　　INITCAP()<br>　　c1为一字符串。函数将每个单词的第一个字母大写其它字母小写返回。单词由空格，控制字符，标点符号限制。<br>select INITCAP('veni,vedi,vici') Ceasar from dualCeasarVeni,Vedi,Vici</p>
<p>　　INSTR(,[,＜i＞[,]])<br>　　c1,c2均为字符串，i,j为整数。函数返回c2在c1中第j次出现的位置，搜索从c1的第i个字符开始。当没有发现需要的字符时返回0,如果i为负数，那么搜索将从右到左进行，但是位置的计算还是从左到右，i和j的缺省值为1.<br>select INSTR('Mississippi','i',3,3) from dualINSTR('MISSISSIPPI','I',3,3)11select INSTR('Mississippi','i',-2,3) from dualINSTR('MISSISSIPPI','I',3,3)2</p>
<p>　　INSTRB(,[,i[,j])<br>　　与INSTR（）函数一样，只是他返回的是字节，对于单字节INSTRB()等于INSTR()</p>
<p>　　LENGTH()<br>　　c1为字符串，返回c1的长度，如果c1为null，那么将返回null值。<br>select LENGTH('Ipso Facto') ergo from dualergo10</p>
<p>　　LENGTHb()<br>　　与LENGTH()一样，返回字节。</p>
<p>　　lower()<br>　　返回c的小写字符，经常出现在where子串中<br>select LOWER(colorname) from itemdetail WHERE LOWER(colorname) LIKE '%white%'COLORNAMEWinterwhite</p>
<p>　　LPAD(,＜i＞[,])<br>　　c1,c2均为字符串，i为整数。在c1的左侧用c2字符串补足致长度i,可多次重复，如果i小于c1的长度，那么只返回i那么长的c1字符，其他的将被截去。c2的缺省值为单空格，参见RPAD。<br>select LPAD(answer,7,'') padded,answer unpadded from question;PADDED UNPADDED Yes YesNO NOMaybe maybe</p>
<p>　　LTRIM(,)<br>　　把c1中最左边的字符去掉，使其第一个字符不在c2中，如果没有c2，那么c1就不会改变。<br>select LTRIM('Mississippi','Mis') from dualLTRppi</p>
<p>　　RPAD(,＜i＞[,]) <br>　　在c1的右侧用c2字符串补足致长度i,可多次重复，如果i小于c1的长度，那么只返回i那么长的c1字符，其他的将被截去。c2的缺省值为单空格,其他与LPAD相似</p>
<p>　　RTRIM(,)<br>　　把c1中最右边的字符去掉，使其第后一个字符不在c2中，如果没有c2，那么c1就不会改变。</p>
<p>　　REPLACE(,[,])<br>　　c1,c2,c3都是字符串，函数用c3代替出现在c1中的c2后返回。<br>select REPLACE('uptown','up','down') from dualREPLACEdowntown</p>
<p>　　STBSTR(,＜i＞[,])<br>　　c1为一字符串，i,j为整数，从c1的第i位开始返回长度为j的子字符串，如果j为空，则直到串的尾部。<br>select SUBSTR('Message',1,4) from dualSUBSMess</p>
<p>　　SUBSTRB(,＜i＞[,])<br>　　与SUBSTR大致相同，只是I,J是以字节计算。</p>
<p>　　SOUNDEX()<br>　　返回与c1发音相似的词<br>select SOUNDEX('dawes') Dawes SOUNDEX('daws') Daws, SOUNDEX('dawson') from dualDawes Daws DawsonD200 D200 D250</p>
<p>　　TRANSLATE(,,)<br>　　将c1中与c2相同的字符以c3代替<br>select TRANSLATE('fumble','uf','ar') test from dualTEXTramble </p>
<p>　　TRIM([[]] from c3)<br>　　将c3串中的第一个，最后一个，或者都删除。<br>select TRIM(' space padded ') trim from dual TRIMspace padded</p>
<p>　　UPPER()<br>　　返回c1的大写，常出现where子串中<br>select name from dual where UPPER(name) LIKE 'KI%'NAMEKING<br>单行数字函数</p>
<p>　　单行数字函数操作数字数据，执行数学和算术运算。所有函数都有数字参数并返回数字值。所有三角函数的操作数和值都是弧度而不是角度，oracle没有提供内建的弧度和角度的转换函数。 </p>
<p>&#160;</p>
<p>　　ABS()<br>　　返回n的绝对值</p>
<p>　　ACOS()<br>　　反余玄函数，返回-1到1之间的数。n表示弧度<br>select ACOS(-1) pi,ACOS(1) ZERO FROM dualPI ZERO3.14159265 0 </p>
<p>　　ASIN()<br>　　反正玄函数，返回-1到1，n表示弧度</p>
<p>　　ATAN()<br>　　反正切函数，返回n的反正切值，n表示弧度。</p>
<p>　　CEIL()<br>　　返回大于或等于n的最小整数。</p>
<p>　　COS()<br>　　返回n的余玄值，n为弧度</p>
<p>　　COSH()<br>　　返回n的双曲余玄值，n 为数字。<br>select COSH(&lt;1.4&gt;) FROM dualCOSH(1.4)2.15089847</p>
<p>　　EXP()<br>　　返回e的n次幂，e=2.71828183.</p>
<p>　　FLOOR()<br>　　返回小于等于N的最大整数。</p>
<p>　　LN()<br>　　返回N的自然对数，N必须大于0</p>
<p>　　LOG(,)<br>　　返回以n1为底n2的对数</p>
<p>　　MOD()<br>　　返回n1除以n2的余数，</p>
<p>　　POWER(,)<br>　　返回n1的n2次方</p>
<p>　　ROUND(,)<br>　　返回舍入小数点右边n2位的n1的值，n2的缺省值为0，这回将小数点最接近的整数，如果n2为负数就舍入到小数点左边相应的位上，n2必须是整数。<br>select ROUND(12345,-2),ROUND(12345.54321,2) FROM dualROUND(12345,-2) ROUND(12345.54321,2)12300 12345.54</p>
<p>　　SIGN()<br>　　如果n为负数，返回-1,如果n为正数，返回1，如果n=0返回0.</p>
<p>　　SIN（)<br>　　返回n的正玄值,n为弧度。</p>
<p>　　SINH()<br>　　返回n的双曲正玄值,n为弧度。</p>
<p>　　SQRT()<br>　　返回n的平方根,n为弧度</p>
<p>　　TAN（)<br>　　返回n的正切值,n为弧度</p>
<p>　　TANH()<br>　　返回n的双曲正切值,n为弧度</p>
<p>　　TRUNC(,)<br>　　返回截尾到n2位小数的n1的值，n2缺省设置为0，当n2为缺省设置时会将n1截尾为整数，如果n2为负值，就截尾在小数点左边相应的位上。</p>
<p>　　单行日期函数</p>
<p>　　单行日期函数操作DATA数据类型，绝大多数都有DATA数据类型的参数，绝大多数返回的也是DATA数据类型的值。</p>
<p>　　ADD_MONTHS(,＜i＞)<br>　　返回日期d加上i个月后的结果。i可以使任意整数。如果i是一个小数，那么数据库将隐式的他转换成整数，将会截去小数点后面的部分。</p>
<p>　　LAST_DAY()<br>　　函数返回包含日期d的月份的最后一天 </p>
<p>　　MONTHS_BETWEEN(,)<br>　　返回d1和d2之间月的数目,如果d1和d2的日的日期都相同，或者都使该月的最后一天，那么将返回一个整数，否则会返回的结果将包含一个分数。</p>
<p>　　NEW_TIME(,,)<br>　　d1是一个日期数据类型，当时区tz1中的日期和时间是d时，返回时区tz2中的日期和时间。tz1和tz2时字符串。</p>
<p>　　NEXT_DAY(,)<br>　　返回日期d后由dow给出的条件的第一天，dow使用当前会话中给出的语言指定了一周中的某一天，返回的时间分量与d的时间分量相同。<br>select NEXT_DAY('01-Jan-2000','Monday') "1st Monday",NEXT_DAY('01-Nov-2004','Tuesday')+7 "2nd Tuesday") from dual;1st Monday 2nd Tuesday03-Jan-2000 09-Nov-2004 </p>
<p>　　ROUND([,])<br>　　将日期d按照fmt指定的格式舍入，fmt为字符串。</p>
<p>　　SYADATE<br>　　函数没有参数，返回当前日期和时间。</p>
<p>　　TRUNC([,]) <br>　　返回由fmt指定的单位的日期d.<br>单行转换函数</p>
<p>　　单行转换函数用于操作多数据类型，在数据类型之间进行转换。</p>
<p>　　CHARTORWID()<br>　　c 使一个字符串，函数将c转换为RWID数据类型。<br>SELECT test_id from test_case where rowid=CHARTORWID('AAAA0SAACAAAALiAAA') </p>
<p>　　CONVERT(,[,])<br>　　c尾字符串，dset、sset是两个字符集，函数将字符串c由sset字符集转换为dset字符集，sset的缺省设置为数据库的字符集。</p>
<p>　　HEXTORAW()<br>　　x为16进制的字符串，函数将16进制的x转换为RAW数据类型。</p>
<p>　　RAWTOHEX()<br>　　x是RAW数据类型字符串，函数将RAW数据类转换为16进制的数据类型。</p>
<p>　　ROWIDTOCHAR()<br>　　函数将ROWID数据类型转换为CHAR数据类型。</p>
<p>　　TO_CHAR([[,)<br>　　x是一个data或number数据类型，函数将x转换成fmt指定格式的char数据类型，如果x为日期nlsparm=NLS_DATE_LANGUAGE 控制返回的月份和日份所使用的语言。如果x为数字nlsparm=NLS_NUMERIC_CHARACTERS 用来指定小数位和千分位的分隔符，以及货币符号。<br>NLS_NUMERIC_CHARACTERS ="dg", NLS_CURRENCY="string"</p>
<p>　　TO_DATE([,[,）<br>　　c表示字符串，fmt表示一种特殊格式的字符串。返回按照fmt格式显示的c,nlsparm表示使用的语言。函数将字符串c转换成date数据类型。</p>
<p>　　TO_MULTI_BYTE()<br>　　c表示一个字符串，函数将c的担子截字符转换成多字节字符。</p>
<p>　　TO_NUMBER([,[,)<br>　　c表示字符串，fmt表示一个特殊格式的字符串，函数返回值按照fmt指定的格式显示。nlsparm表示语言，函数将返回c代表的数字。</p>
<p>　　TO_SINGLE_BYTE()<br>　　将字符串c中得多字节字符转化成等价的单字节字符。该函数仅当数据库字符集同时包含单字节和多字节字符时才使用</p>
<p>　　其它单行函数</p>
<p>　　BFILENAME( <br>,)<br>　　dir是一个directory类型的对象，file为一文件名。函数返回一个空的BFILE位置值指示符，函数用于初始化BFILE变量或者是BFILE列。</p>
<p>　　DECODE(,,[,,,[])<br>　　x是一个表达式，m1是一个匹配表达式，x与m1比较，如果m1等于x，那么返回r1,否则,x与m2比较，依次类推m3,m4,m5....直到有返回结果。</p>
<p>　　DUMP(,[,[,[,]]])<br>　　x是一个表达式或字符，fmt表示8进制、10进制、16进制、或则单字符。函数返回包含了有关x的内部表示信息的VARCHAR2类型的值。如果指定了n1,n2那么从n1开始的长度为n2的字节将被返回。</p>
<p>　　EMPTY_BLOB()<br>　　该函数没有参数，函数返回 一个空的BLOB位置指示符。函数用于初始化一个BLOB变量或BLOB列。</p>
<p>　　EMPTY_CLOB()<br>　　该函数没有参数，函数返回 一个空的CLOB位置指示符。函数用于初始化一个CLOB变量或CLOB列。</p>
<p>　　GREATEST()<br>　　exp_list是一列表达式，返回其中最大的表达式，每个表达式都被隐含的转换第一个表达式的数据类型，如果第一个表达式是字符串数据类型中的任何一个，那么返回的结果是varchar2数据类型，同时使用的比较是非填充空格类型的比较。</p>
<p>　　LEAST()<br>　　exp_list是一列表达式，返回其中最小的表达式，每个表达式都被隐含的转换第一个表达式的数据类型，如果第一个表达式是字符串数据类型中的任何一个，将返回的结果是varchar2数据类型，同时使用的比较是非填充空格类型的比较。</p>
<p>　　UID<br>　　该函数没有参数，返回唯一标示当前数据库用户的整数。</p>
<p>　　USER<br>　　返回当前用户的用户名</p>
<p>　　USERENV()<br>　　基于opt返回包含当前会话信息。opt的可选值为：</p>
<p>　　ISDBA　 　　会话中SYSDBA脚色响应，返回TRUE <br>　　SESSIONID 　返回审计会话标示符</p>
ENTRYID 　　返回可用的审计项标示符 <br>　　INSTANCE　　在会话连接后，返回实例标示符。该值只用于运行Parallel 服务器并且有 多个实例的情况下使用。<br>　　LANGUAGE　　返回语言、地域、数据库设置的字符集。<br>　　LANG　　　　返回语言名称的ISO缩写。<br>　　TERMINAL　　为当前会话使用的终端或计算机返回操作系统的标示符。
<p>&#160;</p>
<p>　　VSIZE()<br>　　x是一个表达式。返回x内部表示的字节数。<br>SQL中的组函数</p>
<p>　　组函数也叫集合函数，返回基于多个行的单一结果，行的准确数量无法确定，除非查询被执行并且所有的结果都被包含在内。与单行函数不同的是，在解析时所有的行都是已知的。由于这种差别使组函数与单行函数有在要求和行为上有微小的差异.</p>
<p>　　组（多行）函数</p>
<p>　　与单行函数相比，oracle提供了丰富的基于组的，多行的函数。这些函数可以在select或select的having子句中使用，当用于select子串时常常都和GROUP BY一起使用。</p>
<p>　　AVG([{DISYINCT|ALL}])<br>　　返回数值的平均值。缺省设置为ALL.<br>SELECT AVG(sal),AVG(ALL sal),AVG(DISTINCT sal) FROM scott.empAVG(SAL) AVG(ALL SAL) AVG(DISTINCT SAL)1877.94118 1877.94118 1916.071413</p>
<p>　　COUNT({*|DISTINCT|ALL} )<br>　　返回查询中行的数目，缺省设置是ALL,*表示返回所有的行。</p>
<p>　　MAX([{DISTINCT|ALL}])<br>　　返回选择列表项目的最大值，如果x是字符串数据类型，他返回一个VARCHAR2数据类型，如果X是一个DATA数据类型，返回一个日期，如果X是numeric数据类型，返回一个数字。注意distinct和all不起作用，应为最大值与这两种设置是相同的。</p>
<p>　　MIN([{DISTINCT|ALL}])<br>　　返回选择列表项目的最小值。</p>
<p>　　STDDEV([{DISTINCT|ALL}])<br>　　返回选者的列表项目的标准差，所谓标准差是方差的平方根。</p>
<p>　　SUM([{DISTINCT|ALL}])<br>　　返回选择列表项目的数值的总和。</p>
<p>　　VARIANCE([{DISTINCT|ALL}])<br>　　返回选择列表项目的统计方差。</p>
<p>　　用GROUP BY给数据分组</p>
<p>　　正如题目暗示的那样组函数就是操作那些已经分好组的数据，我们告诉数据库用GROUP BY怎样给数据分组或者分类，当我们在SELECT语句的SELECT子句中使用组函数时，我们必须把为分组或非常数列放置在GROUP BY子句中，如果没有用group by进行专门处理，那么缺省的分类是将整个结果设为一类。<br>select stat,counter(*) zip_count from zip_codes GROUP BY state;ST ZIP_COUNT-- ---------AK 360AL 1212AR 1309AZ 768CA 3982</p>
<p>　　在这个例子中，我们用state字段分类；如果我们要将结果按照zip_codes排序,可以用ORDER BY语句，ORDER BY子句可以使用列或组函数。<br>select stat,counter(*) zip_count from zip_codes GROUP BY state ORDER BY COUNT(*) DESC;ST COUNT(*)-- --------NY 4312PA 4297TX 4123CA 3982</p>
<p>　　用HAVING子句限制分组数据</p>
<p>　　现在你已经知道了在查询的SELECT语句和ORDER BY子句中使用主函数，组函数只能用于两个子串中，组函数不能用于WHERE子串中，例如下面的查询是错误的：<br>错误SELECT sales_clerk,SUN(sale_amount) FROM gross_sales WHERE sales_dept='OUTSIDE' AND SUM(sale_amount)&gt;10000 GROUP BY sales_clerk</p>
<p>　　这个语句中数据库不知道SUM()是什么，当我们需要指示数据库对行分组，然后限制分组后的行的输出时，正确的方法是使用HAVING语句：<br>SELECT sales_clerk,SUN(sale_amount) FROM gross_sales WHERE sales_dept='OUTSIDE' GROUP BY sales_clerkHAVING SUM(sale_amount)&gt;10000;</p>
<p>　　嵌套函数</p>
<p>　　函数可以嵌套。一个函数的输出可以是另一个函数的输入。操作数有一个可继承的执行过程。但函数的优先权只是基于位置，函数遵循由内到外，由左到右的原则。嵌套技术一般用于象DECODE这样的能被用于逻辑判断语句IF....THEN...ELSE的函数。</p>
<img src ="http://www.blogjava.net/franlk/aggbug/121072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-05-31 09:46 <a href="http://www.blogjava.net/franlk/articles/121072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Oracle 分析函数的使用(zt) </title><link>http://www.blogjava.net/franlk/articles/118286.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Fri, 18 May 2007 02:55:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/118286.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/118286.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/118286.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/118286.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/118286.html</trackback:ping><description><![CDATA[<br>摘录地址：<a style="COLOR: red" href="http://xsb.itpub.net/post/419/44634">http://xsb.itpub.net/post/419/44634</a><br><br><span class=bold><span class=smalltxt><font face=Arial size=2><strong>2/11/2005 09:43 FP</strong>Oracle <u><font color=#ff0000><strong>分析函数</strong></font></u>使用介绍<br><br>
<p><font size=2><u><strong><font color=#ff0000>分析函数</font></strong></u>是oracle816引入的一个全新的概念,为我们分析数据提供了一种简单高效的处理方式.在<u><strong><font color=#ff0000>分析函数</font></strong></u>出现以前,我们必须使用自联查询,子查询或者内联视图,甚至复杂的存储过程实现的语句,现在只要一条简单的sql语句就可以实现了,而且在执行效率方面也有相当大的提高.下面我将针对<u><strong><font color=#ff0000>分析函数</font></strong></u>做一些具体的说明.</font><strong><font face=Arial><font size=2><span class=bold><span class=smalltxt>基础数据</span></span></font></font></strong></p>
<p><font size=2>除本文内容外，你还可参考：<br>ROLLUP与CUBE <a href="http://xsb.itpub.net/post/419/29159"><font color=#007799>http://xsb.itpub.net/post/419/29159</font></a><br><font size=2>分析函数参考手册：<a href="http://xsb.itpub.net/post/419/33028"><font color=#007799>http://xsb.itpub.net/post/419/33028</font></a></font></font></p>
<p>今天我主要给大家介绍一下以下几个函数的使用方法<br>1. 自动汇总函数rollup,cube,<br>2. rank 函数, rank,dense_rank,row_number<br>3. lag,lead函数<br>4. sum,avg,的移动增加,移动平均数<br>5. ratio_to_report报表处理函数<br>6. first,last取基数的<u><strong><font color=#ff0000>分析函数</font></strong></u></p>
<center>
<table cellSpacing=0 cellPadding=0 width="90%" border=0>
    <tbody>
        <tr>
            <td class=smalltxt><font size=2>Code:</font></td>
            <td align=right></td>
        </tr>
        <tr>
            <td colSpan=2>
            <table cellSpacing=1 cellPadding=10 width="100%" bgColor=#efefcf border=0>
                <tbody>
                    <tr>
                        <td id=code0 style="WORD-BREAK: break-all" width="100%" bgColor=#ffffff><font size=2>06:34:23 SQL&gt; select * from t;<br><br>BILL_MONTH AREA_CODE NET_TYPE LOCAL_FARE<br>--------------- ---------- ---------- --------------<br>200405 5761 G 7393344.04<br>200405 5761 J 5667089.85<br>200405 5762 G 6315075.96<br>200405 5762 J 6328716.15<br>200405 5763 G 8861742.59<br>200405 5763 J 7788036.32<br>200405 5764 G 6028670.45<br>200405 5764 J 6459121.49<br>200405 5765 G 13156065.77<br>200405 5765 J 11901671.70<br>200406 5761 G 7614587.96<br>200406 5761 J 5704343.05<br>200406 5762 G 6556992.60<br>200406 5762 J 6238068.05<br>200406 5763 G 9130055.46<br>200406 5763 J 7990460.25<br>200406 5764 G 6387706.01<br>200406 5764 J 6907481.66<br>200406 5765 G 13562968.81<br>200406 5765 J 12495492.50<br>200407 5761 G 7987050.65<br>200407 5761 J 5723215.28<br>200407 5762 G 6833096.68<br>200407 5762 J 6391201.44<br>200407 5763 G 9410815.91<br>200407 5763 J 8076677.41<br>200407 5764 G 6456433.23<br>200407 5764 J 6987660.53<br>200407 5765 G 14000101.20<br>200407 5765 J 12301780.20<br>200408 5761 G 8085170.84<br>200408 5761 J 6050611.37<br>200408 5762 G 6854584.22<br>200408 5762 J 6521884.50<br>200408 5763 G 9468707.65<br>200408 5763 J 8460049.43<br>200408 5764 G 6587559.23<br><br>BILL_MONTH AREA_CODE NET_TYPE LOCAL_FARE<br>--------------- ---------- ---------- --------------<br>200408 5764 J 7342135.86<br>200408 5765 G 14450586.63<br>200408 5765 J 12680052.38<br><br>40 rows selected.<br><br>Elapsed: 00:00:00.00</font></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
</center><br><br><strong><font face=Arial><font size=2><span class=bold><span class=smalltxt>1. 使用rollup函数的介绍</span></span></font></font></strong>
<center>
<table cellSpacing=0 cellPadding=0 width="90%" border=0>
    <tbody>
        <tr>
            <td><font size=2>Quote:</font></td>
        </tr>
        <tr>
            <td>
            <table cellSpacing=1 cellPadding=10 width="100%" bgColor=#efefcf border=0>
                <tbody>
                    <tr>
                        <td width="100%" bgColor=#ffffff><font size=2><font color=#0000ff>下面是直接使用普通sql语句求出各地区的汇总数据的例子</font><br>06:41:36 SQL&gt; set autot on<br>06:43:36 SQL&gt; select area_code,sum(local_fare) local_fare<br>06:43:50 2 from t<br>06:43:51 3 group by area_code<br>06:43:57 4 union all<br>06:44:00 5 select '合计' area_code,sum(local_fare) local_fare<br>06:44:06 6 from t<br>06:44:08 7 /<br><br>AREA_CODE LOCAL_FARE<br>---------- --------------<br>5761 54225413.04<br>5762 52039619.60<br>5763 69186545.02<br>5764 53156768.46<br>5765 104548719.19<br>合计 333157065.31<br><br>6 rows selected.<br><br>Elapsed: 00:00:00.03<br><br>Execution Plan<br>----------------------------------------------------------<br>0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=1310 Bytes=<br>24884)<br><br>1 0 UNION-ALL<br>2 1 SORT (GROUP BY) (Cost=5 Card=1309 Bytes=24871)<br>3 2 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=1309 Bytes=248<br>71)<br><br>4 1 SORT (AGGREGATE)<br>5 4 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=1309 Bytes=170<br>17)<br><br><br><br><br><br>Statistics<br>----------------------------------------------------------<br>0 recursive calls<br>0 db block gets<br><font color=#ff0000>6 consistent gets</font><br>0 physical reads<br>0 redo size<br>561 bytes sent via SQL*Net to client<br>503 bytes received via SQL*Net from client<br>2 SQL*Net roundtrips to/from client<br>1 sorts (memory)<br>0 sorts (disk)<br>6 rows processed<br><br><br><font color=#0000ff>下面是使用分析函数rollup得出的汇总数据的例子</font><br>06:44:09 SQL&gt; select nvl(area_code,'合计') area_code,sum(local_fare) local_fare<br>06:45:26 2 from t<br>06:45:30 3 group by rollup(nvl(area_code,'合计'))<br>06:45:50 4 /<br><br>AREA_CODE LOCAL_FARE<br>---------- --------------<br>5761 54225413.04<br>5762 52039619.60<br>5763 69186545.02<br>5764 53156768.46<br>5765 104548719.19<br>333157065.31<br><br>6 rows selected.<br><br>Elapsed: 00:00:00.00<br><br>Execution Plan<br>----------------------------------------------------------<br>0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5 Card=1309 Bytes=<br>24871)<br><br>1 0 SORT (GROUP BY ROLLUP) (Cost=5 Card=1309 Bytes=24871)<br>2 1 TABLE ACCESS (FULL) OF 'T' (Cost=2 Card=1309 Bytes=24871<br>)<br><br><br><br><br><br>Statistics<br>----------------------------------------------------------<br>0 recursive calls<br>0 db block gets<br><font color=#ff0000>4 consistent gets</font><br>0 physical reads<br>0 redo size<br>557 bytes sent via SQL*Net to client<br>503 bytes received via SQL*Net from client<br>2 SQL*Net roundtrips to/from client<br>1 sorts (memory)<br>0 sorts (disk)<br>6 rows processed<br><br><br><strong>从上面的例子我们不难看出使用rollup函数,系统的sql语句更加简单,耗用的资源更少,从6个consistent gets降到4个consistent gets,如果基表很大的话,结果就可想而知了.</strong></font></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
</center><br>
<table style="TABLE-LAYOUT: fixed; WORD-WRAP: break-word" height="100%" cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td vAlign=top><strong><font face=Arial><font size=2><span class=bold><span class=smalltxt>1. 使用cube函数的介绍</span></span></font></font></strong>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td><font size=2>Quote:</font></td>
                    </tr>
                    <tr>
                        <td>
                        <table cellSpacing=1 cellPadding=10 width="100%" bgColor=#efefcf border=0>
                            <tbody>
                                <tr>
                                    <td width="100%" bgColor=#ffffff><font size=2><strong>为了介绍cube函数我们再来看看另外一个使用rollup的例子</strong><br>06:53:00 SQL&gt; select area_code,bill_month,sum(local_fare) local_fare<br>06:53:37 2 from t<br>06:53:38 3 group by rollup(area_code,bill_month)<br>06:53:49 4 /<br><br>AREA_CODE BILL_MONTH LOCAL_FARE<br>---------- --------------- --------------<br>5761 200405 13060433.89<br>5761 200406 13318931.01<br>5761 200407 13710265.93<br>5761 200408 14135782.21<br>5761 54225413.04<br>5762 200405 12643792.11<br>5762 200406 12795060.65<br>5762 200407 13224298.12<br>5762 200408 13376468.72<br>5762 52039619.60<br>5763 200405 16649778.91<br>5763 200406 17120515.71<br>5763 200407 17487493.32<br>5763 200408 17928757.08<br>5763 69186545.02<br>5764 200405 12487791.94<br>5764 200406 13295187.67<br>5764 200407 13444093.76<br>5764 200408 13929695.09<br>5764 53156768.46<br>5765 200405 25057737.47<br>5765 200406 26058461.31<br>5765 200407 26301881.40<br>5765 200408 27130639.01<br>5765 104548719.19<br>333157065.31<br><br>26 rows selected.<br><br>Elapsed: 00:00:00.00</font><font size=2><strong>系统只是根据rollup的第一个参数area_code对结果集的数据做了汇总处理,而没有对bill_month做汇总分析处理,cube函数就是为了这个而设计的.<br>下面,让我们看看使用cube函数的结果</strong><br><br>06:58:02 SQL&gt; select area_code,bill_month,sum(local_fare) local_fare<br>06:58:30 2 from t<br>06:58:32 3 group by cube(area_code,bill_month)<br>06:58:42 4 order by area_code,bill_month nulls last<br>06:58:57 5 /<br><br>AREA_CODE BILL_MONTH LOCAL_FARE<br>---------- --------------- --------------<br>5761 200405 13060.43<br>5761 200406 13318.93<br>5761 200407 13710.27<br>5761 200408 14135.78<br>5761 54225.41<br>5762 200405 12643.79<br>5762 200406 12795.06<br>5762 200407 13224.30<br>5762 200408 13376.47<br>5762 52039.62<br>5763 200405 16649.78<br>5763 200406 17120.52<br>5763 200407 17487.49<br>5763 200408 17928.76<br>5763 69186.54<br>5764 200405 12487.79<br>5764 200406 13295.19<br>5764 200407 13444.09<br>5764 200408 13929.69<br>5764 53156.77<br>5765 200405 25057.74<br>5765 200406 26058.46<br>5765 200407 26301.88<br>5765 200408 27130.64<br>5765 104548.72</font><font size=2><font color=#ff0000><strong>200405 79899.53<br>200406 82588.15<br>200407 84168.03<br>200408 86501.34</strong></font><br>333157.05<br><br>30 rows selected.<br><br>Elapsed: 00:00:00.01<br><br><strong>可以看到,在cube函数的输出结果比使用rollup多出了几行统计数据.这就是cube函数根据bill_month做的汇总统计结果</strong></font></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></td>
        </tr>
    </tbody>
</table>
<strong><font face=Arial><font size=2><span class=bold><span class=smalltxt>1 rollup 和 cube函数的再深入</span></span></font></font></strong>
<center>
<table cellSpacing=0 cellPadding=0 width="90%" border=0>
    <tbody>
        <tr>
            <td><font size=2>Quote:</font></td>
        </tr>
        <tr>
            <td>
            <table cellSpacing=1 cellPadding=10 width="100%" bgColor=#efefcf border=0>
                <tbody>
                    <tr>
                        <td width="100%" bgColor=#ffffff><font size=2><strong>从上面的结果中我们很容易发现,每个统计数据所对应的行都会出现null,<br>我们如何来区分到底是根据那个字段做的汇总呢,<br>这时候,oracle的grouping函数就粉墨登场了.<br>如果当前的汇总记录是利用该字段得出的,grouping函数就会返回1,否则返回0</strong><br><br>1 select decode(grouping(area_code),1,'all area',to_char(area_code)) area_code,<br>2 decode(grouping(bill_month),1,'all month',bill_month) bill_month,<br>3 sum(local_fare) local_fare<br>4 from t<br>5 group by cube(area_code,bill_month)<br>6* order by area_code,bill_month nulls last<br>07:07:29 SQL&gt; /<br><br>AREA_CODE BILL_MONTH LOCAL_FARE<br>---------- --------------- --------------<br>5761 200405 13060.43<br>5761 200406 13318.93<br>5761 200407 13710.27<br>5761 200408 14135.78<br>5761 all month 54225.41<br>5762 200405 12643.79<br>5762 200406 12795.06<br>5762 200407 13224.30<br>5762 200408 13376.47<br>5762 all month 52039.62<br>5763 200405 16649.78<br>5763 200406 17120.52<br>5763 200407 17487.49<br>5763 200408 17928.76<br>5763 all month 69186.54<br>5764 200405 12487.79<br>5764 200406 13295.19<br>5764 200407 13444.09<br>5764 200408 13929.69<br>5764 all month 53156.77<br>5765 200405 25057.74<br>5765 200406 26058.46<br>5765 200407 26301.88<br>5765 200408 27130.64<br>5765 all month 104548.72</font><font size=2><font color=#ff0000><strong>all area 200405 79899.53<br>all area 200406 82588.15<br>all area 200407 84168.03<br>all area 200408 86501.34<br>all area all month 333157.05</strong></font><br>30 rows selected.<br><br>Elapsed: 00:00:00.01<br>07:07:31 SQL&gt;</font><strong><br><font size=2>可以看到,所有的空值现在都根据grouping函数做出了很好的区分,这样利用rollup,cube和grouping函数,我们做数据统计的时候就可以轻松很多了.</font></strong></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
</center><br><br><br>
<table style="TABLE-LAYOUT: fixed; WORD-WRAP: break-word" height="100%" cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td vAlign=top><font size=2><strong><span class=bold><span class=smalltxt><font face=Arial>2. rank函数的介绍</font></span></span>介绍完rollup和cube函数的使用,下面我们来看看rank系列函数的使用方法.</strong><br><br><strong>问题2.</strong>我想查出这几个月份中各个地区的总话费的排名.</font>
            <center>
            <table cellSpacing=0 cellPadding=0 width="90%" border=0>
                <tbody>
                    <tr>
                        <td><font size=2>Quote:</font></td>
                    </tr>
                    <tr>
                        <td>
                        <table cellSpacing=1 cellPadding=10 width="100%" bgColor=#efefcf border=0>
                            <tbody>
                                <tr>
                                    <td width="100%" bgColor=#ffffff><font size=2><strong>为了将rank,dense_rank,row_number函数的差别显示出来,我们对已有的基础数据做一些修改,将5763的数据改成与5761的数据相同.</strong><br>1 update t t1 set local_fare = (<br>2 select local_fare from t t2<br>3 where t1.bill_month = t2.bill_month<br>4 and t1.net_type = t2.net_type<br>5 and t2.area_code = '5761'<br>6* ) where area_code = '5763'<br>07:19:18 SQL&gt; /<br><br>8 rows updated.<br><br>Elapsed: 00:00:00.01<br><br>我们先使用rank函数来计算各个地区的话费排名.<br>07:34:19 SQL&gt; select area_code,sum(local_fare) local_fare,<br>07:35:25 2 rank() over (order by sum(local_fare) desc) fare_rank<br>07:35:44 3 from t<br>07:35:45 4 group by area_codee<br>07:35:50 5<br>07:35:52 SQL&gt; select area_code,sum(local_fare) local_fare,<br>07:36:02 2 rank() over (order by sum(local_fare) desc) fare_rank<br>07:36:20 3 from t<br>07:36:21 4 group by area_code<br>07:36:25 5 /<br><br>AREA_CODE LOCAL_FARE FARE_RANK<br>---------- -------------- ----------<br>5765 104548.72 1<br>5761 54225.41 2<br>5763 54225.41 <font color=#ff0000>2 </font><br>5764 53156.77 <font color=#ff0000>4 </font><br>5762 52039.62 5<br><br>Elapsed: 00:00:00.01</font><font size=2><strong>我们可以看到红色标注的地方出现了,跳位,排名3没有出现<br>下面我们再看看dense_rank查询的结果.</strong><br><br>07:36:26 SQL&gt; select area_code,sum(local_fare) local_fare,<br>07:39:16 2 dense_rank() over (order by sum(local_fare) desc ) fare_rank<br>07:39:39 3 from t<br>07:39:42 4 group by area_code<br>07:39:46 5 /<br><br>AREA_CODE LOCAL_FARE FARE_RANK<br>---------- -------------- ----------<br>5765 104548.72 1<br>5761 54225.41 2<br>5763 54225.41 2<br>5764 53156.77 3 <font color=#ff0000>这是这里出现了第三名</font><br>5762 52039.62 4<br><br>Elapsed: 00:00:00.00</font><strong><br><font size=2>在这个例子中,出现了一个第三名,这就是rank和dense_rank的差别,<br>rank如果出现两个相同的数据,那么后面的数据就会<font color=#0000ff>直接跳过</font>这个排名,而dense_rank则不会,<br>差别更大的是,row_number哪怕是两个数据完全相同,排名也会不一样,这个特性在我们想找出对应没个条件的唯一记录的时候又很大用处</font></strong><br><br><font size=2>1 select area_code,sum(local_fare) local_fare,<br>2 row_number() over (order by sum(local_fare) desc ) fare_rank<br>3 from t<br>4* group by area_code<br>07:44:50 SQL&gt; /<br><br>AREA_CODE LOCAL_FARE FARE_RANK<br>---------- -------------- ----------<br>5765 104548.72 1<br><font color=#ff0000>5761 54225.41 2</font><br><font color=#ff0000>5763 54225.41 3</font><br>5764 53156.77 4<br>5762 52039.62 5</font><strong><font size=2>在row_nubmer函数中,我们发现,哪怕sum(local_fare)完全相同,我们还是得到了不一样排名,我们可以利用这个特性剔除数据库中的重复记录.<br><br>这个帖子中的几个例子是为了说明这三个函数的基本用法的. 下个帖子我们将详细介绍他们的一些用法.</font></strong></td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            </center></td>
        </tr>
    </tbody>
</table>
<font size=2><span class=bold><span class=smalltxt><strong><font face=Arial>2. rank函数的介绍</font></strong></span></span>a. 取出数据库中最后入网的n个用户<br>select user_id,tele_num,user_name,user_status,create_date <br>from (<br>select user_id,tele_num,user_name,user_status,create_date,<br>rank() over (order by create_date desc) add_rank<br>from user_info<br>)<br>where add_rank &lt;= :n;<br><br>b.根据object_name删除数据库中的重复记录<br>create table t as select obj#,name from sys.obj$;<br>再insert into t1 select * from t1 数次.<br>delete from t1 where rowid in (<br>select row_id from (<br>select rowid row_id,row_number() over (partition by obj# order by rowid ) rn<br>) where rn &lt;&gt; 1<br>);<br><br>c. 取出各地区的话费收入在各个月份排名.<br>SQL&gt; select bill_month,area_code,sum(local_fare) local_fare,<br>2 rank() over (partition by bill_month order by sum(local_fare) desc) area_rank<br>3 from t<br>4 group by bill_month,area_code<br>5 /<br><br>BILL_MONTH AREA_CODE LOCAL_FARE AREA_RANK<br>--------------- --------------- -------------- ----------<br>200405 5765 25057.74 1<br>200405 5761 13060.43 2<br>200405 5763 13060.43 2<br>200405 5762 12643.79 4<br>200405 5764 12487.79 5<br>200406 5765 26058.46 1<br>200406 5761 13318.93 2<br>200406 5763 13318.93 2<br>200406 5764 13295.19 4<br>200406 5762 12795.06 5<br>200407 5765 26301.88 1<br>200407 5761 13710.27 2<br>200407 5763 13710.27 2<br>200407 5764 13444.09 4<br>200407 5762 13224.30 5<br>200408 5765 27130.64 1<br>200408 5761 14135.78 2<br>200408 5763 14135.78 2<br>200408 5764 13929.69 4<br>200408 5762 13376.47 5<br><br>20 rows selected.<br>SQL&gt;</font><font size=2><strong><span class=bold><span class=smalltxt><font face=Arial>3. lag和lead函数介绍</font></span></span>取出每个月的上个月和下个月的话费总额</strong><br>1 select area_code,bill_month, local_fare cur_local_fare,<br>2 lag(local_fare,2,0) over (partition by area_code order by bill_month ) pre_local_fare,<br>3 lag(local_fare,1,0) over (partition by area_code order by bill_month ) last_local_fare,<br>4 lead(local_fare,1,0) over (partition by area_code order by bill_month ) next_local_fare,<br>5 lead(local_fare,2,0) over (partition by area_code order by bill_month ) post_local_fare<br>6 from (<br>7 select area_code,bill_month,sum(local_fare) local_fare<br>8 from t<br>9 group by area_code,bill_month<br>10* )<br>SQL&gt; /<br>AREA_CODE BILL_MONTH CUR_LOCAL_FARE PRE_LOCAL_FARE LAST_LOCAL_FARE NEXT_LOCAL_FARE POST_LOCAL_FARE<br>--------- ---------- -------------- -------------- --------------- --------------- ---------------<br>5761 200405 13060.433 0 0 13318.93 13710.265<br>5761 200406 13318.93 0 13060.433 13710.265 14135.781<br>5761 200407 13710.265 13060.433 13318.93 14135.781 0<br>5761 200408 14135.781 13318.93 13710.265 0 0<br>5762 200405 12643.791 0 0 12795.06 13224.297<br>5762 200406 12795.06 0 12643.791 13224.297 13376.468<br>5762 200407 13224.297 12643.791 12795.06 13376.468 0<br>5762 200408 13376.468 12795.06 13224.297 0 0<br>5763 200405 13060.433 0 0 13318.93 13710.265<br>5763 200406 13318.93 0 13060.433 13710.265 14135.781<br>5763 200407 13710.265 13060.433 13318.93 14135.781 0<br>5763 200408 14135.781 13318.93 13710.265 0 0<br>5764 200405 12487.791 0 0 13295.187 13444.093<br>5764 200406 13295.187 0 12487.791 13444.093 13929.694<br>5764 200407 13444.093 12487.791 13295.187 13929.694 0<br>5764 200408 13929.694 13295.187 13444.093 0 0<br>5765 200405 25057.736 0 0 26058.46 26301.881<br>5765 200406 26058.46 0 25057.736 26301.881 27130.638<br>5765 200407 26301.881 25057.736 26058.46 27130.638 0<br>5765 200408 27130.638 26058.46 26301.881 0 0<br>20 rows selected.<br><br><strong>利用lag和lead函数,我们可以在同一行中显示前n行的数据,也可以显示后n行的数据.</strong></font><font size=2><span class=bold><span class=smalltxt><strong><font face=Arial>4. sum,avg,max,min移动计算数据介绍</font></strong></span></span>计算出各个连续3个月的通话费用的平均数<br>1 select area_code,bill_month, local_fare,<br>2 sum(local_fare)<br>3 over ( partition by area_code<br>4 order by to_number(bill_month)<br>5 range between 1 preceding and 1 following ) "3month_sum",<br>6 avg(local_fare)<br>7 over ( partition by area_code<br>8 order by to_number(bill_month)<br>9 range between 1 preceding and 1 following ) "3month_avg",<br>10 max(local_fare)<br>11 over ( partition by area_code<br>12 order by to_number(bill_month)<br>13 range between 1 preceding and 1 following ) "3month_max",<br>14 min(local_fare)<br>15 over ( partition by area_code<br>16 order by to_number(bill_month)<br>17 range between 1 preceding and 1 following ) "3month_min"<br>18 from (<br>19 select area_code,bill_month,sum(local_fare) local_fare<br>20 from t<br>21 group by area_code,bill_month<br>22* )<br>SQL&gt; /<br><br>AREA_CODE BILL_MONTH LOCAL_FARE 3month_sum 3month_avg 3month_max 3month_min<br>--------- ---------- ---------------- ---------- ---------- ---------- ----------<br>5761 200405 <font color=#0000ff>13060.433</font> 26379.363 13189.6815 13318.93 13060.433<br>5761 200406 <font color=#0000ff>13318.930</font> 40089.628 13363.2093 13710.265 13060.433<br>5761 200407 <font color=#0000ff>13710.265</font> 41164.976 13721.6587 14135.781 13318.93</font><font size=2><strong>40089.628 = 13060.433 + 13318.930 + 13710.265<br>13363.2093 = (13060.433 + 13318.930 + 13710.265) / 3<br>13710.265 = max(13060.433 + 13318.930 + 13710.265)<br>13060.433 = min(13060.433 + 13318.930 + 13710.265)</strong><br>5761 200408 14135.781 27846.046 13923.023 14135.781 13710.265<br>5762 200405 12643.791 25438.851 12719.4255 12795.06 12643.791<br>5762 200406 12795.060 38663.148 12887.716 13224.297 12643.791<br>5762 200407 13224.297 39395.825 13131.9417 13376.468 12795.06<br>5762 200408 13376.468 26600.765 13300.3825 13376.468 13224.297<br>5763 200405 13060.433 26379.363 13189.6815 13318.93 13060.433<br>5763 200406 13318.930 40089.628 13363.2093 13710.265 13060.433<br>5763 200407 13710.265 41164.976 13721.6587 14135.781 13318.93<br>5763 200408 14135.781 27846.046 13923.023 14135.781 13710.265<br>5764 200405 12487.791 25782.978 12891.489 13295.187 12487.791<br>5764 200406 13295.187 39227.071 13075.6903 13444.093 12487.791<br>5764 200407 13444.093 40668.974 13556.3247 13929.694 13295.187<br>5764 200408 13929.694 27373.787 13686.8935 13929.694 13444.093<br>5765 200405 25057.736 51116.196 25558.098 26058.46 25057.736<br>5765 200406 26058.460 77418.077 25806.0257 26301.881 25057.736<br>5765 200407 26301.881 79490.979 26496.993 27130.638 26058.46<br>5765 200408 27130.638 53432.519 26716.2595 27130.638 26301.881<br><br>20 rows selected.</font><strong><font face=Arial><font size=2><span class=bold><span class=smalltxt>5. ratio_to_report函数的介绍</span></span></font></font></strong>
<center>
<table cellSpacing=0 cellPadding=0 width="90%" border=0>
    <tbody>
        <tr>
            <td><font size=2>Quote:</font></td>
        </tr>
        <tr>
            <td>
            <table cellSpacing=1 cellPadding=10 width="100%" bgColor=#efefcf border=0>
                <tbody>
                    <tr>
                        <td width="100%" bgColor=#ffffff><font size=2>1 select bill_month,area_code,sum(local_fare) local_fare,<br>2 ratio_to_report(sum(local_fare)) over<br>3 ( partition by bill_month ) area_pct<br>4 from t<br>5* group by bill_month,area_code<br>SQL&gt; break on bill_month skip 1<br>SQL&gt; compute sum of local_fare on bill_month<br>SQL&gt; compute sum of area_pct on bill_month<br>SQL&gt; /<br><br>BILL_MONTH AREA_CODE LOCAL_FARE AREA_PCT<br>---------- --------- ---------------- ----------<br>200405 5761 13060.433 .171149279<br>5762 12643.791 .165689431<br>5763 13060.433 .171149279<br>5764 12487.791 .163645143<br>5765 25057.736 .328366866<br>********** ---------------- ----------<br>sum 76310.184 1<br><br>200406 5761 13318.930 .169050772<br>5762 12795.060 .162401542<br>5763 13318.930 .169050772<br>5764 13295.187 .168749414<br>5765 26058.460 .330747499<br>********** ---------------- ----------<br>sum 78786.567 1<br><br>200407 5761 13710.265 .170545197<br>5762 13224.297 .164500127<br>5763 13710.265 .170545197<br>5764 13444.093 .167234221<br>5765 26301.881 .327175257<br>********** ---------------- ----------<br>sum 80390.801 1<br><br>200408 5761 14135.781 .170911147<br>5762 13376.468 .161730539<br>5763 14135.781 .170911147<br>5764 13929.694 .168419416<br>5765 27130.638 .328027751<br>********** ---------------- ----------<br>sum 82708.362 1<br><br><br>20 rows selected.</font></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
</center><br><strong><font face=Arial><font size=2><span class=bold><span class=smalltxt>6 first,last函数使用介绍</span></span></font></font></strong>
<center>
<table cellSpacing=0 cellPadding=0 width="90%" border=0>
    <tbody>
        <tr>
            <td><font size=2>Quote:</font></td>
        </tr>
        <tr>
            <td>
            <table cellSpacing=1 cellPadding=10 width="100%" bgColor=#efefcf border=0>
                <tbody>
                    <tr>
                        <td width="100%" bgColor=#ffffff><font size=2><strong>取出每月通话费最高和最低的两个用户.</strong><br>1 select bill_month,area_code,sum(local_fare) local_fare,<br>2 first_value(area_code)<br>3 over (order by sum(local_fare) desc<br>4 rows unbounded preceding) firstval,<br>5 first_value(area_code)<br>6 over (order by sum(local_fare) asc<br>7 rows unbounded preceding) lastval<br>8 from t<br>9 group by bill_month,area_code<br>10* order by bill_month<br>SQL&gt; /<br><br>BILL_MONTH AREA_CODE LOCAL_FARE FIRSTVAL LASTVAL<br>---------- --------- ---------------- --------------- ---------------<br>200405 5764 12487.791 5765 5764<br>200405 5762 12643.791 5765 5764<br>200405 5761 13060.433 5765 5764<br>200405 5765 25057.736 5765 5764<br>200405 5763 13060.433 5765 5764<br>200406 5762 12795.060 5765 5764<br>200406 5763 13318.930 5765 5764<br>200406 5764 13295.187 5765 5764<br>200406 5765 26058.460 5765 5764<br>200406 5761 13318.930 5765 5764<br>200407 5762 13224.297 5765 5764<br>200407 5765 26301.881 5765 5764<br>200407 5761 13710.265 5765 5764<br>200407 5763 13710.265 5765 5764<br>200407 5764 13444.093 5765 5764<br>200408 5762 13376.468 5765 5764<br>200408 5764 13929.694 5765 5764<br>200408 5761 14135.781 5765 5764<br>200408 5765 27130.638 5765 5764<br>200408 5763 14135.781 5765 5764<br><br>20 rows selected.</font></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
</center></font></span></span>
<img src ="http://www.blogjava.net/franlk/aggbug/118286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-05-18 10:55 <a href="http://www.blogjava.net/franlk/articles/118286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]ROLLUP和CUBE语句</title><link>http://www.blogjava.net/franlk/articles/118282.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Fri, 18 May 2007 02:48:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/118282.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/118282.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/118282.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/118282.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/118282.html</trackback:ping><description><![CDATA[<br>摘录地址：<a href="http://xsb.itpub.net/post/419/29159"><font color=#000080><u style="COLOR: red">http://xsb.itpub.net/post/419/29159</u></font></a><br><br>2005-05-10 09:40 First Publish.<br>Oracle的GROUP BY语句除了最基本的语法外，还支持ROLLUP和CUBE语句。如果是ROLLUP(A, B, C)的话，首先会对(A、B、C)进行GROUP BY，然后对(A、B)进行GROUP BY，然后是(A)进行GROUP BY，最后对全表进行GROUP BY操作。如果是GROUP BY CUBE(A, B, C)，则首先会对(A、B、C)进行GROUP BY，然后依次是(A、B)，(A、C)，(A)，(B、C)，(B)，(C)，最后对全表进行GROUP BY操作。 grouping_id()可以美化效果：
<p><br><font size=2>Oracle的GROUP BY语句除了最基本的语法外，还支持ROLLUP和CUBE语句。</font></span />
<p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: ">
<p><font size=2>除本文内容外，你还可参考：<br>分析函数参考手册： </font><font color=#007799 size=2><a href="http://xsb.itpub.net/post/419/33028">http://xsb.itpub.net/post/419/33028</a></font><br><font size=2>分析函数使用例子介绍：</font><a href="http://xsb.itpub.net/post/419/44634"><font color=#007799 size=2>http://xsb.itpub.net/post/419/44634</font></a></p>
<p><span lang=EN-US><font face=宋体 size=2>SQL&gt; create table t as select * from dba_indexes;</font></span></p>
<p>
<p><span><font face=宋体 size=2>表已创建。</font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>SQL&gt; select index_type, status, count(*) from t group by index_type, status;</font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>INDEX_TYPE STATUS COUNT(*)<br>--------------------------- -------- ----------<br>LOB VALID 51<br>NORMAL N/A 25<br>NORMAL VALID 479<br>CLUSTER VALID 11</font></span></p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: "><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><font size=2>下面来看看<span lang=EN-US>ROLLUP和CUBE语句的执行结果。</span></font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>SQL&gt; select index_type, status, count(*) from t group by rollup(index_type, status);</font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>INDEX_TYPE STATUS COUNT(*)<br>--------------------------- -------- ----------<br>LOB VALID 51<br>LOB 51<br>NORMAL N/A 25<br>NORMAL VALID 479<br>NORMAL 504<br>CLUSTER VALID 11<br>CLUSTER 11<br>566</font></span></p>
<p>
<p><span><font face=宋体><font size=2>已选择<span lang=EN-US>8行。</span></font></font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>SQL&gt; select index_type, status, count(*) from t group by cube(index_type, status);</font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>INDEX_TYPE STATUS COUNT(*)<br>--------------------------- -------- ----------<br>566<br>N/A 25<br>VALID 541<br>LOB 51<br>LOB VALID 51<br>NORMAL 504<br>NORMAL N/A 25<br>NORMAL VALID 479<br>CLUSTER 11<br>CLUSTER VALID 11</font></span></p>
<p>
<p><span><font face=宋体><font size=2>已选择<span lang=EN-US>10行。</span></font></font></span></p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: "><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><font size=2>查询结果不是很一目了然，下面通过<span lang=EN-US>Oracle提供的函数GROUPING来整理一下查询结果。</span></font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>SQL&gt; select grouping(index_type) g_ind, grouping(status) g_st, index_type, status, count(*)<br>2 from t group by rollup(index_type, status) order by 1, 2;</font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>G_IND G_ST INDEX_TYPE STATUS COUNT(*)<br>---------- ---------- --------------------------- -------- ----------<br>0 0 LOB VALID 51<br>0 0 NORMAL N/A 25<br>0 0 NORMAL VALID 479<br>0 0 CLUSTER VALID 11<br>0 1 LOB 51<br>0 1 NORMAL 504<br>0 1 CLUSTER 11<br>1 1 566</font></span></p>
<p>
<p><span><font face=宋体><font size=2>已选择<span lang=EN-US>8行。</span></font></font></span></p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: "><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><font size=2>这个查询结果就直观多了，和不带<span lang=EN-US>ROLLUP语句的GROUP BY相比，ROLLUP增加了对INDEX_TYPE的GROUP BY统计和对所有记录的GROUP BY统计。</span></font></span></p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: "><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><font size=2>也就是说，如果是<span lang=EN-US>ROLLUP(A, B, C)的话，首先会对(A、B、C)进行GROUP BY，然后对(A、B)进行GROUP BY，然后是(A)进行GROUP BY，最后对全表进行GROUP BY操作。</span></font></span></p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: "><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><font size=2>下面看看<span lang=EN-US>CUBE语句。</span></font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>SQL&gt; select grouping(index_type) g_ind, grouping(status) g_st, index_type, status, count(*) <br>2 from t group by cube(index_type, status) order by 1, 2;</font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>G_IND G_ST INDEX_TYPE STATUS COUNT(*)<br>---------- ---------- --------------------------- -------- ----------<br>0 0 LOB VALID 51<br>0 0 NORMAL N/A 25<br>0 0 NORMAL VALID 479<br>0 0 CLUSTER VALID 11<br>0 1 LOB 51<br>0 1 NORMAL 504<br>0 1 CLUSTER 11<br>1 0 N/A 25<br>1 0 VALID 541<br>1 1 566</font></span></p>
<p>
<p><span><font face=宋体><font size=2>已选择<span lang=EN-US>10行。</span></font></font></span></p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: "><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><font size=2>和<span lang=EN-US>ROLLUP相比，CUBE又增加了对STATUS列的GROUP BY统计。</span></font></span></p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: "><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><font size=2>如果是<span lang=EN-US>GROUP BY CUBE(A, B, C)，则首先会对(A、B、C)进行GROUP BY，然后依次是(A、B)，(A、C)，(A)，(B、C)，(B)，(C)，最后对全表进行GROUP BY操作。</span></font></span></p>
<p>
<p style="TEXT-INDENT: 24pt; 0cm: "><span style="FONT-SIZE: 12pt; FONT-FAMILY: 宋体"><font size=2>除了使用<span lang=EN-US>GROUPING函数，还可以使用GROUPING_ID来标识GROUP BY结果。</span></font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>SQL&gt; select grouping_id(index_type, status) g_ind, index_type, status, count(*) <br>2 from t group by rollup(index_type, status) order by 1;</font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>G_IND INDEX_TYPE STATUS COUNT(*)<br>---------- --------------------------- -------- ----------<br>0 LOB VALID 51<br>0 NORMAL N/A 25<br>0 NORMAL VALID 479<br>0 CLUSTER VALID 11<br>1 LOB 51<br>1 NORMAL 504<br>1 CLUSTER 11<br>3 566</font></span></p>
<p>
<p><span><font face=宋体><font size=2>已选择<span lang=EN-US>8行。</span></font></font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>SQL&gt; select grouping_id(index_type, status) g_ind, index_type, status, count(*) <br>2 from t group by cube(index_type, status) order by 1;</font></span></p>
<p>
<p><span lang=EN-US><font face=宋体 size=2>G_IND INDEX_TYPE STATUS COUNT(*)<br>---------- --------------------------- -------- ----------<br>0 LOB VALID 51<br>0 NORMAL N/A 25<br>0 NORMAL VALID 479<br>0 CLUSTER VALID 11<br>1 LOB 51<br>1 NORMAL 504<br>1 CLUSTER 11<br>2 N/A 25<br>2 VALID 541<br>3 566</font></span></p>
<p>
<p><span><font face=宋体><font size=2>已选择<span lang=EN-US>10行。</span></font></font></span></p>
<p><span><font face=宋体><font size=2><span lang=EN-US><strong>grouping_id()可以美化效果：</strong></span></font></font></span></p>
<p><span><font face=宋体><font size=2><span lang=EN-US>select DECODE(GROUPING_ID(C1), 1, '合计', C1) D1,<br>DECODE(GROUPING_ID(C1, C2), 1, '小计', C2) D2,<br>DECODE(GROUPING_ID(C1, C2, C1 + C2), 1, '小计', C1 + C2) D3,<br>count(*),<br>GROUPING_ID(C1, C2, C1 + C2, C1 + 1, C2 + 1),<br>GROUPING_ID(C1)<br>from T2<br>group by rollup(C1, C2, C1 + C2, C1 + 1, C2 + 1);</span></font></font></span></p>
<p><span><font face=宋体><font size=2><span lang=EN-US>===========================================================</span></font></font></span></p>
<p><font size=2><strong><span lang=EN-US><font face=Arial>1.</font></span><span style="FONT-FAMILY: 宋体">报表合计专用的</span><span lang=EN-US><font face=Arial>Rollup</font></span><span style="FONT-FAMILY: 宋体">函数</span></strong></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">销售报表</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">广州</span><span lang=EN-US><font face=Arial><span> </span>1</font></span><span style="FONT-FAMILY: 宋体">月</span><span lang=EN-US><font face=Arial><span> </span>2000</font></span><span style="FONT-FAMILY: 宋体">元</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">广州</span><span lang=EN-US><font face=Arial><span> </span>2</font></span><span style="FONT-FAMILY: 宋体">月</span><span lang=EN-US><font face=Arial><span> </span>2500</font></span><span style="FONT-FAMILY: 宋体">元</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">广州</span><span lang=EN-US><font face=Arial><span> </span>4500</font></span><span style="FONT-FAMILY: 宋体">元</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">深圳</span><span lang=EN-US><font face=Arial><span> </span>1</font></span><span style="FONT-FAMILY: 宋体">月</span><span lang=EN-US><font face=Arial><span> </span>1000</font></span><span style="FONT-FAMILY: 宋体">元</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">深圳</span><span lang=EN-US><font face=Arial><span> </span>2</font></span><span style="FONT-FAMILY: 宋体">月</span><span lang=EN-US><font face=Arial><span> </span>2000</font></span><span style="FONT-FAMILY: 宋体">元</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">深圳</span><span lang=EN-US><font face=Arial><span> </span>3000</font></span><span style="FONT-FAMILY: 宋体">元</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">所有地区</span><span lang=EN-US><font face=Arial><span> </span>7500</font></span><span style="FONT-FAMILY: 宋体">元</span></font></p>
<p>
<p>
<p><font size=2><span style="FONT-FAMILY: 宋体">以往的查询</span><span lang=EN-US><font face=Arial>SQL:</font></span></font></p>
<p><span lang=EN-US><font face=Arial size=2>Select<span> </span>area,month,sum(money) from SaleOrder group by area,month</font></span></p>
<p><span style="FONT-FAMILY: 宋体"><font size=2>然后广州，深圳的合计和所有地区合计都需要在程序里自行累计</font></span></p>
<p>
<p><font size=2><span lang=EN-US><font face=Arial>1.</font></span><span style="FONT-FAMILY: 宋体">其实可以使用如下</span><span lang=EN-US><font face=Arial>SQL:</font></span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>Select area,month,sum(total_sale) from SaleOrder group by rollup(area,month)</font></font></span></p>
<p><span style="FONT-FAMILY: 宋体"><font size=2>就能产生和报表一模一样的纪录</font></span></p>
<p>
<p><font size=2><span lang=EN-US><font face=Arial>2.</font></span><span style="FONT-FAMILY: 宋体">如果</span><span lang=EN-US><font face=Arial>year</font></span><span style="FONT-FAMILY: 宋体">不想累加，可以写成</span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>Select year,month,area,sum(total_sale) from SaleOrder group by year, rollup(month,area)</font></font></span></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">另外</span><span lang=EN-US><font face=Arial>Oracle 9i</font></span><span style="FONT-FAMILY: 宋体">还支持如下语法</span><span lang=EN-US><font face=Arial>:</font></span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>Select year,month,area,sum(total_sale) from SaleOrder group by rollup((year,month),area)</font></font></span></p>
<p>
<p><font size=2><span lang=EN-US><font face=Arial>3.</font></span><span style="FONT-FAMILY: 宋体">如果使用</span><span lang=EN-US><font face=Arial>Cube(area,month)</font></span><span style="FONT-FAMILY: 宋体">而不是</span><span lang=EN-US><font face=Arial>RollUp(area,month)</font></span><span style="FONT-FAMILY: 宋体">，除了获得每个地区的合计之外，还将获得每个月份的合计，在报表最后显示。</span></font></p>
<p>
<p><font size=2><span lang=EN-US><font face=Arial>4.Grouping</font></span><span style="FONT-FAMILY: 宋体">让合计列更好读</span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>RollUp</font></span><span style="FONT-FAMILY: 宋体">在显示广州合计时，月份列为</span><span lang=EN-US><font face=Arial>NULL</font></span><span style="FONT-FAMILY: 宋体">，但更好的做法应该是显示为</span><span lang=EN-US><font face=Arial>"</font></span><span style="FONT-FAMILY: 宋体">所有月份</span><span lang=EN-US><font face=Arial>"</font></span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>Grouping</font></span><span style="FONT-FAMILY: 宋体">就是用来判断当前</span><span lang=EN-US><font face=Arial>Column</font></span><span style="FONT-FAMILY: 宋体">是否是一个合计列，</span><span lang=EN-US><font face=Arial>1</font></span><span style="FONT-FAMILY: 宋体">为</span><span lang=EN-US><font face=Arial>yes</font></span><span style="FONT-FAMILY: 宋体">，然后用</span><span lang=EN-US><font face=Arial>Decode</font></span><span style="FONT-FAMILY: 宋体">把它转为</span><span lang=EN-US><font face=Arial>"</font></span><span style="FONT-FAMILY: 宋体">所有月份</span><span lang=EN-US><font face=Arial>"</font></span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>Select<span> </span>Decode(Grouping(area),1,'</font></span><span style="FONT-FAMILY: 宋体">所有地区</span><span lang=EN-US><font face=Arial>',area) area,<span> </span>Decode(Grouping(month),1,'</font></span><span style="FONT-FAMILY: 宋体">所有月份</span><span lang=EN-US><font face=Arial>',month),<span> </span>sum(money)<span> </span>From SaleOrder<span> </span>Group by RollUp(area,month);</font></span></font></p>
<p>
<p><font size=2><strong><span lang=EN-US><font face=Arial>2.</font></span><span style="FONT-FAMILY: 宋体">对多级层次查询的</span><span lang=EN-US><font face=Arial>start with.....connect by</font></span></strong></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">比如人员组织</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">产品类别</span><span lang=EN-US><font face=Arial>,Oracle</font></span><span style="FONT-FAMILY: 宋体">提供了很经典的方法</span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>SELECT LEVEL, name, emp_id,manager_emp_id FROM employee START WITH manager_emp_id is null CONNECT BY PRIOR emp_id = manager_emp_id;</font></font></span></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">上面的语句</span><span lang=EN-US><font face=Arial>demo</font></span><span style="FONT-FAMILY: 宋体">了全部的应用</span><span lang=EN-US><font face=Arial>,start with</font></span><span style="FONT-FAMILY: 宋体">指明从哪里开始遍历树</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">如果从根开始</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">那么它的</span><span lang=EN-US><font face=Arial>manager</font></span><span style="FONT-FAMILY: 宋体">应该是</span><span lang=EN-US><font face=Arial>Null,</font></span><span style="FONT-FAMILY: 宋体">如果从某个职员开始</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">可以写成</span><span lang=EN-US><font face=Arial>emp_id='11'</font></span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>CONNECT BY </font></span><span style="FONT-FAMILY: 宋体">就是指明父子关系</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">注意</span><span lang=EN-US><font face=Arial>PRIOR</font></span><span style="FONT-FAMILY: 宋体">位置</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">另外还有一个</span><span lang=EN-US><font face=Arial>LEVEL</font></span><span style="FONT-FAMILY: 宋体">列</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">显示节点的层次</span></font></p>
<p>
<p><font size=2><strong><span lang=EN-US><font face=Arial>3.</font></span><span style="FONT-FAMILY: 宋体">更多报表</span><span lang=EN-US><font face=Arial>/</font></span><span style="FONT-FAMILY: 宋体">分析决策功能</span></strong></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>3.1 </font></span><span style="FONT-FAMILY: 宋体">分析功能的基本结构</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">分析功能</span><span lang=EN-US><font face=Arial>() over( partion</font></span><span style="FONT-FAMILY: 宋体">子句</span><span lang=EN-US><font face=Arial>,order by</font></span><span style="FONT-FAMILY: 宋体">子句</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">窗口子句</span><span lang=EN-US><font face=Arial>)</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">概念上很难讲清楚</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">还是用例子说话比较好</span><span lang=EN-US><font face=Arial>.<span> </span></font></span></font></p>
<p>
<p><font size=2><span lang=EN-US><font face=Arial>3.2 Row_Number </font></span><span style="FONT-FAMILY: 宋体">和</span><span lang=EN-US><font face=Arial> Rank, DENSE_Rank</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">用于选出</span><span lang=EN-US><font face=Arial>Top 3 sales</font></span><span style="FONT-FAMILY: 宋体">这样的报表</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">当两个业务员可能有相同业绩时</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">就要使用</span><span lang=EN-US><font face=Arial>Rank</font></span><span style="FONT-FAMILY: 宋体">和</span><span lang=EN-US><font face=Arial>Dense_Rank</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">比如</span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">金额</span><span lang=EN-US><font face=Arial><span> </span>RowNum<span> </span>Rank<span> </span>Dense_Rank</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">张三</span><span lang=EN-US><font face=Arial> 4000</font></span><span style="FONT-FAMILY: 宋体">元</span><span lang=EN-US><font face=Arial><span> </span>1<span> </span>1<span> </span>1</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">李四</span><span lang=EN-US><font face=Arial> 3000</font></span><span style="FONT-FAMILY: 宋体">元</span><span lang=EN-US><font face=Arial><span> </span>2<span> </span>2<span> </span>2</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">钱五</span><span lang=EN-US><font face=Arial> 2000</font></span><span style="FONT-FAMILY: 宋体">元</span><span lang=EN-US><font face=Arial><span> </span>3<span> </span>3<span> </span>3</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">孙六</span><span lang=EN-US><font face=Arial> 2000</font></span><span style="FONT-FAMILY: 宋体">元</span><span lang=EN-US><font face=Arial><span> </span>4<span> </span>3<span> </span>3</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">丁七</span><span lang=EN-US><font face=Arial> 1000</font></span><span style="FONT-FAMILY: 宋体">元</span><span lang=EN-US><font face=Arial><span> </span>5<span> </span>5<span> </span>4</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">这时</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">应该把并列第三的钱五和孙六都选进去</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">所以用</span><span lang=EN-US><font face=Arial>Ranking</font></span><span style="FONT-FAMILY: 宋体">功能比</span><span lang=EN-US><font face=Arial>RowNumber</font></span><span style="FONT-FAMILY: 宋体">保险</span><span lang=EN-US><font face=Arial>.</font></span><span style="FONT-FAMILY: 宋体">至于</span><span lang=EN-US><font face=Arial>Desnse</font></span><span style="FONT-FAMILY: 宋体">还是</span><span lang=EN-US><font face=Arial>Ranking</font></span><span style="FONT-FAMILY: 宋体">就看具体情况了。</span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>SELECT salesperson_id, SUM(tot_sales) sp_sales,<span> </span>RANK( ) OVER (ORDER BY SUM(tot_sales) DESC) sales_rank<span> </span>FROM orders<span> </span>GROUP BY salesperson_id</font></font></span></p>
<p><font size=2><span lang=EN-US><font face=Arial>3.3 NTILE </font></span><span style="FONT-FAMILY: 宋体">把纪录平分成甲乙丙丁四等</span><span lang=EN-US><font face=Arial> </font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">比如我想取得前</span><span lang=EN-US><font face=Arial>25%</font></span><span style="FONT-FAMILY: 宋体">的纪录</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">或者把</span><span lang=EN-US><font face=Arial>25%</font></span><span style="FONT-FAMILY: 宋体">的纪录当作同一个</span><span lang=EN-US><font face=Arial>level</font></span><span style="FONT-FAMILY: 宋体">平等对待</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">把另</span><span lang=EN-US><font face=Arial>25%</font></span><span style="FONT-FAMILY: 宋体">当作另一个</span><span lang=EN-US><font face=Arial>Level</font></span><span style="FONT-FAMILY: 宋体">平等对待</span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>SELECT cust_nbr, SUM(tot_sales) cust_sales,<span> </span>NTILE(4) OVER (ORDER BY SUM(tot_sales) DESC) sales_quartile<span> </span>FROM orders<span> </span>GROUP BY cust_nbr<span> </span>ORDER BY 3,2 DESC;</font></font></span></p>
<p><font size=2><span lang=EN-US><font face=Arial>NTITLE(4)</font></span><span style="FONT-FAMILY: 宋体">把纪录以</span><span lang=EN-US><font face=Arial> SUM(tot_sales)</font></span><span style="FONT-FAMILY: 宋体">排序分成</span><span lang=EN-US><font face=Arial>4</font></span><span style="FONT-FAMILY: 宋体">份</span><span lang=EN-US><font face=Arial>.</font></span></font></p>
<p>
<p><font size=2><span lang=EN-US><font face=Arial>3.4 </font></span><span style="FONT-FAMILY: 宋体">辅助分析列和</span><span lang=EN-US><font face=Arial>Windows Function</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">报表除了基本事实数据外</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">总希望旁边多些全年总销量</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">到目前为止的累计销量</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">前后三个月的平均销量这样的列来参考</span><span lang=EN-US><font face=Arial>.</font></span></font></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">这种前后三个月的平均和到目前为止的累计销量就叫</span><span lang=EN-US><font face=Arial>windows function, </font></span><span style="FONT-FAMILY: 宋体">见下例</span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>SELECT month, SUM(tot_sales) monthly_sales,<span> </span>SUM(SUM(tot_sales)) OVER (ORDER BY month<span> </span>ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_preceeding<span> </span>FROM orders<span> </span>GROUP BY month<span> </span>ORDER BY month;</font></font></span></p>
<p><span lang=EN-US><font face=Arial><font size=2>SELECT month, SUM(tot_sales) monthly_sales,<span> </span>AVG(SUM(tot_sales)) OVER (ORDER BY month<span> </span>ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) rolling_avg<span> </span>FROM orders<span> </span>GROUP BY month<span> </span>ORDER BY month;</font></font></span></p>
<p><font size=2><span lang=EN-US><font face=Arial>Windows Function</font></span><span style="FONT-FAMILY: 宋体">的关键就是</span><span lang=EN-US><font face=Arial>Windows</font></span><span style="FONT-FAMILY: 宋体">子句的几个取值</span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>1 PRECEDING </font></span><span style="FONT-FAMILY: 宋体">之前的一条记录</span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>1 FOLLOWING </font></span><span style="FONT-FAMILY: 宋体">之后的一条记录</span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>UNBOUNDED PRECEDING </font></span><span style="FONT-FAMILY: 宋体">之前的所有记录</span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>CURRENT ROW </font></span><span style="FONT-FAMILY: 宋体">当前纪录</span></font></p>
<p>
<p><font size=2><strong><span lang=EN-US><font face=Arial>4.SubQuery</font></span><span style="FONT-FAMILY: 宋体">总结</span></strong></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>SubQuery</font></span><span style="FONT-FAMILY: 宋体">天天用了</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">理论上总结一下</span><span lang=EN-US><font face=Arial>.SubQuery </font></span><span style="FONT-FAMILY: 宋体">分三种</span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>1.Noncorrelated </font></span><span style="FONT-FAMILY: 宋体">子查询</span><span lang=EN-US><span><font face=Arial> </font></span></span><span style="FONT-FAMILY: 宋体">最普通的样式</span><span lang=EN-US><font face=Arial>.</font></span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>2.Correlated Subqueries<span> </span></font></span><span style="FONT-FAMILY: 宋体">把父查询的列拉到子查询里面去</span><span lang=EN-US><font face=Arial>,</font></span><span style="FONT-FAMILY: 宋体">头一回</span><span lang=EN-US><font face=Arial>cyt</font></span><span style="FONT-FAMILY: 宋体">教我的时候理解了半天</span><span lang=EN-US><font face=Arial>.</font></span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>3.Inline View<span> </span></font></span><span style="FONT-FAMILY: 宋体">也被当成最普通的样式用了</span><span lang=EN-US><font face=Arial>.</font></span></font></p>
<p>
<p><font size=2><span style="FONT-FAMILY: 宋体">然后</span><span lang=EN-US><font face=Arial>Noncorrelated </font></span><span style="FONT-FAMILY: 宋体">子查询又有三种情况</span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>1.</font></span><span style="FONT-FAMILY: 宋体">返回一行一列</span><span lang=EN-US><font face=Arial><span> </span>where price &lt; (select max(price) from goods )</font></span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>2.</font></span><span style="FONT-FAMILY: 宋体">返回多行一列</span><span lang=EN-US><font face=Arial><span> </span>where price&gt;= ALL (select price from goods where type=2)</font></span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>or where NOT price&lt; ANY(select price from goods where type=2)</font></font></span></p>
<p><font size=2><span style="FONT-FAMILY: 宋体">最常用的</span><span lang=EN-US><font face=Arial>IN</font></span><span style="FONT-FAMILY: 宋体">其实就是</span><span lang=EN-US><font face=Arial>=ANY()</font></span></font></p>
<p><font size=2><span lang=EN-US><font face=Arial>3.</font></span><span style="FONT-FAMILY: 宋体">返回多行多列</span><span lang=EN-US><span><font face=Arial> </font></span></span><span style="FONT-FAMILY: 宋体">一次返回多列当然就节省了查询时间</span><span lang=EN-US><font face=Arial> </font></span></font></p>
<p><span lang=EN-US><font face=Arial><font size=2>UPDATE monthly_orders<span> </span>SET (tot_orders, max_order_amt) =<span> </span>(SELECT COUNT(*), MAX(sale_price)<span> </span>FROM cust_order)<span> </span>DELETE FROM line_item<span> </span>WHERE (order_nbr, part_nbr) IN<span> </span>(SELECT order_nbr, part_nbr FROM cust_order c)</font></font></span></p>
<p><span lang=EN-US><font face=Arial size=2>========================================<br>/*--------理解grouping sets<br>select a, b, c, sum( d ) from t<br>group by grouping sets ( a, b, c )</font></span></p>
<p><span lang=EN-US><font face=Arial size=2>等效于</font></span></p>
<p><span lang=EN-US><font face=Arial size=2>select * from (<br>select a, null, null, sum( d ) from t group by a<br>union all<br>select null, b, null, sum( d ) from t group by b <br>union all<br>select null, null, c, sum( d ) from t group by c <br>)<br>*/</font></span></p>
<img src ="http://www.blogjava.net/franlk/aggbug/118282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-05-18 10:48 <a href="http://www.blogjava.net/franlk/articles/118282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Oracle分析函数参考手册 </title><link>http://www.blogjava.net/franlk/articles/118280.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Fri, 18 May 2007 02:44:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/118280.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/118280.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/118280.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/118280.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/118280.html</trackback:ping><description><![CDATA[<br>摘录地址：<a href="http://xsb.itpub.net/post/419/33028"><u><font color=#800080>http://xsb.itpub.net/post/419/33028</font></u></a><br><br>
<p>Oracle从8.1.6开始提供分析函数，分析函数用于计算基于组的某种聚合值，它和聚合函数的不同之处是对于每个组返回多行，而聚合函数对于每个组只返回一行。</p>
<p>下面例子中使用的表来自Oracle自带的HR用户下的表，如果没有安装该用户，可以在SYS用户下运行$ORACLE_HOME/demo/schema/human_resources/hr_main.sql来创建。</p>
<p>除本文内容外，你还可参考：<br>ROLLUP与CUBE <a href="http://xsb.itpub.net/post/419/29159"><font color=#000080>http://xsb.itpub.net/post/419/29159</font></a><br>分析函数使用例子介绍：<a href="http://xsb.itpub.net/post/419/44634"><font color=#000080>http://xsb.itpub.net/post/419/44634</font></a></p>
<p>本文如果未指明，缺省是在HR用户下运行例子。<br>开窗函数的的理解：<br>开窗函数指定了分析函数工作的数据窗口大小，这个数据窗口大小可能会随着行的变化而变化，举例如下：<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）</p>
<p>主要参考资料：《expert one-on-one》 Tom Kyte 《Oracle9i SQL Reference》第6章</p>
<p><br>AVG <br>功能描述：用于计算一个组和数据窗口内表达式的平均值。<br>SAMPLE：下面的例子中列c_mavg计算员工表中每个员工的平均薪水报告，该平均值由当前员工和与之具有相同经理的前一个和后一个三者的平均数得来；</p>
<p>SELECT manager_id, last_name, hire_date, salary,<br>AVG(salary) OVER (PARTITION BY manager_id ORDER BY hire_date <br>ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS c_mavg<br>FROM employees;</p>
<p>MANAGER_ID LAST_NAME HIRE_DATE SALARY C_MAVG<br>---------- ------------------------- --------- ---------- ----------<br>100 Kochhar 21-SEP-89 17000 17000<br>100 De Haan 13-JAN-93 17000 15000<br>100 Raphaely 07-DEC-94 11000 11966.6667<br>100 Kaufling 01-MAY-95 7900 10633.3333<br>100 Hartstein 17-FEB-96 13000 9633.33333<br>100 Weiss 18-JUL-96 8000 11666.6667<br>100 Russell 01-OCT-96 14000 11833.3333</p>
<p>CORR <br>功能描述：返回一对表达式的相关系数，它是如下的缩写：<br>COVAR_POP(expr1,expr2)/STDDEV_POP(expr1)*STDDEV_POP(expr2))<br>从统计上讲，相关性是变量之间关联的强度，变量之间的关联意味着在某种程度<br>上一个变量的值可由其它的值进行预测。通过返回一个-1~1之间的一个数, 相关<br>系数给出了关联的强度，0表示不相关。<br>SAMPLE：下例返回1998年月销售收入和月单位销售的关系的累积系数（本例在SH用户下运行）</p>
<p>SELECT t.calendar_month_number,<br>CORR (SUM(s.amount_sold), SUM(s.quantity_sold))<br>OVER (ORDER BY t.calendar_month_number) as CUM_CORR<br>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;</p>
<p>CALENDAR_MONTH_NUMBER CUM_CORR<br>--------------------- ----------<br>1<br>2 1<br>3 .994309382<br>4 .852040875<br>5 .846652204<br>6 .871250628<br>7 .910029803<br>8 .917556399<br>9 .920154356<br>10 .86720251<br>11 .844864765<br>12 .903542662</p>
<p><br>COVAR_POP <br>功能描述：返回一对表达式的总体协方差。<br>SAMPLE：下例CUM_COVP返回定价和最小产品价格的累积总体协方差</p>
<p>SELECT product_id, supplier_id,<br>COVAR_POP(list_price, min_price) <br>OVER (ORDER BY product_id, supplier_id) AS CUM_COVP,<br>COVAR_SAMP(list_price, min_price)<br>OVER (ORDER BY product_id, supplier_id) AS CUM_COVS <br>FROM product_information p<br>WHERE category_id = 29<br>ORDER BY product_id, supplier_id;</p>
<p>PRODUCT_ID SUPPLIER_ID CUM_COVP CUM_COVS<br>---------- ----------- ---------- ----------<br>1774 103088 0<br>1775 103087 1473.25 2946.5<br>1794 103096 1702.77778 2554.16667<br>1825 103093 1926.25 2568.33333<br>2004 103086 1591.4 1989.25<br>2005 103086 1512.5 1815<br>2416 103088 1475.97959 1721.97619<br>.<br>.</p>
<p><br>COVAR_SAMP <br>功能描述：返回一对表达式的样本协方差<br>SAMPLE：下例CUM_COVS返回定价和最小产品价格的累积样本协方差</p>
<p>SELECT product_id, supplier_id,<br>COVAR_POP(list_price, min_price) <br>OVER (ORDER BY product_id, supplier_id) AS CUM_COVP,<br>COVAR_SAMP(list_price, min_price)<br>OVER (ORDER BY product_id, supplier_id) AS CUM_COVS <br>FROM product_information p<br>WHERE category_id = 29<br>ORDER BY product_id, supplier_id;</p>
<p>PRODUCT_ID SUPPLIER_ID CUM_COVP CUM_COVS<br>---------- ----------- ---------- ----------<br>1774 103088 0<br>1775 103087 1473.25 2946.5<br>1794 103096 1702.77778 2554.16667<br>1825 103093 1926.25 2568.33333<br>2004 103086 1591.4 1989.25<br>2005 103086 1512.5 1815<br>2416 103088 1475.97959 1721.97619<br>.<br>.</p>
<p><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值的所有行数</p>
<p>SELECT last_name, salary, COUNT(*) OVER () AS cnt1,<br>COUNT(*) OVER (ORDER BY salary) AS cnt2,<br>COUNT(*) OVER (ORDER BY salary RANGE BETWEEN 50 PRECEDING<br>AND 150 FOLLOWING) AS cnt3 FROM employees;</p>
<p>LAST_NAME SALARY CNT1 CNT2 CNT3<br>------------------------- ---------- ---------- ---------- ----------<br>Olson 2100 107 1 3<br>Markle 2200 107 3 2<br>Philtanker 2200 107 3 2<br>Landry 2400 107 5 8<br>Gee 2400 107 5 8<br>Colmenares 2500 107 11 10<br>Patel 2500 107 11 10<br>.<br>.</p>
<p><br>CUME_DIST <br>功能描述：计算一行在组中的相对位置，CUME_DIST总是返回大于0、小于或等于1的数，该数表示该行在N行中的位置。例如，在一个3行的组中，返回的累计分布值为1/3、2/3、3/3<br>SAMPLE：下例中计算每个工种的员工按薪水排序依次累积出现的分布百分比</p>
<p>SELECT job_id, last_name, salary, CUME_DIST() <br>OVER (PARTITION BY job_id ORDER BY salary) AS cume_dist<br>FROM employees WHERE job_id LIKE 'PU%';</p>
<p>JOB_ID LAST_NAME SALARY CUME_DIST<br>---------- ------------------------- ---------- ----------<br>PU_CLERK Colmenares 2500 .2<br>PU_CLERK Himuro 2600 .4<br>PU_CLERK Tobias 2800 .6<br>PU_CLERK Baida 2900 .8<br>PU_CLERK Khoo 3100 1<br>PU_MAN Raphaely 11000 1</p>
<p><br>DENSE_RANK <br>功能描述：根据ORDER BY子句中表达式的值，从查询返回的每一行，计算它们与其它行的相对位置。组内的数据按ORDER BY子句排序，然后给每一行赋一个号，从而形成一个序列，该序列从1开始，往后累加。每次ORDER BY表达式的值发生变化时，该序列也随之增加。有同样值的行得到同样的数字序号（认为null时相等的）。密集的序列返回的时没有间隔的数<br>SAMPLE：下例中计算每个员工按部门分区再按薪水排序，依次出现的序列号（注意与RANK函数的区别）</p>
<p>SELECT d.department_id , e.last_name, e.salary, DENSE_RANK() <br>OVER (PARTITION BY e.department_id ORDER BY e.salary) as drank<br>FROM employees e, departments d<br>WHERE e.department_id = d.department_id<br>AND d.department_id IN ('60', '90'); </p>
<p>DEPARTMENT_ID LAST_NAME SALARY DRANK<br>------------- ------------------------- ---------- ----------<br>60 Lorentz 4200 1<br>60 Austin 4800 2<br>60 Pataballa 4800 2<br>60 Ernst 6000 3<br>60 Hunold 9000 4<br>90 Kochhar 17000 1<br>90 De Haan 17000 1<br>90 King 24000 2</p>
<p><br>FIRST <br>功能描述：从DENSE_RANK返回的集合中取出排在最前面的一个值的行（可能多行，因为值可能相等），因此完整的语法需要在开始处加上一个集合函数以从中取出记录<br>SAMPLE：下面例子中DENSE_RANK按部门分区，再按佣金commission_pct排序，FIRST取出佣金最低的对应的所有行，然后前面的MAX函数从这个集合中取出薪水最低的值；LAST取出佣金最高的对应的所有行，然后前面的MIN函数从这个集合中取出薪水最高的值<br>SELECT last_name, department_id, salary,<br>MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct)<br>OVER (PARTITION BY department_id) "Worst",<br>MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct)<br>OVER (PARTITION BY department_id) "Best"<br>FROM employees <br>WHERE department_id in (20,80) <br>ORDER BY department_id, salary;</p>
<p>LAST_NAME DEPARTMENT_ID SALARY Worst Best<br>------------------------- ------------- ---------- ---------- ----------<br>Fay 20 6000 6000 13000<br>Hartstein 20 13000 6000 13000<br>Kumar 80 6100 6100 14000<br>Banda 80 6200 6100 14000<br>Johnson 80 6200 6100 14000<br>Ande 80 6400 6100 14000<br>Lee 80 6800 6100 14000<br>Tuvault 80 7000 6100 14000<br>Sewall 80 7000 6100 14000<br>Marvins 80 7200 6100 14000<br>Bates 80 7300 6100 14000<br>.<br>.<br>.</p>
<p><br>FIRST_VALUE <br>功能描述：返回组中数据窗口的第一个值。<br>SAMPLE：下面例子计算按部门分区按薪水排序的数据窗口的第一个值对应的名字，如果薪水的第一个值有多个，则从多个对应的名字中取缺省排序的第一个名字</p>
<p>SELECT department_id, last_name, salary, FIRST_VALUE(last_name)<br>OVER (PARTITION BY department_id ORDER BY salary ASC ) AS lowest_sal<br>FROM employees <br>WHERE department_id in(20,30);</p>
<p>DEPARTMENT_ID LAST_NAME SALARY LOWEST_SAL<br>------------- ------------------------- ---------- --------------<br>20 Fay 6000 Fay<br>20 Hartstein 13000 Fay<br>30 Colmenares 2500 Colmenares<br>30 Himuro 2600 Colmenares<br>30 Tobias 2800 Colmenares<br>30 Baida 2900 Colmenares<br>30 Khoo 3100 Colmenares<br>30 Raphaely 11000 Colmenares</p>
<p><br>LAG <br>功能描述：可以访问结果集中的其它行而不用进行自连接。它允许去处理游标，就好像游标是一个数组一样。在给定组中可参考当前行之前的行，这样就可以从组中与当前行一起选择以前的行。Offset是一个正整数，其默认值为1，若索引超出窗口的范围，就返回默认值（默认返回的是组中第一行），其相反的函数是LEAD<br>SAMPLE：下面的例子中列prev_sal返回按hire_date排序的前1行的salary值</p>
<p>SELECT last_name, hire_date, salary,<br>LAG(salary, 1, 0) OVER (ORDER BY hire_date) AS prev_sal<br>FROM employees<br>WHERE job_id = 'PU_CLERK';</p>
<p>LAST_NAME HIRE_DATE SALARY PREV_SAL<br>------------------------- ---------- ---------- ----------<br>Khoo 18-5月 -95 3100 0<br>Tobias 24-7月 -97 2800 3100<br>Baida 24-12月-97 2900 2800<br>Himuro 15-11月-98 2600 2900<br>Colmenares 10-8月 -99 2500 2600</p>
<p><br>LAST <br>功能描述：从DENSE_RANK返回的集合中取出排在最后面的一个值的行（可能多行，因为值可能相等），因此完整的语法需要在开始处加上一个集合函数以从中取出记录<br>SAMPLE：下面例子中DENSE_RANK按部门分区，再按佣金commission_pct排序，FIRST取出佣金最低的对应的所有行，然后前面的MAX函数从这个集合中取出薪水最低的值；LAST取出佣金最高的对应的所有行，然后前面的MIN函数从这个集合中取出薪水最高的值<br>SELECT last_name, department_id, salary,<br>MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct)<br>OVER (PARTITION BY department_id) "Worst",<br>MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct)<br>OVER (PARTITION BY department_id) "Best"<br>FROM employees <br>WHERE department_id in (20,80) <br>ORDER BY department_id, salary;</p>
<p>LAST_NAME DEPARTMENT_ID SALARY Worst Best<br>------------------------- ------------- ---------- ---------- ----------<br>Fay 20 6000 6000 13000<br>Hartstein 20 13000 6000 13000<br>Kumar 80 6100 6100 14000<br>Banda 80 6200 6100 14000<br>Johnson 80 6200 6100 14000<br>Ande 80 6400 6100 14000<br>Lee 80 6800 6100 14000<br>Tuvault 80 7000 6100 14000<br>Sewall 80 7000 6100 14000<br>Marvins 80 7200 6100 14000<br>Bates 80 7300 6100 14000<br>.<br>LAST_VALUE <br>功能描述：返回组中数据窗口的最后一个值。<br>SAMPLE：下面例子计算按部门分区按薪水排序的数据窗口的最后一个值对应的名字，如果薪水的最后一个值有多个，则从多个对应的名字中取缺省排序的最后一个名字<br>SELECT department_id, last_name, salary, LAST_VALUE(last_name)<br>OVER(PARTITION BY department_id ORDER BY salary) AS highest_sal<br>FROM employees <br>WHERE department_id in(20,30);</p>
<p>DEPARTMENT_ID LAST_NAME SALARY HIGHEST_SAL<br>------------- ------------------------- ---------- ------------<br>20 Fay 6000 Fay<br>20 Hartstein 13000 Hartstein<br>30 Colmenares 2500 Colmenares<br>30 Himuro 2600 Himuro<br>30 Tobias 2800 Tobias<br>30 Baida 2900 Baida<br>30 Khoo 3100 Khoo<br>30 Raphaely 11000 Raphaely</p>
<p><br>LEAD <br>功能描述：LEAD与LAG相反，LEAD可以访问组中当前行之后的行。Offset是一个正整数，其默认值为1，若索引超出窗口的范围，就返回默认值（默认返回的是组中第一行）<br>SAMPLE：下面的例子中每行的"NextHired"返回按hire_date排序的下一行的hire_date值</p>
<p>SELECT last_name, hire_date, <br>LEAD(hire_date, 1) OVER (ORDER BY hire_date) AS "NextHired" <br>FROM employees WHERE department_id = 30;</p>
<p>LAST_NAME HIRE_DATE NextHired<br>------------------------- --------- ---------<br>Raphaely 07-DEC-94 18-MAY-95<br>Khoo 18-MAY-95 24-JUL-97<br>Tobias 24-JUL-97 24-DEC-97<br>Baida 24-DEC-97 15-NOV-98<br>Himuro 15-NOV-98 10-AUG-99<br>Colmenares 10-AUG-99</p>
<p><br>MAX <br>功能描述：在一个组中的数据窗口中查找表达式的最大值。<br>SAMPLE：下面例子中dept_max返回当前行所在部门的最大薪水值</p>
<p>SELECT department_id, last_name, salary, <br>MAX(salary) OVER (PARTITION BY department_id) AS dept_max<br>FROM employees WHERE department_id in (10,20,30);</p>
<p>DEPARTMENT_ID LAST_NAME SALARY DEPT_MAX<br>------------- ------------------------- ---------- ----------<br>10 Whalen 4400 4400<br>20 Hartstein 13000 13000<br>20 Fay 6000 13000<br>30 Raphaely 11000 11000<br>30 Khoo 3100 11000<br>30 Baida 2900 11000<br>30 Tobias 2800 11000<br>30 Himuro 2600 11000<br>30 Colmenares 2500 11000</p>
<p><br>MIN <br>功能描述：在一个组中的数据窗口中查找表达式的最小值。<br>SAMPLE：下面例子中dept_min返回当前行所在部门的最小薪水值</p>
<p>SELECT department_id, last_name, salary, <br>MIN(salary) OVER (PARTITION BY department_id) AS dept_min<br>FROM employees WHERE department_id in (10,20,30);</p>
<p>DEPARTMENT_ID LAST_NAME SALARY DEPT_MIN<br>------------- ------------------------- ---------- ----------<br>10 Whalen 4400 4400<br>20 Hartstein 13000 6000<br>20 Fay 6000 6000<br>30 Raphaely 11000 2500<br>30 Khoo 3100 2500<br>30 Baida 2900 2500<br>30 Tobias 2800 2500<br>30 Himuro 2600 2500<br>30 Colmenares 2500 2500</p>
<p><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份</p>
<p>SELECT last_name, salary, <br>NTILE(4) OVER (ORDER BY salary DESC) AS quartile FROM employees<br>WHERE department_id = 100;</p>
<p>LAST_NAME SALARY QUARTILE<br>------------------------- ---------- ----------<br>Greenberg 12000 1<br>Faviet 9000 1<br>Chen 8200 2<br>Urman 7800 2<br>Sciarra 7700 3<br>Popp 6900 4</p>
<p><br>PERCENT_RANK <br>功能描述：和CUME_DIST（累积分配）函数类似，对于一个组中给定的行来说，在计算那行的序号时，先减1，然后除以n-1（n为组中所有的行数）。该函数总是返回0～1（包括1）之间的数。<br>SAMPLE：下例中如果Khoo的salary为2900，则pr值为0.6，因为RANK函数对于等值的返回序列值是一样的</p>
<p>SELECT department_id, last_name, salary, <br>PERCENT_RANK() <br>OVER (PARTITION BY department_id ORDER BY salary) AS pr<br>FROM employees<br>WHERE department_id &lt; 50<br>ORDER BY department_id,salary;</p>
<p>DEPARTMENT_ID LAST_NAME SALARY PR<br>------------- ------------------------- ---------- ----------<br>10 Whalen 4400 0<br>20 Fay 6000 0<br>20 Hartstein 13000 1<br>30 Colmenares 2500 0<br>30 Himuro 2600 0.2<br>30 Tobias 2800 0.4<br>30 Baida 2900 0.6<br>30 Khoo 3100 0.8<br>30 Raphaely 11000 1<br>40 Mavris 6500 0</p>
<p><br>PERCENTILE_CONT <br>功能描述：返回一个与输入的分布百分比值相对应的数据值，分布百分比的计算方法见函数PERCENT_RANK，如果没有正好对应的数据值，就通过下面算法来得到值：<br>RN = 1+ (P*(N-1)) 其中P是输入的分布百分比值，N是组内的行数<br>CRN = CEIL(RN) FRN = FLOOR(RN)<br>if (CRN = FRN = RN) then <br>(value of expression from row at RN)<br>else<br>(CRN - RN) * (value of expression for row at FRN) +<br>(RN - FRN) * (value of expression for row at CRN)<br>注意：本函数与PERCENTILE_DISC的区别在找不到对应的分布值时返回的替代值的计算方法不同</p>
<p>SAMPLE：在下例中，对于部门60的Percentile_Cont值计算如下：<br>P=0.7 N=5 RN =1+ (P*(N-1)=1+(0.7*(5-1))=3.8 CRN = CEIL(3.8)=4 <br>FRN = FLOOR(3.8)=3 <br>（4 - 3.8）* 4800 + (3.8 - 3) * 6000 = 5760</p>
<p>SELECT last_name, salary, department_id,<br>PERCENTILE_CONT(0.7) WITHIN GROUP (ORDER BY salary) <br>OVER (PARTITION BY department_id) "Percentile_Cont",<br>PERCENT_RANK() <br>OVER (PARTITION BY department_id ORDER BY salary) "Percent_Rank"<br>FROM employees WHERE department_id IN (30, 60);</p>
<p>LAST_NAME SALARY DEPARTMENT_ID Percentile_Cont Percent_Rank<br>------------------------- ---------- ------------- --------------- ------------<br>Colmenares 2500 30 3000 0<br>Himuro 2600 30 3000 0.2<br>Tobias 2800 30 3000 0.4<br>Baida 2900 30 3000 0.6<br>Khoo 3100 30 3000 0.8<br>Raphaely 11000 30 3000 1<br>Lorentz 4200 60 5760 0<br>Austin 4800 60 5760 0.25<br>Pataballa 4800 60 5760 0.25<br>Ernst 6000 60 5760 0.75<br>Hunold 9000 60 5760 1</p>
<p><br>PERCENTILE_DISC <br>功能描述：返回一个与输入的分布百分比值相对应的数据值，分布百分比的计算方法见函数CUME_DIST，如果没有正好对应的数据值，就取大于该分布值的下一个值。<br>注意：本函数与PERCENTILE_CONT的区别在找不到对应的分布值时返回的替代值的计算方法不同</p>
<p>SAMPLE：下例中0.7的分布值在部门30中没有对应的Cume_Dist值，所以就取下一个分布值0.83333333所对应的SALARY来替代</p>
<p>SELECT last_name, salary, department_id,<br>PERCENTILE_DISC(0.7) WITHIN GROUP (ORDER BY salary )<br>OVER (PARTITION BY department_id) "Percentile_Disc",<br>CUME_DIST() OVER (PARTITION BY department_id ORDER BY salary) "Cume_Dist"<br>FROM employees <br>WHERE department_id in (30, 60);</p>
<p>LAST_NAME SALARY DEPARTMENT_ID Percentile_Disc Cume_Dist<br>------------------------- ---------- ------------- --------------- ----------<br>Colmenares 2500 30 3100 .166666667<br>Himuro 2600 30 3100 .333333333<br>Tobias 2800 30 3100 .5<br>Baida 2900 30 3100 .666666667<br>Khoo 3100 30 3100 .833333333<br>Raphaely 11000 30 3100 1<br>Lorentz 4200 60 6000 .2<br>Austin 4800 60 6000 .6<br>Pataballa 4800 60 6000 .6<br>Ernst 6000 60 6000 .8<br>Hunold 9000 60 6000 1</p>
<p><br>RANK <br>功能描述：根据ORDER BY子句中表达式的值，从查询返回的每一行，计算它们与其它行的相对位置。组内的数据按ORDER BY子句排序，然后给每一行赋一个号，从而形成一个序列，该序列从1开始，往后累加。每次ORDER BY表达式的值发生变化时，该序列也随之增加。有同样值的行得到同样的数字序号（认为null时相等的）。然而，如果两行的确得到同样的排序，则序数将随后跳跃。若两行序数为1，则没有序数2，序列将给组中的下一行分配值3，DENSE_RANK则没有任何跳跃。<br>SAMPLE：下例中计算每个员工按部门分区再按薪水排序，依次出现的序列号（注意与DENSE_RANK函数的区别）</p>
<p>SELECT d.department_id , e.last_name, e.salary, RANK() <br>OVER (PARTITION BY e.department_id ORDER BY e.salary) as drank<br>FROM employees e, departments d<br>WHERE e.department_id = d.department_id<br>AND d.department_id IN ('60', '90');</p>
<p>DEPARTMENT_ID LAST_NAME SALARY DRANK<br>------------- ------------------------- ---------- ----------<br>60 Lorentz 4200 1<br>60 Austin 4800 2<br>60 Pataballa 4800 2<br>60 Ernst 6000 4<br>60 Hunold 9000 5<br>90 Kochhar 17000 1<br>90 De Haan 17000 1<br>90 King 24000 3</p>
<p><br>RATIO_TO_REPORT <br>功能描述：该函数计算expression/(sum(expression))的值，它给出相对于总数的百分比，即当前行对sum(expression)的贡献。<br>SAMPLE：下例计算每个员工的工资占该类员工总工资的百分比</p>
<p>SELECT last_name, salary, RATIO_TO_REPORT(salary) OVER () AS rr<br>FROM employees<br>WHERE job_id = 'PU_CLERK';</p>
<p>LAST_NAME SALARY RR<br>------------------------- ---------- ----------<br>Khoo 3100 .223021583<br>Baida 2900 .208633094<br>Tobias 2800 .201438849<br>Himuro 2600 .18705036<br>Colmenares 2500 .179856115</p>
<p><br>REGR_ (Linear Regression) Functions <br>功能描述：这些线性回归函数适合最小二乘法回归线，有9个不同的回归函数可使用。<br>REGR_SLOPE：返回斜率，等于COVAR_POP(expr1, expr2) / VAR_POP(expr2)<br>REGR_INTERCEPT：返回回归线的y截距，等于<br>AVG(expr1) - REGR_SLOPE(expr1, expr2) * AVG(expr2)<br>REGR_COUNT：返回用于填充回归线的非空数字对的数目<br>REGR_R2：返回回归线的决定系数，计算式为：<br>If VAR_POP(expr2) = 0 then return NULL<br>If VAR_POP(expr1) = 0 and VAR_POP(expr2) != 0 then return 1<br>If VAR_POP(expr1) &gt; 0 and VAR_POP(expr2 != 0 then <br>return POWER(CORR(expr1,expr),2)<br>REGR_AVGX：计算回归线的自变量(expr2)的平均值，去掉了空对(expr1, expr2)后，等于AVG(expr2)<br>REGR_AVGY：计算回归线的应变量(expr1)的平均值，去掉了空对(expr1, expr2)后，等于AVG(expr1)<br>REGR_SXX： 返回值等于REGR_COUNT(expr1, expr2) * VAR_POP(expr2)<br>REGR_SYY： 返回值等于REGR_COUNT(expr1, expr2) * VAR_POP(expr1)<br>REGR_SXY: 返回值等于REGR_COUNT(expr1, expr2) * COVAR_POP(expr1, expr2)</p>
<p>（下面的例子都是在SH用户下完成的）<br>SAMPLE 1：下例计算1998年最后三个星期中两种产品（260和270）在周末的销售量中已开发票数量和总数量的累积斜率和回归线的截距</p>
<p>SELECT t.fiscal_month_number "Month", t.day_number_in_month "Day", <br>REGR_SLOPE(s.amount_sold, s.quantity_sold) <br>OVER (ORDER BY t.fiscal_month_desc, t.day_number_in_month) AS CUM_SLOPE,<br>REGR_INTERCEPT(s.amount_sold, s.quantity_sold) <br>OVER (ORDER BY t.fiscal_month_desc, t.day_number_in_month) AS CUM_ICPT <br>FROM sales s, times t<br>WHERE s.time_id = t.time_id <br>AND s.prod_id IN (270, 260)<br>AND t.fiscal_year=1998 <br>AND t.fiscal_week_number IN (50, 51, 52)<br>AND t.day_number_in_week IN (6,7)<br>ORDER BY t.fiscal_month_desc, t.day_number_in_month;</p>
<p>Month Day CUM_SLOPE CUM_ICPT<br>---------- ---------- ---------- ----------<br>12 12 -68 1872<br>12 12 -68 1872<br>12 13 -20.244898 1254.36735<br>12 13 -20.244898 1254.36735<br>12 19 -18.826087 1287<br>12 20 62.4561404 125.28655<br>12 20 62.4561404 125.28655<br>12 20 62.4561404 125.28655<br>12 20 62.4561404 125.28655<br>12 26 67.2658228 58.9712313<br>12 26 67.2658228 58.9712313<br>12 27 37.5245541 284.958221<br>12 27 37.5245541 284.958221<br>12 27 37.5245541 284.958221</p>
<p>SAMPLE 2：下例计算1998年4月每天的累积交易数量</p>
<p>SELECT UNIQUE t.day_number_in_month,<br>REGR_COUNT(s.amount_sold, s.quantity_sold) <br>OVER (PARTITION BY t.fiscal_month_number ORDER BY t.day_number_in_month)<br>"Regr_Count"<br>FROM sales s, times t<br>WHERE s.time_id = t.time_id <br>AND t.fiscal_year = 1998 AND t.fiscal_month_number = 4;</p>
<p>DAY_NUMBER_IN_MONTH Regr_Count<br>------------------- ----------<br>1 825<br>2 1650<br>3 2475<br>4 3300<br>.<br>.<br>.<br>26 21450<br>30 22200</p>
<p>SAMPLE 3：下例计算1998年每月销售量中已开发票数量和总数量的累积回归线决定系数</p>
<p>SELECT t.fiscal_month_number,<br>REGR_R2(SUM(s.amount_sold), SUM(s.quantity_sold))<br>OVER (ORDER BY t.fiscal_month_number) "Regr_R2"<br>FROM sales s, times t<br>WHERE s.time_id = t.time_id<br>AND t.fiscal_year = 1998<br>GROUP BY t.fiscal_month_number<br>ORDER BY t.fiscal_month_number;</p>
<p>FISCAL_MONTH_NUMBER Regr_R2<br>------------------- ----------<br>1<br>2 1<br>3 .927372984<br>4 .807019972<br>5 .932745567<br>6 .94682861<br>7 .965342011<br>8 .955768075<br>9 .959542618<br>10 .938618575<br>11 .880931415<br>12 .882769189</p>
<p>SAMPLE 4：下例计算1998年12月最后两周产品260的销售量中已开发票数量和总数量的累积平均值</p>
<p>SELECT t.day_number_in_month,<br>REGR_AVGY(s.amount_sold, s.quantity_sold)<br>OVER (ORDER BY t.fiscal_month_desc, t.day_number_in_month)<br>"Regr_AvgY",<br>REGR_AVGX(s.amount_sold, s.quantity_sold)<br>OVER (ORDER BY t.fiscal_month_desc, t.day_number_in_month)<br>"Regr_AvgX"<br>FROM sales s, times t<br>WHERE s.time_id = t.time_id <br>AND s.prod_id = 260<br>AND t.fiscal_month_desc = '1998-12'<br>AND t.fiscal_week_number IN (51, 52)<br>ORDER BY t.day_number_in_month;</p>
<p>DAY_NUMBER_IN_MONTH Regr_AvgY Regr_AvgX<br>------------------- ---------- ----------<br>14 882 24.5<br>14 882 24.5<br>15 801 22.25<br>15 801 22.25<br>16 777.6 21.6<br>18 642.857143 17.8571429<br>18 642.857143 17.8571429<br>20 589.5 16.375<br>21 544 15.1111111<br>22 592.363636 16.4545455<br>22 592.363636 16.4545455<br>24 553.846154 15.3846154<br>24 553.846154 15.3846154<br>26 522 14.5<br>27 578.4 16.0666667</p>
<p>SAMPLE 5：下例计算产品260和270在1998年2月周末销售量中已开发票数量和总数量的累积REGR_SXY, REGR_SXX, and REGR_SYY统计值</p>
<p>SELECT t.day_number_in_month,<br>REGR_SXY(s.amount_sold, s.quantity_sold)<br>OVER (ORDER BY t.fiscal_year, t.fiscal_month_desc) "Regr_sxy",<br>REGR_SYY(s.amount_sold, s.quantity_sold)<br>OVER (ORDER BY t.fiscal_year, t.fiscal_month_desc) "Regr_syy",<br>REGR_SXX(s.amount_sold, s.quantity_sold)<br>OVER (ORDER BY t.fiscal_year, t.fiscal_month_desc) "Regr_sxx"<br>FROM sales s, times t<br>WHERE s.time_id = t.time_id <br>AND prod_id IN (270, 260)<br>AND t.fiscal_month_desc = '1998-02'<br>AND t.day_number_in_week IN (6,7)<br>ORDER BY t.day_number_in_month;</p>
<p>DAY_NUMBER_IN_MONTH Regr_sxy Regr_syy Regr_sxx<br>------------------- ---------- ---------- ----------<br>1 18870.4 2116198.4 258.4<br>1 18870.4 2116198.4 258.4<br>1 18870.4 2116198.4 258.4<br>1 18870.4 2116198.4 258.4<br>7 18870.4 2116198.4 258.4<br>8 18870.4 2116198.4 258.4<br>14 18870.4 2116198.4 258.4<br>15 18870.4 2116198.4 258.4<br>21 18870.4 2116198.4 258.4<br>22 18870.4 2116198.4 258.4</p>
<p><br>ROW_NUMBER <br>功能描述：返回有序组中一行的偏移量，从而可用于按特定标准排序的行号。<br>SAMPLE：下例返回每个员工再在每个部门中按员工号排序后的顺序号</p>
<p>SELECT department_id, last_name, employee_id, ROW_NUMBER()<br>OVER (PARTITION BY department_id ORDER BY employee_id) AS emp_id<br>FROM employees<br>WHERE department_id &lt; 50;</p>
<p>DEPARTMENT_ID LAST_NAME EMPLOYEE_ID EMP_ID<br>------------- ------------------------- ----------- ----------<br>10 Whalen 200 1<br>20 Hartstein 201 1<br>20 Fay 202 2<br>30 Raphaely 114 1<br>30 Khoo 115 2<br>30 Baida 116 3<br>30 Tobias 117 4<br>30 Himuro 118 5<br>30 Colmenares 119 6<br>40 Mavris 203 1</p>
<p><br>STDDEV <br>功能描述：计算当前行关于组的标准偏离。（Standard Deviation）<br>SAMPLE：下例返回部门30按雇佣日期排序的薪水值的累积标准偏离</p>
<p>SELECT last_name, hire_date,salary, <br>STDDEV(salary) OVER (ORDER BY hire_date) "StdDev"<br>FROM employees <br>WHERE department_id = 30;</p>
<p>LAST_NAME HIRE_DATE SALARY StdDev<br>------------------------- ---------- ---------- ----------<br>Raphaely 07-12月-94 11000 0<br>Khoo 18-5月 -95 3100 5586.14357<br>Tobias 24-7月 -97 2800 4650.0896<br>Baida 24-12月-97 2900 4035.26125<br>Himuro 15-11月-98 2600 3649.2465<br>Colmenares 10-8月 -99 2500 3362.58829</p>
<p><br>STDDEV_POP <br>功能描述：该函数计算总体标准偏离，并返回总体变量的平方根，其返回值与VAR_POP函数的平方根相同。（Standard Deviation－Population）<br>SAMPLE：下例返回部门20、30、60的薪水值的总体标准偏差</p>
<p>SELECT department_id, last_name, salary, <br>STDDEV_POP(salary) OVER (PARTITION BY department_id) AS pop_std<br>FROM employees<br>WHERE department_id in (20,30,60);</p>
<p>DEPARTMENT_ID LAST_NAME SALARY POP_STD<br>------------- ------------------------- ---------- ----------<br>20 Hartstein 13000 3500<br>20 Fay 6000 3500<br>30 Raphaely 11000 3069.6091<br>30 Khoo 3100 3069.6091<br>30 Baida 2900 3069.6091<br>30 Colmenares 2500 3069.6091<br>30 Himuro 2600 3069.6091<br>30 Tobias 2800 3069.6091<br>60 Hunold 9000 1722.32401<br>60 Ernst 6000 1722.32401<br>60 Austin 4800 1722.32401<br>60 Pataballa 4800 1722.32401<br>60 Lorentz 4200 1722.32401</p>
<p><br>STDDEV_SAMP <br>功能描述： 该函数计算累积样本标准偏离，并返回总体变量的平方根，其返回值与VAR_POP函数的平方根相同。（Standard Deviation－Sample）<br>SAMPLE：下例返回部门20、30、60的薪水值的样本标准偏差</p>
<p>SELECT department_id, last_name, hire_date, salary, <br>STDDEV_SAMP(salary) OVER <br>(PARTITION BY department_id ORDER BY hire_date <br>ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cum_sdev <br>FROM employees<br>WHERE department_id in (20,30,60);</p>
<p>DEPARTMENT_ID LAST_NAME HIRE_DATE SALARY CUM_SDEV<br>------------- ------------------------- ---------- ---------- ----------<br>20 Hartstein 17-2月 -96 13000<br>20 Fay 17-8月 -97 6000 4949.74747<br>30 Raphaely 07-12月-94 11000<br>30 Khoo 18-5月 -95 3100 5586.14357<br>30 Tobias 24-7月 -97 2800 4650.0896<br>30 Baida 24-12月-97 2900 4035.26125<br>30 Himuro 15-11月-98 2600 3649.2465<br>30 Colmenares 10-8月 -99 2500 3362.58829<br>60 Hunold 03-1月 -90 9000<br>60 Ernst 21-5月 -91 6000 2121.32034<br>60 Austin 25-6月 -97 4800 2163.33077<br>60 Pataballa 05-2月 -98 4800 1982.42276<br>60 Lorentz 07-2月 -99 4200 1925.61678</p>
<p><br>SUM <br>功能描述：该函数计算组中表达式的累积和。<br>SAMPLE：下例计算同一经理下员工的薪水累积值</p>
<p>SELECT manager_id, last_name, salary,<br>SUM (salary) OVER (PARTITION BY manager_id ORDER BY salary<br>RANGE UNBOUNDED PRECEDING) l_csum<br>FROM employees<br>WHERE manager_id in (101,103,108);</p>
<p>MANAGER_ID LAST_NAME SALARY L_CSUM<br>---------- ------------------------- ---------- ----------<br>101 Whalen 4400 4400<br>101 Mavris 6500 10900<br>101 Baer 10000 20900<br>101 Greenberg 12000 44900<br>101 Higgins 12000 44900<br>103 Lorentz 4200 4200<br>103 Austin 4800 13800<br>103 Pataballa 4800 13800<br>103 Ernst 6000 19800<br>108 Popp 6900 6900<br>108 Sciarra 7700 14600<br>108 Urman 7800 22400<br>108 Chen 8200 30600<br>108 Faviet 9000 39600</p>
<p><br>VAR_POP<br>功能描述：（Variance Population）该函数返回非空集合的总体变量（忽略null），VAR_POP进行如下计算：<br>(SUM(expr2) - SUM(expr)2 / COUNT(expr)) / COUNT(expr)<br>SAMPLE：下例计算1998年每月销售的累积总体和样本变量（本例在SH用户下运行）</p>
<p>SELECT t.calendar_month_desc,<br>VAR_POP(SUM(s.amount_sold)) <br>OVER (ORDER BY t.calendar_month_desc) "Var_Pop",<br>VAR_SAMP(SUM(s.amount_sold)) <br>OVER (ORDER BY t.calendar_month_desc) "Var_Samp" <br>FROM sales s, times t<br>WHERE s.time_id = t.time_id AND t.calendar_year = 1998<br>GROUP BY t.calendar_month_desc;</p>
<p>CALENDAR Var_Pop Var_Samp<br>-------- ---------- ----------<br>1998-01 0<br>1998-02 6.1321E+11 1.2264E+12<br>1998-03 4.7058E+11 7.0587E+11<br>1998-04 4.6929E+11 6.2572E+11<br>1998-05 1.5524E+12 1.9405E+12<br>1998-06 2.3711E+12 2.8453E+12<br>1998-07 3.7464E+12 4.3708E+12<br>1998-08 3.7852E+12 4.3260E+12<br>1998-09 3.5753E+12 4.0222E+12<br>1998-10 3.4343E+12 3.8159E+12<br>1998-11 3.4245E+12 3.7669E+12<br>1998-12 4.8937E+12 5.3386E+12</p>
<p><br>VAR_SAMP <br>功能描述：（Variance Sample）该函数返回非空集合的样本变量（忽略null），VAR_POP进行如下计算：<br>(SUM(expr*expr)-SUM(expr)*SUM(expr)/COUNT(expr))/(COUNT(expr)-1)<br>SAMPLE：下例计算1998年每月销售的累积总体和样本变量</p>
<p>SELECT t.calendar_month_desc,<br>VAR_POP(SUM(s.amount_sold)) <br>OVER (ORDER BY t.calendar_month_desc) "Var_Pop",<br>VAR_SAMP(SUM(s.amount_sold)) <br>OVER (ORDER BY t.calendar_month_desc) "Var_Samp" <br>FROM sales s, times t<br>WHERE s.time_id = t.time_id AND t.calendar_year = 1998<br>GROUP BY t.calendar_month_desc;</p>
<p>CALENDAR Var_Pop Var_Samp<br>-------- ---------- ----------<br>1998-01 0<br>1998-02 6.1321E+11 1.2264E+12<br>1998-03 4.7058E+11 7.0587E+11<br>1998-04 4.6929E+11 6.2572E+11<br>1998-05 1.5524E+12 1.9405E+12<br>1998-06 2.3711E+12 2.8453E+12<br>1998-07 3.7464E+12 4.3708E+12<br>1998-08 3.7852E+12 4.3260E+12<br>1998-09 3.5753E+12 4.0222E+12<br>1998-10 3.4343E+12 3.8159E+12<br>1998-11 3.4245E+12 3.7669E+12<br>1998-12 4.8937E+12 5.3386E+12</p>
<p><br>VARIANCE <br>功能描述：该函数返回表达式的变量，Oracle计算该变量如下：<br>如果表达式中行数为1，则返回0<br>如果表达式中行数大于1，则返回VAR_SAMP<br>SAMPLE：下例返回部门30按雇佣日期排序的薪水值的累积变化</p>
<p>SELECT last_name, salary, VARIANCE(salary) <br>OVER (ORDER BY hire_date) "Variance"<br>FROM employees <br>WHERE department_id = 30;</p>
<p>LAST_NAME SALARY Variance<br>------------------------- ---------- ----------<br>Raphaely 11000 0<br>Khoo 3100 31205000<br>Tobias 2800 21623333.3<br>Baida 2900 16283333.3<br>Himuro 2600 13317000<br>Colmenares 2500 11307000<br></p>
<img src ="http://www.blogjava.net/franlk/aggbug/118280.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-05-18 10:44 <a href="http://www.blogjava.net/franlk/articles/118280.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC、ODBC、不需配置DSN的几个数据库连接</title><link>http://www.blogjava.net/franlk/articles/109613.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 10 Apr 2007 05:36:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/109613.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/109613.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/109613.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/109613.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/109613.html</trackback:ping><description><![CDATA[<p><br>/*<br>&nbsp;* FranlkTest.java<br>&nbsp;* 模块:<br>&nbsp;* 版权所有:Franlk<br>&nbsp;*/</p>
<p><br>import java.sql.*;<br>/**<br>&nbsp;* 此类的简要说明:。<br>&nbsp;* &lt;p&gt;<br>&nbsp;* 创建日期：2007-4-10&lt;br&gt;<br>&nbsp;* 修改历史：&lt;br&gt;<br>&nbsp;* 修改日期：&lt;br&gt;<br>&nbsp;* 修改人&nbsp; ：&lt;br&gt;<br>&nbsp;* 修改内容：。&lt;br&gt;<br>&nbsp;* <br>&nbsp;* @author FRANLK<br>&nbsp;* @version 1.0<br>&nbsp;*/<br>public class FranlkTest {</p>
<p>&nbsp;public static void main(String[] args) {<br>&nbsp;&nbsp;System.out.println(4/2);<br>&nbsp;&nbsp;System.out.println(5 % 2);&nbsp;<br>&nbsp;&nbsp;System.out.println("=======================通过JDBC直接连ORACLE==========================================");<br>&nbsp;&nbsp;String driver ="oracle.jdbc.driver.OracleDriver";//驱动，一般用ojdbc14.jar包<br>&nbsp;&nbsp;String url = "jdbc:oracle:thin:@192.168.0.19:1521:YXDB";<br>&nbsp;&nbsp;String user ="userid";<br>&nbsp;&nbsp;String pwd = "oracle";<br>&nbsp;&nbsp;Connection conn = null;<br>&nbsp;&nbsp;try{<br>&nbsp;&nbsp;&nbsp;Class.forName(driver);<br>&nbsp;&nbsp;&nbsp;conn = DriverManager.getConnection(url,user,pwd);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;System.out.println("===conn========"+conn);<br>&nbsp;&nbsp;&nbsp;if(conn!=null){<br>&nbsp;&nbsp;&nbsp;&nbsp;conn.close();<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}catch(Exception ex){<br>&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;System.out.println("=======================不需要配置DSN连接Access==========================================");<br>&nbsp;&nbsp;String odbcDriver_1 = "sun.jdbc.odbc.JdbcOdbcDriver";//驱动，装完JDK在$JAVA_HOME$/jre/lib/rt.jar就有这个驱动。<br>&nbsp;&nbsp;String odbcUrl_1 = "jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=D://FRANLK//ACCESS_DB//FRANLK_ACCESS.mdb";&nbsp;<br>&nbsp;&nbsp;//&nbsp; D://FRANLK//ACCESS_DB//FRANLK_ACCESS.mdb 对应数据库文件。<br>&nbsp;&nbsp;String odbcUser_1 ="";<br>&nbsp;&nbsp;String odbcPwd_1 = "";<br>&nbsp;&nbsp;Connection odbcConn_1 = null;<br>&nbsp;&nbsp;try{<br>&nbsp;&nbsp;&nbsp;Class.forName(odbcDriver_1);<br>&nbsp;&nbsp;&nbsp;odbcConn_1 = DriverManager.getConnection(odbcUrl_1,odbcUser_1,odbcPwd_1);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;System.out.println("==odbcConn_1========="+odbcConn_1);<br>&nbsp;&nbsp;&nbsp;if(odbcConn_1!=null){<br>&nbsp;&nbsp;&nbsp;&nbsp;odbcConn_1.close();<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}catch(Exception ex){<br>&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br>&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;System.out.println("==================通过ODBC连接ORACLE;通过DSN===============================================");<br>&nbsp;&nbsp;String odbcDriver = "sun.jdbc.odbc.JdbcOdbcDriver";//驱动，装完JDK在$JAVA_HOME$/jre/lib/rt.jar就有这个驱动。<br>&nbsp;&nbsp;String odbcUrl = "jdbc:odbc:franlk_odbc";//franlk_odbc:ODBC数据源中配置的数据源名称&nbsp;&nbsp;<br>&nbsp;&nbsp;String odbcUser ="ydyx";<br>&nbsp;&nbsp;String odbcPwd = "ydyx";&nbsp;&nbsp;<br>&nbsp;&nbsp;try{<br>&nbsp;&nbsp;&nbsp;Class.forName(odbcDriver);<br>&nbsp;&nbsp;&nbsp;Connection odbcConn&nbsp; = DriverManager.getConnection(odbcUrl,odbcUser,odbcPwd);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;System.out.println("==odbcConn========="+odbcConn);<br>&nbsp;&nbsp;&nbsp;if(odbcConn!=null){<br>&nbsp;&nbsp;&nbsp;&nbsp;odbcConn.close();<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}catch(Exception ex){<br>&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;System.out.println("************不需要配置DSN连接FoxPro*****************************************");<br>&nbsp;&nbsp;try<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");//驱动，装完JDK在$JAVA_HOME$/jre/lib/rt.jar就有这个驱动。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; String sourceURL ="jdbc:odbc:driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=C://dfcb//dfcb_k;UID=;PWD=";//UID:用户名；PWD:密码&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp; C://dfcb//dfcb_kFoxPro ：对应*.dbf文件的目录。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection databaseConnection = DriverManager.getConnection(sourceURL);<br>&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("========="+databaseConnection);<br>&nbsp;&nbsp;&nbsp;&nbsp; if(databaseConnection!=null){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;databaseConnection.close();<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(ClassNotFoundException cnfe)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println(cnfe);<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(SQLException sqle)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println(sqle);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;}<br>}<br></p>
<img src ="http://www.blogjava.net/franlk/aggbug/109613.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-04-10 13:36 <a href="http://www.blogjava.net/franlk/articles/109613.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]JDBC连接的方式大全</title><link>http://www.blogjava.net/franlk/articles/109608.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Tue, 10 Apr 2007 05:09:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/109608.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/109608.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/109608.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/109608.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/109608.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://blog.donews.com/javapro/articles/491212.aspx">http://blog.donews.com/javapro/articles/491212.aspx</a><br><br>&nbsp;
<p><span>Java</span><span>数据库连接（</span><span>JDBC</span><span>）由一组用</span><span> Java </span><span>编程语言编写的类和接口组成。</span><span>JDBC </span><span>为工具</span><span>/</span><span>数据库开发人员提供了一个标准的</span><span> API</span><span>，使他们能够用纯</span><span>Java API </span><span>来编写数据库应用程序。然而各个开发商的接口并不完全相同，所以开发环境的变化会带来一定的配置变化。本文主要集合了不同数据库的连接方式。</span></p>
<p><span>一、连接各种数据库方式速查表</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>下面罗列了各种数据库使用</span><span>JDBC</span><span>连接的方式，可以作为一个手册使用。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>1</span><span>、</span><span>Oracle8/8i/9i</span><span>数据库（</span><span>thin</span><span>模式）</span><span> </span></p>
<p><span>Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); </span></p>
<p><span>String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl</span><span>为数据库的</span><span>SID </span></p>
<p><span>String user="test"; </span></p>
<p><span>String password="test"; </span></p>
<p><span>Connection conn= DriverManager.getConnection(url,user,password); </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>2</span><span>、</span><span>DB2</span><span>数据库</span><span> </span></p>
<p><span>Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance(); </span></p>
<p><span>String url="jdbc:db2://localhost:5000/sample"; //sample</span><span>为你的数据库名</span><span> </span></p>
<p><span>String user="admin"; </span></p>
<p><span>String password=""; </span></p>
<p><span>Connection conn= DriverManager.getConnection(url,user,password); </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>3</span><span>、</span><span>Sql Server7.0/2000</span><span>数据库</span><span> </span></p>
<p><span>Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance(); </span></p>
<p><span>String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"; </span></p>
<p><span>//mydb</span><span>为数据库</span><span> </span></p>
<p><span>String user="sa"; </span></p>
<p><span>String password=""; </span></p>
<p><span>Connection conn= DriverManager.getConnection(url,user,password); </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>4</span><span>、</span><span>Sybase</span><span>数据库</span><span> </span></p>
<p><span>Class.forName("com.sybase.jdbc.SybDriver").newInstance(); </span></p>
<p><span>String url =" jdbc:sybase:Tds:localhost:5007/myDB";//myDB</span><span>为你的数据库名</span><span> </span></p>
<p><span>Properties sysProps = System.getProperties(); </span></p>
<p><span>SysProps.put("user","userid"); </span></p>
<p><span>SysProps.put("password","user_password"); </span></p>
<p><span>Connection conn= DriverManager.getConnection(url, SysProps); </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>5</span><span>、</span><span>Informix</span><span>数据库</span><span> </span></p>
<p><span>Class.forName("com.informix.jdbc.IfxDriver").newInstance(); </span></p>
<p><span>String url = </span></p>
<p><span>"jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver; </span></p>
<p><span>user=testuser;password=testpassword"; //myDB</span><span>为数据库名</span><span> </span></p>
<p><span>Connection conn= DriverManager.getConnection(url); </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>6</span><span>、</span><span>MySQL</span><span>数据库</span><span> </span></p>
<p><span>Class.forName("org.gjt.mm.mysql.Driver").newInstance(); </span></p>
<p><span>String url ="jdbc:mysql://localhost/myDB?user=soft&amp;password=soft1234&amp;useUnicode=true&amp;characterEncoding=8859_1" </span></p>
<p><span>//myDB</span><span>为数据库名</span><span> </span></p>
<p><span>Connection conn= DriverManager.getConnection(url); </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>7</span><span>、</span><span>PostgreSQL</span><span>数据库</span><span> </span></p>
<p><span>Class.forName("org.postgresql.Driver").newInstance(); </span></p>
<p><span>String url ="jdbc:postgresql://localhost/myDB" //myDB</span><span>为数据库名</span><span> </span></p>
<p><span>String user="myuser"; </span></p>
<p><span>String password="mypassword"; </span></p>
<p><span>Connection conn= DriverManager.getConnection(url,user,password); </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>8</span><span>、</span><span>access</span><span>数据库直连用</span><span>ODBC</span><span>的</span></p>
<p><span>Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;</span></p>
<p><span>String url="jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ="+application.getRealPath("/Data/ReportDemo.mdb");</span></p>
<p><span>Connection conn = DriverManager.getConnection(url,"","");</span></p>
<p><span>&nbsp;Statement stmtNew=conn.createStatement() ;</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>二、</span><span>JDBC</span><span>连接</span><span>MySql</span><span>方式</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>下面是使用</span><span>JDBC</span><span>连接</span><span>MySql</span><span>的一个小的教程</span><span><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>1</span><span>、查找驱动程序</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>MySQL</span><span>目前提供的</span><span>java</span><span>驱动程序为</span><span>Connection/J</span><span>，可以从</span><span>MySQL</span><span>官方网站下载，并找到</span><span>mysql-connector-java-3.0.15-ga-bin.jar</span><span>文件，此驱动程序为纯</span><span>java</span><span>驱动程序，不需做其他配置。</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>2</span><span>、动态指定</span><span>classpath</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>如果需要执行时动态指定</span><span>classpath</span><span>，就在执行时采用－</span><span>cp</span><span>方式。否则将上面的</span><span>.jar</span><span>文件加入到</span><span>classpath</span><span>环境变量中。</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>3</span><span>、加载驱动程序</span></p>
<p><span>try{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>Class.forName(com.mysql.jdbc.Driver);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>System.out.println(Success loading Mysql Driver!);</span></p>
<p><span>}catch(Exception e)</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>System.out.println(Error loading Mysql Driver!);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>e.printStackTrace();</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>4</span><span>、设置连接的</span><span>url</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>jdbc</span><span>：</span><span>mysql</span><span>：</span><span>//localhost/databasename[?pa=va][</span><span>＆</span><span>pa=va]</span></p>
<p>&nbsp;</p>
<p><span>三、以下列出了在使用</span><span>JDBC</span><span>来连接</span><span>Oracle</span><span>数据库时可以使用的一些技巧，这些技巧能够使我们更好地发挥系统的性能和实现更多的功能（系转载）。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1</span><span>、在客户端软件开发中使用</span><span>Thin</span><span>驱动程序</span></p>
<p>&nbsp;</p>
<p><span>　　在开发</span><span>Java</span><span>软件方面，</span><span>Oracle</span><span>的数据库提供了四种类型的驱动程序，二种用于应用软件、</span><span>applets</span><span>、</span><span>servlets</span><span>等客户端软件，另外二种用于数据库中的</span><span>Java</span><span>存储过程等服务器端软件。在客户机端软件的开发中，我们可以选择</span><span>OCI</span><span>驱动程序或</span><span>Thin</span><span>驱动程序。</span><span>OCI</span><span>驱动程序利用</span><span>Java</span><span>本地化接口（</span><span>JNI</span><span>），通过</span><span>Oracle</span><span>客户端软件与数据库进行通讯。</span><span>Thin</span><span>驱动程序是纯</span><span>Java</span><span>驱动程序，它直接与数据库进行通讯。为了获得最高的性能，</span><span>Oracle</span><span>建议在客户端软件的开发中使用</span><span>OCI</span><span>驱动程序，这似乎是正确的。但我建议使用</span><span>Thin</span><span>驱动程序，因为通过多次测试发现，在通常情况下，</span><span>Thin</span><span>驱动程序的性能都超过了</span><span>OCI</span><span>驱动程序。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>2</span><span>、关闭自动提交功能，提高系统性能</span></p>
<p>&nbsp;</p>
<p><span>　　在第一次建立与数据库的连接时，在缺省情况下，连接是在自动提交模式下的。为了获得更好的性能，可以通过调用带布尔值</span><span>false</span><span>参数的</span><span>Connection</span><span>类的</span><span>setAutoCommit()</span><span>方法关闭自动提交功能，如下所示：</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>conn.setAutoCommit(false);</span></p>
<p>&nbsp;</p>
<p><span>　　值得注意的是，一旦关闭了自动提交功能，我们就需要通过调用</span><span>Connection</span><span>类的</span><span>commit()</span><span>和</span><span>rollback()</span><span>方法来人工的方式对事务进行管理。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>3</span><span>、在动态</span><span>SQL</span><span>或有时间限制的命令中使用</span><span>Statement</span><span>对象</span></p>
<p>&nbsp;</p>
<p><span>　　在执行</span><span>SQL</span><span>命令时，我们有二种选择：可以使用</span><span>PreparedStatement</span><span>对象，也可以使用</span><span>Statement</span><span>对象。无论多少次地使用同一个</span><span>SQL</span><span>命令，</span><span>PreparedStatement</span><span>都只对它解析和编译一次。当使用</span><span>Statement</span><span>对象时，每次执行一个</span><span>SQL</span><span>命令时，都会对它进行解析和编译。这可能会使你认为，使用</span><span>PreparedStatement</span><span>对象比使用</span><span>Statement</span><span>对象的速度更快。然而，我进行的测试表明，在客户端软件中，情况并非如此。因此，在有时间限制的</span><span>SQL</span><span>操作中，除非成批地处理</span><span>SQL</span><span>命令，我们应当考虑使用</span><span>Statement</span><span>对象。</span></p>
<p>&nbsp;</p>
<p><span>　　此外，使用</span><span>Statement</span><span>对象也使得编写动态</span><span>SQL</span><span>命令更加简单，因为我们可以将字符串连接在一起，建立一个有效的</span><span>SQL</span><span>命令。因此，我认为，</span><span>Statement</span><span>对象可以使动态</span><span>SQL</span><span>命令的创建和执行变得更加简单。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>4</span><span>、利用</span><span>helper</span><span>函数对动态</span><span>SQL</span><span>命令进行格式化</span></p>
<p>&nbsp;</p>
<p><span>　　在创建使用</span><span>Statement</span><span>对象执行的动态</span><span>SQL</span><span>命令时，我们需要处理一些格式化方面的问题。例如，如果我们想创建一个将名字</span><span>O'Reilly</span><span>插入表中的</span><span>SQL</span><span>命令，则必须使用二个相连的&#8220;</span><span>''</span><span>&#8221;号替换</span><span>O'Reilly</span><span>中的&#8220;</span><span>'</span><span>&#8221;号。完成这些工作的最好的方法是创建一个完成替换操作的</span><span>helper</span><span>方法，然后在连接字符串心服用公式表达一个</span><span>SQL</span><span>命令时，使用创建的</span><span>helper</span><span>方法。与此类似的是，我们可以让</span><span>helper</span><span>方法接受一个</span><span>Date</span><span>型的值，然后让它输出基于</span><span>Oracle</span><span>的</span><span>to_date()</span><span>函数的字符串表达式。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>5</span><span>、利用</span><span>PreparedStatement</span><span>对象提高数据库的总体效率</span></p>
<p>&nbsp;</p>
<p><span>　　在使用</span><span>PreparedStatement</span><span>对象执行</span><span>SQL</span><span>命令时，命令被数据库进行解析和编译，然后被放到命令缓冲区。然后，每当执行同一个</span><span>PreparedStatement</span><span>对象时，它就会被再解析一次，但不会被再次编译。在缓冲区中可以发现预编译的命令，并且可以重新使用。在有大量用户的企业级应用软件中，经常会重复执行相同的</span><span>SQL</span><span>命令，使用</span><span>PreparedStatement</span><span>对象带来的编译次数的减少能够提高数据库的总体性能。如果不是在客户端创建、预备、执行</span><span>PreparedStatement</span><span>任务需要的时间长于</span><span>Statement</span><span>任务，我会建议在除动态</span><span>SQL</span><span>命令之外的所有情况下使用</span><span>PreparedStatement</span><span>对象。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>6</span><span>、在成批处理重复的插入或更新操作中使用</span><span>PreparedStatement</span><span>对象</span></p>
<p>&nbsp;</p>
<p><span>　　如果成批地处理插入和更新操作，就能够显著地减少它们所需要的时间。</span><span>Oracle</span><span>提供的</span><span>Statement</span><span>和</span><span> CallableStatement</span><span>并不真正地支持批处理，只有</span><span>PreparedStatement</span><span>对象才真正地支持批处理。我们可以使用</span><span>addBatch()</span><span>和</span><span>executeBatch()</span><span>方法选择标准的</span><span>JDBC</span><span>批处理，或者通过利用</span><span>PreparedStatement</span><span>对象的</span><span>setExecuteBatch()</span><span>方法和标准的</span><span>executeUpdate()</span><span>方法选择速度更快的</span><span>Oracle</span><span>专有的方法。要使用</span><span>Oracle</span><span>专有的批处理机制，可以以如下所示的方式调用</span><span>setExecuteBatch()</span><span>：</span></p>
<p><span>PreparedStatement pstmt3D null;</span></p>
<p><span>try {</span></p>
<p><span>((OraclePreparedStatement)</span></p>
<p><span>pstmt).setExecuteBatch(30);</span></p>
<p><span>...</span></p>
<p><span>pstmt.executeUpdate();</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>　　调用</span><span>setExecuteBatch()</span><span>时指定的值是一个上限，当达到该值时，就会自动地引发</span><span>SQL</span><span>命令执行，标准的</span><span>executeUpdate()</span><span>方法就会被作为批处理送到数据库中。我们可以通过调用</span><span>PreparedStatement</span><span>类的</span><span>sendBatch()</span><span>方法随时传输批处理任务。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>7</span><span>、使用</span><span>Oracle locator</span><span>方法插入、更新大对象（</span><span>LOB</span><span>）</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>Oracle</span><span>的</span><span>PreparedStatement</span><span>类不完全支持</span><span>BLOB</span><span>和</span><span>CLOB</span><span>等大对象的处理，尤其是</span><span>Thin</span><span>驱动程序不支持利用</span><span>PreparedStatement</span><span>对象的</span><span>setObject()</span><span>和</span><span>setBinaryStream()</span><span>方法设置</span><span>BLOB</span><span>的值，也不支持利用</span><span>setCharacterStream()</span><span>方法设置</span><span>CLOB</span><span>的值。只有</span><span>locator</span><span>本身中的方法才能够从数据库中获取</span><span>LOB</span><span>类型的值。可以使用</span><span>PreparedStatement</span><span>对象插入或更新</span><span>LOB</span><span>，但需要使用</span><span>locator</span><span>才能获取</span><span>LOB</span><span>的值。由于存在这二个问题，因此，我建议使用</span><span>locator</span><span>的方法来插入、更新或获取</span><span>LOB</span><span>的值。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>8</span><span>、使用</span><span>SQL92</span><span>语法调用存储过程</span></p>
<p>&nbsp;</p>
<p><span>　　在调用存储过程时，我们可以使用</span><span>SQL92</span><span>或</span><span>Oracle PL/SQL</span><span>，由于使用</span><span>Oracle PL/SQL</span><span>并没有什么实际的好处，而且会给以后维护你的应用程序的开发人员带来麻烦，因此，我建议在调用存储过程时使用</span><span>SQL92</span><span>。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>9</span><span>、使用</span><span>Object SQL</span><span>将对象模式转移到数据库中</span></p>
<p>&nbsp;</p>
<p><span>　　既然可以将</span><span>Oracle</span><span>的数据库作为一种面向对象的数据库来使用，就可以考虑将应用程序中的面向对象模式转到数据库中。目前的方法是创建</span><span>Java bean</span><span>作为伪装的数据库对象，将它们的属性映射到关系表中，然后在这些</span><span>bean</span><span>中添加方法。尽管这样作在</span><span>Java</span><span>中没有什么问题，但由于操作都是在数据库之外进行的，因此其他访问数据库的应用软件无法利用对象模式。如果利用</span><span>Oracle</span><span>的面向对象的技术，可以通过创建一个新的数据库对象类型在数据库中模仿其数据和操作，然后使用</span><span>JPublisher</span><span>等工具生成自己的</span><span>Java bean</span><span>类。如果使用这种方式，不但</span><span>Java</span><span>应用程序可以使用应用软件的对象模式，其他需要共享你的应用中的数据和操作的应用软件也可以使用应用软件中的对象模式。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>10</span><span>、利用</span><span>SQL</span><span>完成数据库内的操作</span></p>
<p>&nbsp;</p>
<p><span>　　我要向大家介绍的最重要的经验是充分利用</span><span>SQL</span><span>的面向集合的方法来解决数据库处理需求，而不是使用</span><span>Java</span><span>等过程化的编程语言。</span></p>
<p>&nbsp;</p>
<p><span>　　如果编程人员要在一个表中查找许多行，结果中的每个行都会查找其他表中的数据，最后，编程人员创建了独立的</span><span>UPDATE</span><span>命令来成批地更新第一个表中的数据。与此类似的任务可以通过在</span><span>set</span><span>子句中使用多列子查询而在一个</span><span>UPDATE</span><span>命令中完成。当能够在单一的</span><span>SQL</span><span>命令中完成任务，何必要让数据在网上流来流去的？我建议用户认真学习如何最大限度地发挥</span><span>SQL</span><span>的功能。</span><span> </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>二、</span><span>JDBC</span><span>连接</span><span>MySql</span><span>方式</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>下面是使用</span><span>JDBC</span><span>连接</span><span>MySql</span><span>的一个小的教程</span><span><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>1</span><span>、查找驱动程序</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>MySQL</span><span>目前提供的</span><span>java</span><span>驱动程序为</span><span>Connection/J</span><span>，可以从</span><span>MySQL</span><span>官方网站下载，并找到</span><span>mysql-connector-java-3.0.15-ga-bin.jar</span><span>文件，此驱动程序为纯</span><span>java</span><span>驱动程序，不需做其他配置。</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>2</span><span>、动态指定</span><span>classpath</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>如果需要执行时动态指定</span><span>classpath</span><span>，就在执行时采用－</span><span>cp</span><span>方式。否则将上面的</span><span>.jar</span><span>文件加入到</span><span>classpath</span><span>环境变量中。</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>3</span><span>、加载驱动程序</span></p>
<p><span>try{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>Class.forName(com.mysql.jdbc.Driver);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>System.out.println(Success loading Mysql Driver!);</span></p>
<p><span>}catch(Exception e)</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>System.out.println(Error loading Mysql Driver!);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>e.printStackTrace();</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>4</span><span>、设置连接的</span><span>url</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>jdbc</span><span>：</span><span>mysql</span><span>：</span><span>//localhost/databasename[?pa=va][</span><span>＆</span><span>pa=va]</span></p>
<p>&nbsp;</p>
<p><span>三、以下列出了在使用</span><span>JDBC</span><span>来连接</span><span>Oracle</span><span>数据库时可以使用的一些技巧，这些技巧能够使我们更好地发挥系统的性能和实现更多的功能（系转载）。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1</span><span>、在客户端软件开发中使用</span><span>Thin</span><span>驱动程序</span></p>
<p>&nbsp;</p>
<p><span>　　在开发</span><span>Java</span><span>软件方面，</span><span>Oracle</span><span>的数据库提供了四种类型的驱动程序，二种用于应用软件、</span><span>applets</span><span>、</span><span>servlets</span><span>等客户端软件，另外二种用于数据库中的</span><span>Java</span><span>存储过程等服务器端软件。在客户机端软件的开发中，我们可以选择</span><span>OCI</span><span>驱动程序或</span><span>Thin</span><span>驱动程序。</span><span>OCI</span><span>驱动程序利用</span><span>Java</span><span>本地化接口（</span><span>JNI</span><span>），通过</span><span>Oracle</span><span>客户端软件与数据库进行通讯。</span><span>Thin</span><span>驱动程序是纯</span><span>Java</span><span>驱动程序，它直接与数据库进行通讯。为了获得最高的性能，</span><span>Oracle</span><span>建议在客户端软件的开发中使用</span><span>OCI</span><span>驱动程序，这似乎是正确的。但我建议使用</span><span>Thin</span><span>驱动程序，因为通过多次测试发现，在通常情况下，</span><span>Thin</span><span>驱动程序的性能都超过了</span><span>OCI</span><span>驱动程序。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>2</span><span>、关闭自动提交功能，提高系统性能</span></p>
<p>&nbsp;</p>
<p><span>　　在第一次建立与数据库的连接时，在缺省情况下，连接是在自动提交模式下的。为了获得更好的性能，可以通过调用带布尔值</span><span>false</span><span>参数的</span><span>Connection</span><span>类的</span><span>setAutoCommit()</span><span>方法关闭自动提交功能，如下所示：</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>conn.setAutoCommit(false);</span></p>
<p>&nbsp;</p>
<p><span>　　值得注意的是，一旦关闭了自动提交功能，我们就需要通过调用</span><span>Connection</span><span>类的</span><span>commit()</span><span>和</span><span>rollback()</span><span>方法来人工的方式对事务进行管理。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>3</span><span>、在动态</span><span>SQL</span><span>或有时间限制的命令中使用</span><span>Statement</span><span>对象</span></p>
<p>&nbsp;</p>
<p><span>　　在执行</span><span>SQL</span><span>命令时，我们有二种选择：可以使用</span><span>PreparedStatement</span><span>对象，也可以使用</span><span>Statement</span><span>对象。无论多少次地使用同一个</span><span>SQL</span><span>命令，</span><span>PreparedStatement</span><span>都只对它解析和编译一次。当使用</span><span>Statement</span><span>对象时，每次执行一个</span><span>SQL</span><span>命令时，都会对它进行解析和编译。这可能会使你认为，使用</span><span>PreparedStatement</span><span>对象比使用</span><span>Statement</span><span>对象的速度更快。然而，我进行的测试表明，在客户端软件中，情况并非如此。因此，在有时间限制的</span><span>SQL</span><span>操作中，除非成批地处理</span><span>SQL</span><span>命令，我们应当考虑使用</span><span>Statement</span><span>对象。</span></p>
<p>&nbsp;</p>
<p><span>　　此外，使用</span><span>Statement</span><span>对象也使得编写动态</span><span>SQL</span><span>命令更加简单，因为我们可以将字符串连接在一起，建立一个有效的</span><span>SQL</span><span>命令。因此，我认为，</span><span>Statement</span><span>对象可以使动态</span><span>SQL</span><span>命令的创建和执行变得更加简单。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>4</span><span>、利用</span><span>helper</span><span>函数对动态</span><span>SQL</span><span>命令进行格式化</span></p>
<p>&nbsp;</p>
<p><span>　　在创建使用</span><span>Statement</span><span>对象执行的动态</span><span>SQL</span><span>命令时，我们需要处理一些格式化方面的问题。例如，如果我们想创建一个将名字</span><span>O'Reilly</span><span>插入表中的</span><span>SQL</span><span>命令，则必须使用二个相连的&#8220;</span><span>''</span><span>&#8221;号替换</span><span>O'Reilly</span><span>中的&#8220;</span><span>'</span><span>&#8221;号。完成这些工作的最好的方法是创建一个完成替换操作的</span><span>helper</span><span>方法，然后在连接字符串心服用公式表达一个</span><span>SQL</span><span>命令时，使用创建的</span><span>helper</span><span>方法。与此类似的是，我们可以让</span><span>helper</span><span>方法接受一个</span><span>Date</span><span>型的值，然后让它输出基于</span><span>Oracle</span><span>的</span><span>to_date()</span><span>函数的字符串表达式。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>5</span><span>、利用</span><span>PreparedStatement</span><span>对象提高数据库的总体效率</span></p>
<p>&nbsp;</p>
<p><span>　　在使用</span><span>PreparedStatement</span><span>对象执行</span><span>SQL</span><span>命令时，命令被数据库进行解析和编译，然后被放到命令缓冲区。然后，每当执行同一个</span><span>PreparedStatement</span><span>对象时，它就会被再解析一次，但不会被再次编译。在缓冲区中可以发现预编译的命令，并且可以重新使用。在有大量用户的企业级应用软件中，经常会重复执行相同的</span><span>SQL</span><span>命令，使用</span><span>PreparedStatement</span><span>对象带来的编译次数的减少能够提高数据库的总体性能。如果不是在客户端创建、预备、执行</span><span>PreparedStatement</span><span>任务需要的时间长于</span><span>Statement</span><span>任务，我会建议在除动态</span><span>SQL</span><span>命令之外的所有情况下使用</span><span>PreparedStatement</span><span>对象。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>6</span><span>、在成批处理重复的插入或更新操作中使用</span><span>PreparedStatement</span><span>对象</span></p>
<p>&nbsp;</p>
<p><span>　　如果成批地处理插入和更新操作，就能够显著地减少它们所需要的时间。</span><span>Oracle</span><span>提供的</span><span>Statement</span><span>和</span><span> CallableStatement</span><span>并不真正地支持批处理，只有</span><span>PreparedStatement</span><span>对象才真正地支持批处理。我们可以使用</span><span>addBatch()</span><span>和</span><span>executeBatch()</span><span>方法选择标准的</span><span>JDBC</span><span>批处理，或者通过利用</span><span>PreparedStatement</span><span>对象的</span><span>setExecuteBatch()</span><span>方法和标准的</span><span>executeUpdate()</span><span>方法选择速度更快的</span><span>Oracle</span><span>专有的方法。要使用</span><span>Oracle</span><span>专有的批处理机制，可以以如下所示的方式调用</span><span>setExecuteBatch()</span><span>：</span></p>
<p><span>PreparedStatement pstmt3D null;</span></p>
<p><span>try {</span></p>
<p><span>((OraclePreparedStatement)</span></p>
<p><span>pstmt).setExecuteBatch(30);</span></p>
<p><span>...</span></p>
<p><span>pstmt.executeUpdate();</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>　　调用</span><span>setExecuteBatch()</span><span>时指定的值是一个上限，当达到该值时，就会自动地引发</span><span>SQL</span><span>命令执行，标准的</span><span>executeUpdate()</span><span>方法就会被作为批处理送到数据库中。我们可以通过调用</span><span>PreparedStatement</span><span>类的</span><span>sendBatch()</span><span>方法随时传输批处理任务。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>7</span><span>、使用</span><span>Oracle locator</span><span>方法插入、更新大对象（</span><span>LOB</span><span>）</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>Oracle</span><span>的</span><span>PreparedStatement</span><span>类不完全支持</span><span>BLOB</span><span>和</span><span>CLOB</span><span>等大对象的处理，尤其是</span><span>Thin</span><span>驱动程序不支持利用</span><span>PreparedStatement</span><span>对象的</span><span>setObject()</span><span>和</span><span>setBinaryStream()</span><span>方法设置</span><span>BLOB</span><span>的值，也不支持利用</span><span>setCharacterStream()</span><span>方法设置</span><span>CLOB</span><span>的值。只有</span><span>locator</span><span>本身中的方法才能够从数据库中获取</span><span>LOB</span><span>类型的值。可以使用</span><span>PreparedStatement</span><span>对象插入或更新</span><span>LOB</span><span>，但需要使用</span><span>locator</span><span>才能获取</span><span>LOB</span><span>的值。由于存在这二个问题，因此，我建议使用</span><span>locator</span><span>的方法来插入、更新或获取</span><span>LOB</span><span>的值。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>8</span><span>、使用</span><span>SQL92</span><span>语法调用存储过程</span></p>
<p>&nbsp;</p>
<p><span>　　在调用存储过程时，我们可以使用</span><span>SQL92</span><span>或</span><span>Oracle PL/SQL</span><span>，由于使用</span><span>Oracle PL/SQL</span><span>并没有什么实际的好处，而且会给以后维护你的应用程序的开发人员带来麻烦，因此，我建议在调用存储过程时使用</span><span>SQL92</span><span>。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>9</span><span>、使用</span><span>Object SQL</span><span>将对象模式转移到数据库中</span></p>
<p>&nbsp;</p>
<p><span>　　既然可以将</span><span>Oracle</span><span>的数据库作为一种面向对象的数据库来使用，就可以考虑将应用程序中的面向对象模式转到数据库中。目前的方法是创建</span><span>Java bean</span><span>作为伪装的数据库对象，将它们的属性映射到关系表中，然后在这些</span><span>bean</span><span>中添加方法。尽管这样作在</span><span>Java</span><span>中没有什么问题，但由于操作都是在数据库之外进行的，因此其他访问数据库的应用软件无法利用对象模式。如果利用</span><span>Oracle</span><span>的面向对象的技术，可以通过创建一个新的数据库对象类型在数据库中模仿其数据和操作，然后使用</span><span>JPublisher</span><span>等工具生成自己的</span><span>Java bean</span><span>类。如果使用这种方式，不但</span><span>Java</span><span>应用程序可以使用应用软件的对象模式，其他需要共享你的应用中的数据和操作的应用软件也可以使用应用软件中的对象模式。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>10</span><span>、利用</span><span>SQL</span><span>完成数据库内的操作</span></p>
<p>&nbsp;</p>
<p><span>　　我要向大家介绍的最重要的经验是充分利用</span><span>SQL</span><span>的面向集合的方法来解决数据库处理需求，而不是使用</span><span>Java</span><span>等过程化的编程语言。</span></p>
<p>&nbsp;</p>
<p><span>　　如果编程人员要在一个表中查找许多行，结果中的每个行都会查找其他表中的数据，最后，编程人员创建了独立的</span><span>UPDATE</span><span>命令来成批地更新第一个表中的数据。与此类似的任务可以通过在</span><span>set</span><span>子句中使用多列子查询而在一个</span><span>UPDATE</span><span>命令中完成。当能够在单一的</span><span>SQL</span><span>命令中完成任务，何必要让数据在网上流来流去的？我建议用户认真学习如何最大限度地发挥</span><span>SQL</span><span>的功能。</span><span> </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>1</span><span>、查找驱动程序</span></p>
<p><span>&nbsp;<span>&nbsp;&nbsp; </span>MySQL</span><span>目前提供的</span><span>java</span><span>驱动程序为</span><span>Connection/J</span><span>，可以从</span><span>MySQL</span><span>官方网站下载，并找到</span><span>mysql-connector-java-3.0.15-ga-bin.jar</span><span>文件，此驱动程序为纯</span><span>java</span><span>驱动程序，不需做其他配置。</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>2</span><span>、动态指定</span><span>classpath</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>如果需要执行时动态指定</span><span>classpath</span><span>，就在执行时采用－</span><span>cp</span><span>方式。否则将上面的</span><span>.jar</span><span>文件加入到</span><span>classpath</span><span>环境变量中。</span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>3</span><span>、加载驱动程序</span></p>
<p><span>try{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>Class.forName(com.mysql.jdbc.Driver);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>System.out.println(Success loading Mysql Driver!);</span></p>
<p><span>}catch(Exception e)</span></p>
<p><span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>System.out.println(Error loading Mysql Driver!);</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>e.printStackTrace();</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>4</span><span>、设置连接的</span><span>url</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>jdbc</span><span>：</span><span>mysql</span><span>：</span><span>//localhost/databasename[?pa=va][</span><span>＆</span><span>pa=va]</span></p>
<p>&nbsp;</p>
<p><span>三、以下列出了在使用</span><span>JDBC</span><span>来连接</span><span>Oracle</span><span>数据库时可以使用的一些技巧，这些技巧能够使我们更好地发挥系统的性能和实现更多的功能（系转载）。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>1</span><span>、在客户端软件开发中使用</span><span>Thin</span><span>驱动程序</span></p>
<p>&nbsp;</p>
<p><span>　　在开发</span><span>Java</span><span>软件方面，</span><span>Oracle</span><span>的数据库提供了四种类型的驱动程序，二种用于应用软件、</span><span>applets</span><span>、</span><span>servlets</span><span>等客户端软件，另外二种用于数据库中的</span><span>Java</span><span>存储过程等服务器端软件。在客户机端软件的开发中，我们可以选择</span><span>OCI</span><span>驱动程序或</span><span>Thin</span><span>驱动程序。</span><span>OCI</span><span>驱动程序利用</span><span>Java</span><span>本地化接口（</span><span>JNI</span><span>），通过</span><span>Oracle</span><span>客户端软件与数据库进行通讯。</span><span>Thin</span><span>驱动程序是纯</span><span>Java</span><span>驱动程序，它直接与数据库进行通讯。为了获得最高的性能，</span><span>Oracle</span><span>建议在客户端软件的开发中使用</span><span>OCI</span><span>驱动程序，这似乎是正确的。但我建议使用</span><span>Thin</span><span>驱动程序，因为通过多次测试发现，在通常情况下，</span><span>Thin</span><span>驱动程序的性能都超过了</span><span>OCI</span><span>驱动程序。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>2</span><span>、关闭自动提交功能，提高系统性能</span></p>
<p>&nbsp;</p>
<p><span>　　在第一次建立与数据库的连接时，在缺省情况下，连接是在自动提交模式下的。为了获得更好的性能，可以通过调用带布尔值</span><span>false</span><span>参数的</span><span>Connection</span><span>类的</span><span>setAutoCommit()</span><span>方法关闭自动提交功能，如下所示：</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>conn.setAutoCommit(false);</span></p>
<p>&nbsp;</p>
<p><span>　　值得注意的是，一旦关闭了自动提交功能，我们就需要通过调用</span><span>Connection</span><span>类的</span><span>commit()</span><span>和</span><span>rollback()</span><span>方法来人工的方式对事务进行管理。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>3</span><span>、在动态</span><span>SQL</span><span>或有时间限制的命令中使用</span><span>Statement</span><span>对象</span></p>
<p>&nbsp;</p>
<p><span>　　在执行</span><span>SQL</span><span>命令时，我们有二种选择：可以使用</span><span>PreparedStatement</span><span>对象，也可以使用</span><span>Statement</span><span>对象。无论多少次地使用同一个</span><span>SQL</span><span>命令，</span><span>PreparedStatement</span><span>都只对它解析和编译一次。当使用</span><span>Statement</span><span>对象时，每次执行一个</span><span>SQL</span><span>命令时，都会对它进行解析和编译。这可能会使你认为，使用</span><span>PreparedStatement</span><span>对象比使用</span><span>Statement</span><span>对象的速度更快。然而，我进行的测试表明，在客户端软件中，情况并非如此。因此，在有时间限制的</span><span>SQL</span><span>操作中，除非成批地处理</span><span>SQL</span><span>命令，我们应当考虑使用</span><span>Statement</span><span>对象。</span></p>
<p>&nbsp;</p>
<p><span>　　此外，使用</span><span>Statement</span><span>对象也使得编写动态</span><span>SQL</span><span>命令更加简单，因为我们可以将字符串连接在一起，建立一个有效的</span><span>SQL</span><span>命令。因此，我认为，</span><span>Statement</span><span>对象可以使动态</span><span>SQL</span><span>命令的创建和执行变得更加简单。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>4</span><span>、利用</span><span>helper</span><span>函数对动态</span><span>SQL</span><span>命令进行格式化</span></p>
<p>&nbsp;</p>
<p><span>　　在创建使用</span><span>Statement</span><span>对象执行的动态</span><span>SQL</span><span>命令时，我们需要处理一些格式化方面的问题。例如，如果我们想创建一个将名字</span><span>O'Reilly</span><span>插入表中的</span><span>SQL</span><span>命令，则必须使用二个相连的&#8220;</span><span>''</span><span>&#8221;号替换</span><span>O'Reilly</span><span>中的&#8220;</span><span>'</span><span>&#8221;号。完成这些工作的最好的方法是创建一个完成替换操作的</span><span>helper</span><span>方法，然后在连接字符串心服用公式表达一个</span><span>SQL</span><span>命令时，使用创建的</span><span>helper</span><span>方法。与此类似的是，我们可以让</span><span>helper</span><span>方法接受一个</span><span>Date</span><span>型的值，然后让它输出基于</span><span>Oracle</span><span>的</span><span>to_date()</span><span>函数的字符串表达式。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>5</span><span>、利用</span><span>PreparedStatement</span><span>对象提高数据库的总体效率</span></p>
<p>&nbsp;</p>
<p><span>　　在使用</span><span>PreparedStatement</span><span>对象执行</span><span>SQL</span><span>命令时，命令被数据库进行解析和编译，然后被放到命令缓冲区。然后，每当执行同一个</span><span>PreparedStatement</span><span>对象时，它就会被再解析一次，但不会被再次编译。在缓冲区中可以发现预编译的命令，并且可以重新使用。在有大量用户的企业级应用软件中，经常会重复执行相同的</span><span>SQL</span><span>命令，使用</span><span>PreparedStatement</span><span>对象带来的编译次数的减少能够提高数据库的总体性能。如果不是在客户端创建、预备、执行</span><span>PreparedStatement</span><span>任务需要的时间长于</span><span>Statement</span><span>任务，我会建议在除动态</span><span>SQL</span><span>命令之外的所有情况下使用</span><span>PreparedStatement</span><span>对象。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>6</span><span>、在成批处理重复的插入或更新操作中使用</span><span>PreparedStatement</span><span>对象</span></p>
<p>&nbsp;</p>
<p><span>　　如果成批地处理插入和更新操作，就能够显著地减少它们所需要的时间。</span><span>Oracle</span><span>提供的</span><span>Statement</span><span>和</span><span> CallableStatement</span><span>并不真正地支持批处理，只有</span><span>PreparedStatement</span><span>对象才真正地支持批处理。我们可以使用</span><span>addBatch()</span><span>和</span><span>executeBatch()</span><span>方法选择标准的</span><span>JDBC</span><span>批处理，或者通过利用</span><span>PreparedStatement</span><span>对象的</span><span>setExecuteBatch()</span><span>方法和标准的</span><span>executeUpdate()</span><span>方法选择速度更快的</span><span>Oracle</span><span>专有的方法。要使用</span><span>Oracle</span><span>专有的批处理机制，可以以如下所示的方式调用</span><span>setExecuteBatch()</span><span>：</span></p>
<p><span>PreparedStatement pstmt3D null;</span></p>
<p><span>try {</span></p>
<p><span>((OraclePreparedStatement)</span></p>
<p><span>pstmt).setExecuteBatch(30);</span></p>
<p><span>...</span></p>
<p><span>pstmt.executeUpdate();</span></p>
<p><span>} </span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>　　调用</span><span>setExecuteBatch()</span><span>时指定的值是一个上限，当达到该值时，就会自动地引发</span><span>SQL</span><span>命令执行，标准的</span><span>executeUpdate()</span><span>方法就会被作为批处理送到数据库中。我们可以通过调用</span><span>PreparedStatement</span><span>类的</span><span>sendBatch()</span><span>方法随时传输批处理任务。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>7</span><span>、使用</span><span>Oracle locator</span><span>方法插入、更新大对象（</span><span>LOB</span><span>）</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>Oracle</span><span>的</span><span>PreparedStatement</span><span>类不完全支持</span><span>BLOB</span><span>和</span><span>CLOB</span><span>等大对象的处理，尤其是</span><span>Thin</span><span>驱动程序不支持利用</span><span>PreparedStatement</span><span>对象的</span><span>setObject()</span><span>和</span><span>setBinaryStream()</span><span>方法设置</span><span>BLOB</span><span>的值，也不支持利用</span><span>setCharacterStream()</span><span>方法设置</span><span>CLOB</span><span>的值。只有</span><span>locator</span><span>本身中的方法才能够从数据库中获取</span><span>LOB</span><span>类型的值。可以使用</span><span>PreparedStatement</span><span>对象插入或更新</span><span>LOB</span><span>，但需要使用</span><span>locator</span><span>才能获取</span><span>LOB</span><span>的值。由于存在这二个问题，因此，我建议使用</span><span>locator</span><span>的方法来插入、更新或获取</span><span>LOB</span><span>的值。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>8</span><span>、使用</span><span>SQL92</span><span>语法调用存储过程</span></p>
<p>&nbsp;</p>
<p><span>　　在调用存储过程时，我们可以使用</span><span>SQL92</span><span>或</span><span>Oracle PL/SQL</span><span>，由于使用</span><span>Oracle PL/SQL</span><span>并没有什么实际的好处，而且会给以后维护你的应用程序的开发人员带来麻烦，因此，我建议在调用存储过程时使用</span><span>SQL92</span><span>。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>9</span><span>、使用</span><span>Object SQL</span><span>将对象模式转移到数据库中</span></p>
<p>&nbsp;</p>
<p><span>　　既然可以将</span><span>Oracle</span><span>的数据库作为一种面向对象的数据库来使用，就可以考虑将应用程序中的面向对象模式转到数据库中。目前的方法是创建</span><span>Java bean</span><span>作为伪装的数据库对象，将它们的属性映射到关系表中，然后在这些</span><span>bean</span><span>中添加方法。尽管这样作在</span><span>Java</span><span>中没有什么问题，但由于操作都是在数据库之外进行的，因此其他访问数据库的应用软件无法利用对象模式。如果利用</span><span>Oracle</span><span>的面向对象的技术，可以通过创建一个新的数据库对象类型在数据库中模仿其数据和操作，然后使用</span><span>JPublisher</span><span>等工具生成自己的</span><span>Java bean</span><span>类。如果使用这种方式，不但</span><span>Java</span><span>应用程序可以使用应用软件的对象模式，其他需要共享你的应用中的数据和操作的应用软件也可以使用应用软件中的对象模式。</span></p>
<p>&nbsp;</p>
<p><span>　　</span><span>10</span><span>、利用</span><span>SQL</span><span>完成数据库内的操作</span></p>
<p>&nbsp;</p>
<p><span>　　我要向大家介绍的最重要的经验是充分利用</span><span>SQL</span><span>的面向集合的方法来解决数据库处理需求，而不是使用</span><span>Java</span><span>等过程化的编程语言。</span></p>
<p>&nbsp;</p>
<p><span>　　如果编程人员要在一个表中查找许多行，结果中的每个行都会查找其他表中的数据，最后，编程人员创建了独立的</span><span>UPDATE</span><span>命令来成批地更新第一个表中的数据。与此类似的任务可以通过在</span><span>set</span><span>子句中使用多列子查询而在一个</span><span>UPDATE</span><span>命令中完成。当能够在单一的</span><span>SQL</span><span>命令中完成任务，何必要让数据在网上流来流去的？我建议用户认真学习如何最大限度地发挥</span><span>SQL</span><span>的功能。</span></p>
<img src ="http://www.blogjava.net/franlk/aggbug/109608.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-04-10 13:09 <a href="http://www.blogjava.net/franlk/articles/109608.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]常用数据库JDBC连接写法</title><link>http://www.blogjava.net/franlk/articles/109448.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Mon, 09 Apr 2007 08:32:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/109448.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/109448.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/109448.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/109448.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/109448.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=123&amp;threadID=20222&amp;tstart=0">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=123&amp;threadID=20222&amp;tstart=0</a><br><br>为了方便大家查找，整理内容如下：<br>1. MySQL(http://www.mysql.com)mm.mysql-2.0.2-bin.jar<br>Class.forName( "org.gjt.mm.mysql.Driver" );<br>cn = DriverManager.getConnection( "jdbc:mysql://MyDbComputerNameOrIP:3306/myDatabaseName", sUsr, sPwd );<br><br>2. PostgreSQL(http://www.de.postgresql.org)pgjdbc2.jar<br>Class.forName( "org.postgresql.Driver" );<br>cn = DriverManager.getConnection( "jdbc:postgresql://MyDbComputerNameOrIP/myDatabaseName", sUsr, sPwd );<br><br>3. Oracle(http://www.oracle.com/ip/deploy/database/oracle9i/)classes12.zip<br>Class.forName( "oracle.jdbc.driver.OracleDriver" );<br>cn = DriverManager.getConnection( "jdbc:oracle:thin:@MyDbComputerNameOrIP:1521:ORCL", sUsr, sPwd );<br><br>4. Sybase(http://jtds.sourceforge.net)jconn2.jar<br>Class.forName( "com.sybase.jdbc2.jdbc.SybDriver" );<br>cn = DriverManager.getConnection( "jdbc:sybase:Tds:MyDbComputerNameOrIP:2638", sUsr, sPwd );<br>//(Default-Username/Password: "dba"/"sql")<br><br>5. Microsoft SQLServer(http://jtds.sourceforge.net)<br>Class.forName( "net.sourceforge.jtds.jdbc.Driver" );<br>cn = DriverManager.getConnection( "jdbc:jtds:sqlserver://MyDbComputerNameOrIP:1433/master", sUsr, sPwd );<br><br>6. Microsoft SQLServer(http://www.microsoft.com)<br>Class.forName( "com.microsoft.jdbc.sqlserver.SQLServerDriver" );<br>cn = DriverManager.getConnection( "jdbc:microsoft:sqlserver://MyDbComputerNameOrIP:1433;databaseName=master", sUsr, sPwd );<br><br>7. ODBC<br>Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );<br>Connection cn = DriverManager.getConnection( "jdbc:odbc:" + sDsn, sUsr, sPwd );<br><br>8.DB2(新添加)<br>Class.forName("com.ibm.db2.jdbc.net.DB2Driver");<br>String url="jdbc:db2://192.9.200.108:6789/SAMPLE"<br>cn = DriverManager.getConnection( url, sUsr, sPwd );<br><br>9.Microsoft SQL Server series (6.5, 7.x and 2000) and Sybase 10<br><br>JDBC Name: jTDS<br>URL: http://jtds.sourceforge.net/<br>Version: 0.5.1<br>Download URL: http://sourceforge.net/project/showfiles.php?group_id=33291<br><br>语法:<br>Class.forName("net.sourceforge.jtds.jdbc.Driver ");<br>Connection con = DriverManager.getConnection("jdbc:jtds:sqlserver://host:port/database","user","password");<br>or<br>Connection con = DriverManager.getConnection("jdbc:jtds:sybase://host:port/database","user","password");<br><br>10.Postgresql<br>JDBC Name: PostgreSQL JDBC<br>URL: http://jdbc.postgresql.org/<br>Version: 7.3.3 build 110<br>Download URL: http://jdbc.postgresql.org/download.html<br>语法:<br>Class.forName("org.postgresql.Driver"); <br>Connection con=DriverManager.getConnection("jdbc:postgresql://host:port/database","user","password");<br><br>11.IBM AS400主机在用的JDBC语法<br>有装V4R4以上版本的Client Access Express<br>可以在C:\Program Files\IBM\Client Access\jt400\lib<br>找到 driver 档案 jt400.zip，并更改扩展名成为 jt400.jar<br>语法:<br>java.sql.DriverManager.registerDriver (new com.ibm.as400.access.AS400JDBCDriver ());<br>Class.forName("com.ibm.as400.access.AS400JDBCConnection");<br>con = DriverManager.getConnection("jdbc:as400://IP","user","password");<br><br>12.informix<br>Class.forName("com.informix.jdbc.IfxDriver").newInstance(); <br>String url = <br>"jdbc:informix-sqli://123.45.67.89:1533/testDB:INFORMIXSERVER=myserver; <br>user=testuser;password=testpassword";<br>Lib：jdbcdrv.zip&lt;br&gt;&lt;br&gt;Class.forName( "com.sybase.jdbc.SybDriver" )<br>url="jdbc:sybase:Tds:127.0.0.1:2638/asademo";<br>SybConnection connection= (SybConnection)DriverManager.getConnection(url,"dba","sql");<br><br>13.SAP DB<br>Class.forName ("com.sap.dbtech.jdbc.DriverSapDB");<br>java.sql.Connection connection = java.sql.DriverManager.getConnection ( "jdbc:sapdb://" + host + "/" + database_name,user_name, password)<br><br>14.InterBase<br>String url = "jdbc:interbase://localhost/e:/testbed/database/employee.gdb";<br>Class.forName("interbase.interclient.Driver");<br>//Driver d = new interbase.interclient.Driver (); /* this will also work if you do not want the line above */<br>Connection conn = DriverManager.getConnection( url, "sysdba", "masterkey" );<br><br>15.HSqlDB<br>url:&nbsp;&nbsp;&nbsp;&nbsp; http://hsqldb.sourceforge.net/<br>driver:&nbsp; org.hsqldb.jdbcDriver<br>连接方式有4种，分别为：<br>con-str（内存）: jdbc:hsqldb.<br>con-str（本地）: jdbc:hsqldb:/path/to/the/db/dir<br>con-str（http）: jdbc:hsqldb:http://dbsrv<br>con-str（hsql）: jdbc:hsqldb:hsql://dbsrv<br>
<img src ="http://www.blogjava.net/franlk/aggbug/109448.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-04-09 16:32 <a href="http://www.blogjava.net/franlk/articles/109448.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]SQL Server和Oracle的常用函数对比</title><link>http://www.blogjava.net/franlk/articles/93855.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Mon, 15 Jan 2007 01:49:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/93855.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/93855.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/93855.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/93855.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/93855.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://jim.blueidea.com/archives/2006/3715.shtml">http://jim.blueidea.com/archives/2006/3715.shtml</a><br /><p>---------数学函数</p><p>1.绝对值<br />S:select abs(-1) value<br />O:select abs(-1) value from dual</p><p>2.取整(大)<br />S:select ceiling(-1.001) value<br />O:select ceil(-1.001) value from dual</p><p>3.取整（小）<br />S:select floor(-1.001) value<br />O:select floor(-1.001) value from dual</p><p>4.取整（截取）<br />S:select cast(-1.002 as int) value<br />O:select trunc(-1.002) value from dual</p><p>5.四舍五入<br />S:select round(1.23456,4) value 1.23460<br />O:select round(1.23456,4) value from dual 1.2346</p><p>6.e为底的幂<br />S:select Exp(1) value 2.7182818284590451<br />O:select Exp(1) value from dual 2.71828182</p><p>7.取e为底的对数<br />S:select log(2.7182818284590451) value 1<br />O:select ln(2.7182818284590451) value from dual; 1</p><p>8.取10为底对数<br />S:select log10(10) value 1<br />O:select log(10,10) value from dual; 1</p><p>9.取平方<br />S:select SQUARE(4) value 16<br />O:select power(4,2) value from dual 16</p><p>10.取平方根<br />S:select SQRT(4) value 2<br />O:select SQRT(4) value from dual 2</p><p>11.求任意数为底的幂<br />S:select power(3,4) value 81<br />O:select power(3,4) value from dual 81</p><p>12.取随机数<br />S:select rand() value<br />O:select sys.dbms_random.value(0,1) value from dual;</p><p>13.取符号<br />S:select sign(-8) value -1<br />O:select sign(-8) value from dual -1</p><p>----------三角函数相关</p><p>14.圆周率<br />S:SELECT PI() value 3.1415926535897931<br />O:不知道</p><p>15.sin,cos,tan 参数都以弧度为单位<br />例如：select sin(PI()/2) value 得到1（SQLServer）</p><p>16.Asin,Acos,Atan,Atan2 返回弧度</p><p>17.弧度角度互换(SQLServer，Oracle不知道)<br />DEGREES：弧度-〉角度<br />RADIANS：角度-〉弧度</p><p>---------数值间比较</p><p>18. 求集合最大值<br />S:select max(value) value from<br />(select 1 value<br />union<br />select -2 value<br />union<br />select 4 value<br />union<br />select 3 value)a</p><p>O:select greatest(1,-2,4,3) value from dual</p><p>19. 求集合最小值<br />S:select min(value) value from<br />(select 1 value<br />union<br />select -2 value<br />union<br />select 4 value<br />union<br />select 3 value)a</p><p>O:select least(1,-2,4,3) value from dual</p><p>20.如何处理null值(F2中的null以10代替)<br />S:select F1,IsNull(F2,10) value from Tbl<br />O:select F1,nvl(F2,10) value from Tbl</p><p>--------字符串函数</p><p>21.求字符序号<br />S:select ascii('a') value<br />O:select ascii('a') value from dual</p><p>22.从序号求字符<br />S:select char(97) value<br />O:select chr(97) value from dual</p><p>23.连接<br />S:select '11'+'22'+'33' value<br />O:select CONCAT('11','22')||33 value from dual</p><p>23.子串位置 --返回3<br />S:select CHARINDEX('s','sdsq',2) value<br />O:select INSTR('sdsq','s',2) value from dual</p><p>23.模糊子串的位置 --返回2,参数去掉中间%则返回7<br />// 本文转自 C++Builder 研究 - <a href="http://www.ccrun.com/article.asp?i=996&amp;d=dwn1rn">http://www.ccrun.com/article.asp?i=996&amp;d=dwn1rn</a><br />S:select patindex('%d%q%','sdsfasdqe') value<br />O:oracle没发现，但是instr可以通过第四个参数控制出现次数<br />select INSTR('sdsfasdqe','sd',1,2) value from dual 返回6</p><p>24.求子串<br />S:select substring('abcd',2,2) value<br />O:select substr('abcd',2,2) value from dual</p><p>25.子串代替 返回aijklmnef<br />S:SELECT STUFF('abcdef', 2, 3, 'ijklmn') value<br />O:SELECT Replace('abcdef', 'bcd', 'ijklmn') value from dual</p><p>26.子串全部替换<br />S:Replace<br />O:select Translate('fasdbfasegas','fa','我' ) value from dual</p><p>27.长度<br />S:len,datalength<br />O:length</p><p>28.大小写转换 lower,upper</p><p>29.单词首字母大写<br />S:没发现<br />O:select INITCAP('abcd dsaf df') value from dual</p><p>30.左补空格（LPAD的第一个参数为空格则同space函数）<br />S:select space(10)+'abcd' value<br />O:select LPAD('abcd',14) value from dual</p><p>31.右补空格（RPAD的第一个参数为空格则同space函数）<br />S:select 'abcd'+space(10) value<br />O:select RPAD('abcd',14) value from dual</p><p>32.删除空格<br />S:ltrim,rtrim<br />O:ltrim,rtrim,trim</p><p>33. 重复字符串<br />S:select REPLICATE('abcd',2) value<br />O:没发现</p><p>34.发音相似性比较(这两个单词返回值一样，发音相同)<br />S:SELECT SOUNDEX ('Smith'), SOUNDEX ('Smythe')<br />O:SELECT SOUNDEX ('Smith'), SOUNDEX ('Smythe') from dual<br />SQLServer中用SELECT DIFFERENCE('Smithers', 'Smythers') 比较soundex的差<br />返回0-4，4为同音，1最高</p><p>--------------日期函数</p><p>35.系统时间<br />S:select getdate() value<br />O:select sysdate value from dual</p><p>36.前后几日<br />直接与整数相加减</p><p>37.求日期<br />S:select convert(char(10),getdate(),20) value<br />O:select trunc(sysdate) value from dual<br />select to_char(sysdate,'yyyy-mm-dd') value from dual</p><p>38.求时间<br />S:select convert(char(8),getdate(),108) value<br />O:select to_char(sysdate,'hh24:mm:ss') value from dual</p><p>39.取日期时间的其他部分<br />S:DATEPART 和 DATENAME 函数 （第一个参数决定）<br />O:to_char函数 第二个参数决定</p><p>参数---------------------------------下表需要补充<br />year yy, yyyy<br />quarter qq, q (季度)<br />month mm, m (m O无效)<br />dayofyear dy, y (O表星期)<br />day dd, d (d O无效)<br />week wk, ww (wk O无效)<br />weekday dw (O不清楚)<br />Hour hh,hh12,hh24 (hh12,hh24 S无效)<br />minute mi, n (n O无效)<br />second ss, s (s O无效)<br />millisecond ms (O无效)<br />----------------------------------------------</p><p>40.当月最后一天<br />S:不知道<br />O:select LAST_DAY(sysdate) value from dual</p><p>41.本星期的某一天（比如星期日）<br />S:不知道<br />O:SELECT Next_day(sysdate,7) vaule FROM DUAL;</p><p>42.字符串转时间<br />S:可以直接转或者select cast('2004-09-08'as datetime) value<br />O:SELECT To_date('2004-01-05 22:09:38','yyyy-mm-dd hh24-mi-ss') vaule FROM DUAL;</p><p>43.求两日期某一部分的差（比如秒）<br />S:select datediff(ss,getdate(),getdate()+12.3) value<br />O:直接用两个日期相减（比如d1-d2=12.3）<br />SELECT (d1-d2)*24*60*60 vaule FROM DUAL;</p><p>44.根据差值求新的日期（比如分钟）<br />S:select dateadd(mi,8,getdate()) value<br />O:SELECT sysdate+8/60/24 vaule FROM DUAL;</p><p>45.求不同时区时间<br />S:不知道<br />O:SELECT New_time(sysdate,'ydt','gmt' ) vaule FROM DUAL;</p><p>-----时区参数,北京在东8区应该是Ydt-------<br />AST ADT 大西洋标准时间<br />BST BDT 白令海标准时间<br />CST CDT 中部标准时间<br />EST EDT 东部标准时间<br />GMT 格林尼治标准时间<br />HST HDT 阿拉斯加—夏威夷标准时间<br />MST MDT 山区标准时间<br />NST 纽芬兰标准时间<br />PST PDT 太平洋标准时间<br />YST YDT YUKON标准时间</p><p>Oracle支持的字符函数和它们的Microsoft SQL Server等价函数:</p><p>函数 Oracle Microsoft SQL　Server<br />把字符转换为ASCII ASCII ASCII<br />字串连接 CONCAT (expression + expression)<br />把ASCII转换为字符 CHR CHAR<br />返回字符串中的开始字符（左起） INSTR CHARINDEX<br />把字符转换为小写 LOWER LOWER<br />把字符转换为大写 UPPER UPPER<br />填充字符串的左边 LPAD N/A<br />清除开始的空白 LTRIM LTRIM<br />清除尾部的空白 RTRIM RTRIM<br />字符串中的起始模式（pattern） INSTR PATINDEX<br />多次重复字符串 RPAD REPLICATE<br />字符串的语音表示 SOUNDEX SOUNDEX<br />重复空格的字串 RPAD SPACE<br />从数字数据转换为字符数据 TO_CHAR STR<br />子串 SUBSTR SUBSTRING<br />替换字符 REPLACE STUFF<br />将字串中的每个词首字母大写 INITCAP N/A<br />翻译字符串 TRANSLATE N/A<br />字符串长度 LENGTH DATELENGTH or LEN<br />列表中最大的字符串 GREATEST N/A<br />列表中最小的字符串 LEAST N/A<br />如果为NULL则转换字串 NVL ISNULL</p><p>日期函数</p><p>函数 Oracle Microsoft SQL　Server<br />日期相加 (date column +/- value) or<br />ADD_MONTHS DATEADD<br />两个日期的差 (date column +/- value) or<br />MONTHS_BETWEEN DATEDIFF<br />当前日期和时间 SYSDATE GETDATE()<br />一个月的最后一天 LAST_DAY N/A<br />时区转换 NEW_TIME N/A<br />日期后的第一个周日 NEXT_DAY N/A<br />代表日期的字符串 TO_CHAR DATENAME<br />代表日期的整数 TO_NUMBER<br />(TO_CHAR)) DATEPART<br />日期舍入 ROUND CONVERT<br />日期截断 TRUNC CONVERT<br />字符串转换为日期 TO_DATE CONVERT<br />如果为NULL则转换日期 NVL ISNULL</p><p>转换函数</p><p>函数 Oracle Microsoft SQL　Server<br />数字转换为字符 TO_CHAR CONVERT<br />字符转换为数字 TO_NUMBER CONVERT<br />日期转换为字符 TO_CHAR CONVERT<br />字符转换为日期 TO_DATE CONVERT<br />16进制转换为2进制 HEX_TO_RAW CONVERT<br />2进制转换为16进制 RAW_TO_HEX CONVERT</p><p>其它行级别的函数</p><p>函数 Oracle Microsoft SQL　Server<br />返回第一个非空表达式 DECODE COALESCE<br />当前序列值 CURRVAL N/A<br />下一个序列值 NEXTVAL N/A<br />如果exp1 = exp2, 返回null DECODE NULLIF<br />用户登录账号ID数字 UID SUSER_ID<br />用户登录名 USER SUSER_NAME<br />用户数据库ID数字 UID USER_ID<br />用户数据库名 USER USER_NAME<br />当前用户 CURRENT_USER CURRENT_USER<br />用户环境(audit trail) USERENV N/A<br />在CONNECT BY子句中的级别 LEVEL N/A</p><p>合计函数</p><p>函数 Oracle Microsoft SQL　Server<br />Average AVG AVG<br />Count COUNT COUNT<br />Maximum MAX MAX<br />Minimum MIN MIN<br />Standard deviation STDDEV STDEV or STDEVP<br />Summation SUM SUM<br />Variance VARIANCE VAR or VARP</p><p>Oracle还有一个有用的函数EXTRACT,提取并且返回日期时间或时间间隔表达式中特定的时间域:<br />EXTRACT(YEAR FROM 日期)</p><br /><img src ="http://www.blogjava.net/franlk/aggbug/93855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-01-15 09:49 <a href="http://www.blogjava.net/franlk/articles/93855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]DBA必须熟悉的、最有用的DBA视图 </title><link>http://www.blogjava.net/franlk/articles/92877.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Wed, 10 Jan 2007 04:58:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/92877.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/92877.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/92877.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/92877.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/92877.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://blog.csdn.net/songq/archive/2007/01/10/1478963.aspx">http://blog.csdn.net/songq/archive/2007/01/10/1478963.aspx</a><br /><br />dba_data_files                      关于数据库文件的信息<br />dba_db_links                        数据库中的所有数据库链路<br />dba_extents                         数据库中包括所有分区<br />dba_free_space                      所有表空间中自由分区<br />dba_indexes                         数据库中所有索引的描述<br />dba_ind_columns                     在所有表及聚族上压缩索引的列<br />dba_objects                         数据库中所有的对象<br />dba_rollback_segs                   回滚段的描述<br />dba_segments                        为所有数据库段分配的存储空间<br />dba_sequences                       数据库中所有顺序书的描述<br />dba_synonyms                        数据库中所有同义词<br />dba_tables                          数据库中所有表的描述<br />dba_tablespaces                     数据库中所有表空间的描述<br />dba_tab_columns                     所有表描述、视图以及聚族的列<br />dba_tab_grants                      数据库中对象所授的权限<br />dba_tab_privs                       数据库中对象所授的权限<br />dba_ts_quotas                       所有用户表空间限额<br />dba_users                           关于数据库的所有用户信息<br />dba_views                           数据库中所有视图<img src ="http://www.blogjava.net/franlk/aggbug/92877.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2007-01-10 12:58 <a href="http://www.blogjava.net/franlk/articles/92877.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]50种方法巧妙优化你的SQL Server数据库</title><link>http://www.blogjava.net/franlk/articles/87449.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Wed, 13 Dec 2006 04:38:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/87449.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/87449.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/87449.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/87449.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/87449.html</trackback:ping><description><![CDATA[摘录地址：<a href="http://blog.btidea.com/article.asp?id=440">http://blog.btidea.com/article.asp?id=440</a><br /><br />查询速度慢的原因很多，常见如下几种： <br />　　<br />　　1、没有索引或者没有用到索引(这是查询慢最常见的问题，是程序设计的缺陷) <br />　　<br />　　2、I/O吞吐量小，形成了瓶颈效应。 <br />　　<br />　　3、没有创建计算列导致查询不优化。 <br />　　<br />　　4、内存不足 <br />　　<br />　　5、网络速度慢 <br />　　<br />　　6、查询出的数据量过大（可以采用多次查询，其他的方法降低数据量） <br />　　<br />　　7、锁或者死锁(这也是查询慢最常见的问题，是程序设计的缺陷)<br />　　<br />　　8、sp_lock,sp_who,活动的用户查看,原因是读写竞争资源。<br />　　<br />　　9、返回了不必要的行和列 <br />　　<br />　　10、查询语句不好，没有优化<br /><br />　　可以通过如下方法来优化查询 : <br />　　<br />　　1、把数据、日志、索引放到不同的I/O设备上，增加读取速度，以前可以将Tempdb应放在RAID0上，SQL2000不在支持。数据量（尺寸）越大，提高I/O越重要. <br />　　<br />　　2、纵向、横向分割表，减少表的尺寸(sp_spaceuse) <br />　　<br />　　3、升级硬件 <br />　　<br />　　4、根据查询条件,建立索引,优化索引、优化访问方式，限制结果集的数据量。注意填充因子要适当（最好是使用默认值0）。索引应该尽量小，使用字节数小的列建索引好（参照索引的创建）,不要对有限的几个值的字段建单一索引如性别字段 <br />　　<br />　　5、提高网速; <br />　　<br />　　6、扩大服务器的内存,Windows 2000和SQL server 2000能支持4-8G的内存。配置虚拟内存：虚拟内存大小应基于计算机上并发运行的服务进行配置。运行 Microsoft SQL Server? 2000 时，可考虑将虚拟内存大小设置为计算机中安装的物理内存的 1.5 倍。如果另外安装了全文检索功能，并打算运行 Microsoft 搜索服务以便执行全文索引和查询，可考虑：将虚拟内存大小配置为至少是计算机中安装的物理内存的 3 倍。将 SQL Server max server memory 服务器配置选项配置为物理内存的 1.5 倍（虚拟内存大小设置的一半）。 <br />　　<br />　　7、增加服务器CPU个数;但是必须明白并行处理串行处理更需要资源例如内存。使用并行还是串行程是MsSQL自动评估选择的。单个任务分解成多个任务，就可以在处理器上运行。例如耽搁查询的排序、连接、扫描和GROUP BY字句同时执行，SQL SERVER根据系统的负载情况决定最优的并行等级，复杂的需要消耗大量的CPU的查询最适合并行处理。但是更新操作Update,Insert，Delete还不能并行处理。 <br />　　<br />　　8、如果是使用like进行查询的话，简单的使用index是不行的，但是全文索引，耗空间。 like 'a%' 使用索引 like '%a' 不使用索引用 like '%a%' 查询时，查询耗时和字段值总长度成正比,所以不能用CHAR类型，而是VARCHAR。对于字段的值很长的建全文索引。 <br />　　<br />　　9、DB Server 和APPLication Server 分离；OLTP和OLAP分离 <br />　　<br />　　10、分布式分区视图可用于实现数据库服务器联合体。联合体是一组分开管理的服务器，但它们相互协作分担系统的处理负荷。这种通过分区数据形成数据库服务器联合体的机制能够扩大一组服务器，以支持大型的多层 Web 站点的处理需要。有关更多信息，参见设计联合数据库服务器。（参照SQL帮助文件'分区视图'） <br />　　<br />　　a、在实现分区视图之前，必须先水平分区表 <br />　　<br />　　b、在创建成员表后，在每个成员服务器上定义一个分布式分区视图，并且每个视图具有相同的名称。这样，引用分布式分区视图名的查询可以在任何一个成员服务器上运行。系统操作如同每个成员服务器上都有一个原始表的复本一样，但其实每个服务器上只有一个成员表和一个分布式分区视图。数据的位置对应用程序是透明的。 <br />　　<br />　　11、重建索引 DBCC REINDEX ,DBCC INDEXDEFRAG,收缩数据和日志 DBCC SHRINKDB,DBCC SHRINKFILE. 设置自动收缩日志.对于大的数据库不要设置数据库自动增长，它会降低服务器的性能。 在T-sql的写法上有很大的讲究，下面列出常见的要点：首先，DBMS处理查询计划的过程是这样的： <br />　　<br />　　1、 查询语句的词法、语法检查 <br />　　<br />　　2、 将语句提交给DBMS的查询优化器 <br />　　<br />　　3、 优化器做代数优化和存取路径的优化 <br />　　<br />　　4、 由预编译模块生成查询规划 <br />　　<br />　　5、 然后在合适的时间提交给系统处理执行 <br />　　<br />　　6、 最后将执行结果返回给用户其次，看一下SQL SERVER的数据存放的结构：一个页面的大小为8K(8060)字节，8个页面为一个盘区，按照B树存放。 <br />　　<br />　　12、Commit和rollback的区别 Rollback:回滚所有的事物。 Commit:提交当前的事物. 没有必要在动态SQL里写事物，如果要写请写在外面如： begin tran exec(@s) commit trans 或者将动态SQL 写成函数或者存储过程。 <br />　　<br />　　13、在查询Select语句中用Where字句限制返回的行数,避免表扫描,如果返回不必要的数据，浪费了服务器的I/O资源，加重了网络的负担降低性能。如果表很大，在表扫描的期间将表锁住，禁止其他的联接访问表,后果严重。 <br />　　<br />　　14、SQL的注释申明对执行没有任何影响<br />　　15、尽可能不使用光标，它占用大量的资源。如果需要row-by-row地执行，尽量采用非光标技术,如：在客户端循环，用临时表，Table变量，用子查询，用Case语句等等。游标可以按照它所支持的提取选项进行分类： 只进 必须按照从第一行到最后一行的顺序提取行。FETCH NEXT 是唯一允许的提取操作,也是默认方式。可滚动性 可以在游标中任何地方随机提取任意行。游标的技术在SQL2000下变得功能很强大，他的目的是支持循环。有四个并发选项 READ_ONLY：不允许通过游标定位更新(Update)，且在组成结果集的行中没有锁。 OPTIMISTIC WITH valueS:乐观并发控制是事务控制理论的一个标准部分。乐观并发控制用于这样的情形，即在打开游标及更新行的间隔中，只有很小的机会让第二个用户更新某一行。当某个游标以此选项打开时，没有锁控制其中的行，这将有助于最大化其处理能力。如果用户试图修改某一行，则此行的当前值会与最后一次提取此行时获取的值进行比较。如果任何值发生改变，则服务器就会知道其他人已更新了此行，并会返回一个错误。如果值是一样的，服务器就执行修改。 选择这个并发选项OPTIMISTIC WITH ROW VERSIONING:此乐观并发控制选项基于行版本控制。使用行版本控制，其中的表必须具有某种版本标识符，服务器可用它来确定该行在读入游标后是否有所更改。在 SQL Server 中，这个性能由 timestamp 数据类型提供，它是一个二进制数字，表示数据库中更改的相对顺序。每个数据库都有一个全局当前时间戳值：@@DBTS。每次以任何方式更改带有 timestamp 列的行时，SQL Server 先在时间戳列中存储当前的 @@DBTS 值，然后增加 @@DBTS 的值。如果某 个表具有 timestamp 列，则时间戳会被记到行级。服务器就可以比较某行的当前时间戳值和上次提取时所存储的时间戳值，从而确定该行是否已更新。服务器不必比较所有列的值，只需比较 timestamp 列即可。如果应用程序对没有 timestamp 列的表要求基于行版本控制的乐观并发，则游标默认为基于数值的乐观并发控制。 SCROLL LOCKS 这个选项实现悲观并发控制。在悲观并发控制中，在把数据库的行读入游标结果集时，应用程序将试图锁定数据库行。在使用服务器游标时，将行读入游标时会在其上放置一个更新锁。如果在事务内打开游标，则该事务更新锁将一直保持到事务被提交或回滚；当提取下一行时，将除去游标锁。如果在事务外打开游标，则提取下一行时，锁就被丢弃。因此，每当用户需要完全的悲观并发控制时，游标都应在事务内打开。更新锁将阻止任何其它任务获取更新锁或排它锁，从而阻止其它任务更新该行。然而，更新锁并不阻止共享锁，所以它不会阻止其它任务读取行，除非第二个任务也在要求带更新锁的读取。滚动锁根据在游标定义的 Select 语句中指定的锁提示，这些游标并发选项可以生成滚动锁。滚动锁在提取时在每行上获取，并保持到下次提取或者游标关闭，以先发生者为准。下次提取时，服务器为新提取中的行获取滚动锁，并释放上次提取中行的滚动锁。滚动锁独立于事务锁，并可以保持到一个提交或回滚操作之后。如果提交时关闭游标的选项为关，则 COMMIT 语句并不关闭任何打开的游标，而且滚动锁被保留到提交之后，以维护对所提取数据的隔离。所获取滚动锁的类型取决于游标并发选项和游标 Select 语句中的锁提示。锁提示 只读 乐观数值 乐观行版本控制 锁定无提示 未锁定 未锁定 未锁定 更新 NOLOCK 未锁定 未锁定 未锁定 未锁定 HOLDLOCK 共享 共享 共享 更新 UPDLOCK 错误 更新 更新 更新 TABLOCKX 错误 未锁定 未锁定 更新其它 未锁定 未锁定 未锁定 更新 *指定 NOLOCK 提示将使指定了该提示的表在游标内是只读的。 <br />　　<br />　　16、用Profiler来跟踪查询，得到查询所需的时间，找出SQL的问题所在;用索引优化器优化索引 <br />　　<br />　　17、注意UNion和UNion all 的区别。UNION all好 <br />　　<br />　　18、注意使用DISTINCT，在没有必要时不要用，它同UNION一样会使查询变慢。重复的记录在查询里是没有问题的 <br />　　<br />　　19、查询时不要返回不需要的行、列 <br />　　<br />　　20、用sp_configure 'query governor cost limit'或者SET QUERY_GOVERNOR_COST_LIMIT来限制查询消耗的资源。当评估查询消耗的资源超出限制时，服务器自动取消查询,在查询之前就扼杀掉。SET LOCKTIME设置锁的时间 <br />　　<br />　　21、用select top 100 / 10 Percent 来限制用户返回的行数或者SET ROWCOUNT来限制操作的行 <br />　　<br />　　22、在SQL2000以前，一般不要用如下的字句: "IS NULL", "&lt;&gt;", "!=", "!&gt;", "!&lt;", "NOT", "NOT EXISTS", "NOT IN", "NOT LIKE", and "LIKE '%500'"，因为他们不走索引全是表扫描。也不要在Where字句中的列名加函数，如Convert，substring等,如果必须用函数的时候，创建计算列再创建索引来替代.还可以变通写法：Where SUBSTRING(firstname,1,1) = 'm'改为Where firstname like 'm%'（索引扫描），一定要将函数和列名分开。并且索引不能建得太多和太大。NOT IN会多次扫描表，使用EXISTS、NOT EXISTS ，IN , LEFT OUTER JOIN 来替代，特别是左连接,而Exists比IN更快，最慢的是NOT操作.如果列的值含有空，以前它的索引不起作用，现在2000的优化器能够处理了。相同的是IS NULL，"NOT", "NOT EXISTS", "NOT IN"能优化她，而"&lt;&gt;"等还是不能优化，用不到索引。 <br />　　<br />　　23、使用Query Analyzer，查看SQL语句的查询计划和评估分析是否是优化的SQL。一般的20%的代码占据了80%的资源，我们优化的重点是这些慢的地方。 <br />　　<br />　　24、如果使用了IN或者OR等时发现查询没有走索引，使用显示申明指定索引： Select * FROM PersonMember (INDEX = IX_Title) Where processid IN ('男'，'女') <br />　　<br />　　25、将需要查询的结果预先计算好放在表中，查询的时候再Select。这在SQL7.0以前是最重要的手段。例如医院的住院费计算。 <br />　　<br />　　26、MIN() 和 MAX()能使用到合适的索引。 <br />　　<br />　　27、数据库有一个原则是代码离数据越近越好，所以优先选择Default,依次为Rules,Triggers, Constraint（约束如外健主健CheckUNIQUE……,数据类型的最大长度等等都是约束）,Procedure.这样不仅维护工作小，编写程序质量高，并且执行的速度快。 <br />　　<br />　　28、如果要插入大的二进制值到Image列，使用存储过程，千万不要用内嵌Insert来插入(不知JAVA是否)。因为这样应用程序首先将二进制值转换成字符串（尺寸是它的两倍），服务器受到字符后又将他转换成二进制值.存储过程就没有这些动作: 方法：Create procedure p_insert as insert into table(Fimage) values (@image), 在前台调用这个存储过程传入二进制参数，这样处理速度明显改善。 <br />　　<br />　　29、Between在某些时候比IN速度更快,Between能够更快地根据索引找到范围。用查询优化器可见到差别。 select * from chineseresume where title in ('男','女') Select * from chineseresume where between '男' and '女' 是一样的。由于in会在比较多次，所以有时会慢些。 <br />　　<br />　　30、在必要是对全局或者局部临时表创建索引，有时能够提高速度，但不是一定会这样，因为索引也耗费大量的资源。他的创建同是实际表一样。 <br />　　<br />　　31、不要建没有作用的事物例如产生报表时，浪费资源。只有在必要使用事物时使用它。 <br />　　<br />　　32、用OR的字句可以分解成多个查询，并且通过UNION 连接多个查询。他们的速度只同是否使用索引有关,如果查询需要用到联合索引，用UNION all执行的效率更高.多个OR的字句没有用到索引，改写成UNION的形式再试图与索引匹配。一个关键的问题是否用到索引。<br />　　<br />　　33、尽量少用视图，它的效率低。对视图操作比直接对表操作慢,可以用stored procedure来代替她。特别的是不要用视图嵌套,嵌套视图增加了寻找原始资料的难度。我们看视图的本质：它是存放在服务器上的被优化好了的已经产生了查询规划的SQL。对单个表检索数据时，不要使用指向多个表的视图，直接从表检索或者仅仅包含这个表的视图上读，否则增加了不必要的开销,查询受到干扰.为了加快视图的查询，MsSQL增加了视图索引的功能。 <br />　　<br />　　34、没有必要时不要用DISTINCT和ORDER BY，这些动作可以改在客户端执行。它们增加了额外的开销。这同UNION 和UNION ALL一样的道理。 <br />　　<br />　　select top 20 ad.companyname,comid,position,ad.referenceid,worklocation, convert(varchar(10),ad.postDate,120) as postDate1,workyear,degreedescription FROM jobcn_query.dbo.COMPANYAD_query ad where referenceID in('JCNAD00329667','JCNAD132168','JCNAD00337748','JCNAD00338345',<br />　　'JCNAD00333138','JCNAD00303570','JCNAD00303569',<br />　　'JCNAD00303568','JCNAD00306698','JCNAD00231935','JCNAD00231933',<br />　　'JCNAD00254567','JCNAD00254585','JCNAD00254608',<br />　　'JCNAD00254607','JCNAD00258524','JCNAD00332133','JCNAD00268618',<br />　　'JCNAD00279196','JCNAD00268613') order by postdate desc <br />　　<br />　　35、在IN后面值的列表中，将出现最频繁的值放在最前面，出现得最少的放在最后面，减少判断的次数。 <br />　　<br />　　36、当用Select INTO时，它会锁住系统表(sysobjects，sysindexes等等)，阻塞其他的连接的存取。创建临时表时用显示申明语句，而不是select INTO. drop table t_lxh begin tran select * into t_lxh from chineseresume where name = 'XYZ' --commit 在另一个连接中Select * from sysobjects可以看到 Select INTO 会锁住系统表，Create table 也会锁系统表(不管是临时表还是系统表)。所以千万不要在事物内使用它！！！这样的话如果是经常要用的临时表请使用实表，或者临时表变量。 <br />　　<br />　　37、一般在GROUP BY 个HAVING字句之前就能剔除多余的行，所以尽量不要用它们来做剔除行的工作。他们的执行顺序应该如下最优：select 的Where字句选择所有合适的行，Group By用来分组个统计行，Having字句用来剔除多余的分组。这样Group By 个Having的开销小，查询快.对于大的数据行进行分组和Having十分消耗资源。如果Group BY的目的不包括计算，只是分组，那么用Distinct更快 <br />　　<br />　　38、一次更新多条记录比分多次更新每次一条快,就是说批处理好 <br />　　<br />　　39、少用临时表，尽量用结果集和Table类性的变量来代替它,Table 类型的变量比临时表好 <br />　　<br />　　40、在SQL2000下，计算字段是可以索引的，需要满足的条件如下： <br />　　<br />　　a、计算字段的表达是确定的 <br />　　<br />　　b、不能用在TEXT,Ntext，Image数据类型 <br />　　<br />　　c、必须配制如下选项 ANSI_NULLS = ON, ANSI_PADDINGS = ON, ……. <br />　　<br />　　41、尽量将数据的处理工作放在服务器上，减少网络的开销，如使用存储过程。存储过程是编译好、优化过、并且被组织到一个执行规划里、且存储在数据库中的SQL语句，是控制流语言的集合，速度当然快。反复执行的动态SQL,可以使用临时存储过程，该过程（临时表）被放在Tempdb中。以前由于SQL SERVER对复杂的数学计算不支持，所以不得不将这个工作放在其他的层上而增加网络的开销。SQL2000支持UDFs,现在支持复杂的数学计算，函数的返回值不要太大，这样的开销很大。用户自定义函数象光标一样执行的消耗大量的资源，如果返回大的结果采用存储过程 <br />　　<br />　　42、不要在一句话里再三的使用相同的函数，浪费资源,将结果放在变量里再调用更快 <br />　　<br />　　43、Select COUNT(*)的效率教低，尽量变通他的写法，而EXISTS快.同时请注意区别： select count(Field of null) from Table 和 select count(Field of NOT null) from Table 的返回值是不同的！！！ <br />　　<br />　　44、当服务器的内存够多时，配制线程数量 = 最大连接数+5，这样能发挥最大的效率；否则使用 配制线程数量&lt;最大连接数启用SQL SERVER的线程池来解决,如果还是数量 = 最大连接数+5，严重的损害服务器的性能。 <br />　　<br />　　45、按照一定的次序来访问你的表。如果你先锁住表A，再锁住表B，那么在所有的存储过程中都要按照这个顺序来锁定它们。如果你（不经意的）某个存储过程中先锁定表B，再锁定表A，这可能就会导致一个死锁。如果锁定顺序没有被预先详细的设计好，死锁很难被发现<br />　　<br />　　46、通过SQL Server Performance Monitor监视相应硬件的负载 Memory: Page Faults / sec计数器如果该值偶尔走高，表明当时有线程竞争内存。如果持续很高，则内存可能是瓶颈。 <br />　　Process: <br />　　<br />　　1、% DPC Time 指在范例间隔期间处理器用在缓延程序调用(DPC)接收和提供服务的百分比。(DPC 正在运行的为比标准间隔优先权低的间隔)。 由于 DPC 是以特权模式执行的，DPC 时间的百分比为特权时间 百分比的一部分。这些时间单独计算并且不属于间隔计算总数的一部 分。这个总数显示了作为实例时间百分比的平均忙时。 <br />　　<br />　　2、%Processor Time计数器　如果该参数值持续超过95%，表明瓶颈是CPU。可以考虑增加一个处理器或换一个更快的处理器。 <br />　　<br />　　3、% Privileged Time 指非闲置处理器时间用于特权模式的百分比。(特权模式是为操作系统组件和操纵硬件驱动程序而设计的一种处理模式。它允许直接访问硬件和所有内存。另一种模式为用户模式，它是一种为应用程序、环境分系统和整数分系统设计的一种有限处理模式。操作系统将应用程序线程转换成特权模式以访问操作系统服务)。 特权时间的 % 包括为间断和 DPC 提供服务的时间。特权时间比率高可能是由于失败设备产生的大数量的间隔而引起的。这个计数器将平均忙时作为样本时间的一部分显示。<br />　　<br />　　4、% User Time表示耗费CPU的数据库操作，如排序，执行aggregate functions等。如果该值很高，可考虑增加索引，尽量使用简单的表联接，水平分割大表格等方法来降低该值。 Physical Disk: Curretn Disk Queue Length计数器该值应不超过磁盘数的1.5~2倍。要提高性能，可增加磁盘。 SQLServer:Cache Hit Ratio计数器该值越高越好。如果持续低于80%，应考虑增加内存。 注意该参数值是从SQL Server启动后，就一直累加记数，所以运行经过一段时间后，该值将不能反映系统当前值。 <br />　　<br />　　47、分析select emp_name form employee where salary &gt; 3000 在此语句中若salary是Float类型的，则优化器对其进行优化为Convert(float,3000)，因为3000是个整数，我们应在编程时使用3000.0而不要等运行时让DBMS进行转化。同样字符和整型数据的转换。 <br />　　<br />　　48、查询的关联同写的顺序 <br />　　<br />　　select a.personMemberID, * from chineseresume a,personmember b where personMemberID = b.referenceid and a.personMemberID = 'JCNPRH39681' （A = B ,B = '号码'） <br />　　<br />　　select a.personMemberID, * from chineseresume a,personmember b where a.personMemberID = b.referenceid and a.personMemberID = 'JCNPRH39681' and b.referenceid = 'JCNPRH39681' （A = B ,B = '号码'， A = '号码'） <br />　　<br />　　select a.personMemberID, * from chineseresume a,personmember b where b.referenceid = 'JCNPRH39681' and a.personMemberID = 'JCNPRH39681' （B = '号码'， A = '号码'） <br />　　<br />　　49、<br />　　<br />　　(1)IF 没有输入负责人代码 THEN code1=0 code2=9999 ELSE code1=code2=负责人代码 END IF 执行SQL语句为: Select 负责人名 FROM P2000 Where 负责人代码&gt;=:code1 AND负责人代码 &lt;=:code2 <br />　　<br />　　(2)IF 没有输入负责人代码 THEN 　Select 负责人名 FROM P2000 ELSE code= 负责人代码 Select 负责人代码 FROM P2000 Where 负责人代码=:code END IF 第一种方法只用了一条SQL语句,第二种方法用了两条SQL语句。在没有输入负责人代码时,第二种方法显然比第一种方法执行效率高,因为它没有限制条件;在输入了负责人代码时,第二种方法仍然比第一种方法效率高,不仅是少了一个限制条件,还因相等运算是最快的查询运算。我们写程序不要怕麻烦 <br />　　<br />　　50、关于JOBCN现在查询分页的新方法（如下），用性能优化器分析性能的瓶颈，如果在I/O或者网络的速度上，如下的方法优化切实有效，如果在CPU或者内存上，用现在的方法更好。请区分如下的方法，说明索引越小越好。 <br />　　<br />　　begin <br />　　<br />　　DECLARE @local_variable table (FID int identity(1,1),ReferenceID varchar(20)) <br />　　<br />　　insert into @local_variable (ReferenceID) <br />　　<br />　　select top 100000 ReferenceID from chineseresume order by ReferenceID <br />　　<br />　　select * from @local_variable where Fid &gt; 40 and fid &lt;= 60 <br />　　<br />　　end 和 <br />　　<br />　　begin <br />　　<br />　　DECLARE @local_variable table (FID int identity(1,1),ReferenceID varchar(20)) <br />　　<br />　　insert into @local_variable (ReferenceID) <br />　　<br />　　select top 100000 ReferenceID from chineseresume order by updatedate <br />　　<br />　　select * from @local_variable where Fid &gt; 40 and fid &lt;= 60 <br />　　<br />　　end 的不同 <br />　　<br />　　begin <br />　　<br />　　create table #temp (FID int identity(1,1),ReferenceID varchar(20)) <br />　　<br />　　insert into #temp (ReferenceID) <br />　　<br />　　select top 100000 ReferenceID from chineseresume order by updatedate <br />　　<br />　　select * from #temp where Fid &gt; 40 and fid &lt;= 60 drop table #temp <br />　　<br />　　end<br /><br /><p>另附：存储过程编写经验和优化措施  From：<a href="http://www.webjx.com/">网页教学网</a></p><p>　　一、适合读者对象：数据库开发程序员，数据库的数据量很多，涉及到对SP（存储过程）的优化的项目开发人员，对数据库有浓厚兴趣的人。 　 <br /><br />　　二、介绍：在数据库的开发过程中，经常会遇到复杂的业务逻辑和对数据库的操作，这个时候就会用SP来封装数据库操作。如果项目的SP较多，书写又没有一定的规范，将会影响以后的系统维护困难和大SP逻辑的难以理解，另外如果数据库的数据量大或者项目对SP的性能要求很，就会遇到优化的问题，否则速度有可能很慢，经过亲身经验，一个经过优化过的SP要比一个性能差的SP的效率甚至高几百倍。 　 <br /><br />　　三、内容： 　 <br /><br />　　1、开发人员如果用到其他库的Table或View，务必在当前库中建立View来实现跨库操作，最好不要直接使用“databse.dbo.table_name”，因为sp_depends不能显示出该SP所使用的跨库table或view，不方便校验。　　 <br /><br />　　2、开发人员在提交SP前，必须已经使用set showplan on分析过查询计划，做过自身的查询优化检查。 　 <br /><br />　　3、高程序运行效率，优化应用程序，在SP编写过程中应该注意以下几点： 　　 <br /><br />　　a)SQL的使用规范： <br /><br />　　　i.　尽量避免大事务操作，慎用holdlock子句，提高系统并发能力。 <br /><br />　　　ii.　尽量避免反复访问同一张或几张表，尤其是数据量较大的表，可以考虑先根据条件提取数据到临时表中，然后再做连接。 <br /><br />　　　iii.　尽量避免使用游标，因为游标的效率较差，如果游标操作的数据超过1万行，那么就应该改写；如果使用了游标，就要尽量避免在游标循环中再进行表连接的操作。 <br /><br />　　　iv.　注意where字句写法，必须考虑语句顺序，应该根据索引顺序、范围大小来确定条件子句的前后顺序，尽可能的让字段顺序与索引顺序相一致，范围从大到小。 <br /><br />　　　v.　不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算，否则系统将可能无法正确使用索引。 <br /><br />　　　vi.　尽量使用exists代替select count(1)来判断是否存在记录，count函数只有在统计表中所有行数时使用，而且count(1)比count(*)更有效率。 <br /><br />　　　vii.　尽量使用“&gt;=”，不要使用“&gt;”。 <br /><br />　　　viii.　注意一些or子句和union子句之间的替换 <br /><br />　　　ix.　注意表之间连接的数据类型，避免不同类型数据之间的连接。 <br /><br />　　　x.　注意存储过程中参数和数据类型的关系。 <br /><br />　　　xi.　注意insert、update操作的数据量，防止与其他应用冲突。如果数据量超过200个数据页面（400k），那么系统将会进行锁升级，页级锁会升级成表级锁。 　　 <br /><br />　　b)索引的使用规范： <br /><br />　　　i.　索引的创建要与应用结合考虑，建议大的OLTP表不要超过6个索引。 <br /><br />　　　ii.　尽可能的使用索引字段作为查询条件，尤其是聚簇索引，必要时可以通过index index_name来强制指定索引 <br /><br />　　　iii.　避免对大表查询时进行table scan，必要时考虑新建索引。 <br /><br />　　　iv.　在使用索引字段作为条件时，如果该索引是联合索引，那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引，否则该索引将不会被使用。 <br /><br />　　　v.　要注意索引的维护，周期性重建索引，重新编译存储过程。　　 <br /><br />　　c)tempdb的使用规范： <br /><br />　　　i.　尽量避免使用distinct、order by、group by、having、join、cumpute，因为这些语句会加重tempdb的负担。 <br /><br />　　　ii.　避免频繁创建和删除临时表，减少系统表资源的消耗。 <br /><br />　　　iii.　在新建临时表时，如果一次性插入数据量很大，那么可以使用select into代替create table，避免log，提高速度；如果数据量不大，为了缓和系统表的资源，建议先create table，然后insert。 <br /><br />　　　iv.　如果临时表的数据量较大，需要建立索引，那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中，这样才能保证系统能够很好的使用到该临时表的索引。 <br /><br />　　　 v.　如果使用到了临时表，在存储过程的最后务必将所有的临时表显式删除，先truncate table，然后drop table，这样可以避免系统表的较长时间锁定。 <br /><br />　　　 vi.　慎用大的临时表与其他大表的连接查询和修改，减低系统表负担，因为这种操作会在一条语句中多次使用tempdb的系统表。　　 <br /><br />　　d)合理的算法使用： 　　 <br /><br />　　根据上面已提到的SQL优化技术和ASE Tuning手册中的SQL优化内容,结合实际应用,采用多种算法进行比较,以获得消耗资源最少、效率最高的方法。具体可用ASE调优命令：set statistics io on, set statistics time on , set showplan on 等。 </p><img src ="http://www.blogjava.net/franlk/aggbug/87449.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2006-12-13 12:38 <a href="http://www.blogjava.net/franlk/articles/87449.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]提高查询速度方法总结 </title><link>http://www.blogjava.net/franlk/articles/77731.html</link><dc:creator>见酒就晕</dc:creator><author>见酒就晕</author><pubDate>Fri, 27 Oct 2006 13:05:00 GMT</pubDate><guid>http://www.blogjava.net/franlk/articles/77731.html</guid><wfw:comment>http://www.blogjava.net/franlk/comments/77731.html</wfw:comment><comments>http://www.blogjava.net/franlk/articles/77731.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/franlk/comments/commentRss/77731.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/franlk/services/trackbacks/77731.html</trackback:ping><description><![CDATA[
		<p>摘录地址：<a href="http://community.csdn.net/Expert/topic/5106/5106330.xml?temp=.948147">http://community.csdn.net/Expert/topic/5106/5106330.xml?temp=.948147</a><br /><br />这个帖子主要总结提高查询速度的方法，涉及到减少连接数据库次数、建立索引、优化语句等方面。</p>
		<p>关于索引，推荐转载的这篇文章<br /><a href="http://blog.csdn.net/dutguoyi/archive/2006/01/10/575617.aspx">http://blog.csdn.net/dutguoyi/archive/2006/01/10/575617.aspx</a></p>
		<p>改善SQL语句的效率<br /><a href="http://community.csdn.net/Expert/topic/5087/5087396.xml?temp=.345669">http://community.csdn.net/Expert/topic/5087/5087396.xml?temp=.345669</a><br />数据量很大怎样加快索检速度<br /><a href="http://community.csdn.net/Expert/topic/5058/5058320.xml?temp=.1229517">http://community.csdn.net/Expert/topic/5058/5058320.xml?temp=.1229517</a><br />索引建立方法的区别<br /><a href="http://community.csdn.net/Expert/topic/5068/5068154.xml?temp=.3010218">http://community.csdn.net/Expert/topic/5068/5068154.xml?temp=.3010218</a><br />频繁插入删除数据需要更新索引<br /><a href="http://community.csdn.net/Expert/topic/4937/4937910.xml?temp=.8428614">http://community.csdn.net/Expert/topic/4937/4937910.xml?temp=.8428614</a><br />测试了一下sql server 2005 全文检索<br /><a href="http://community.csdn.net/Expert/topic/4878/4878430.xml?temp=.6049311">http://community.csdn.net/Expert/topic/4878/4878430.xml?temp=.6049311</a></p>
		<p>其他关于效率的高频问题</p>
		<p>判断一个表的数据不在另一个表中最优秀方法？<br /><a href="http://community.csdn.net/Expert/topic/5038/5038742.xml?temp=.4704553">http://community.csdn.net/Expert/topic/5038/5038742.xml?temp=.4704553</a><br />删除千万级表中重复记录的办法<br /><a href="http://community.csdn.net/Expert/topic/5089/5089261.xml?temp=.7907068">http://community.csdn.net/Expert/topic/5089/5089261.xml?temp=.7907068</a></p>
		<p>数据库数据查询变得不正常类型问题</p>
		<p>大数据量，稳定运行一段时候以后无法得到查询结果。<br /><a href="http://community.csdn.net/Expert/topic/4810/4810464.xml?temp=9.014529E-02">http://community.csdn.net/Expert/topic/4810/4810464.xml?temp=9.014529E-02</a><br /><br />建索引的根据？<br /><a href="http://community.csdn.net/Expert/topic/5092/5092873.xml?temp=.5849573">http://community.csdn.net/Expert/topic/5092/5092873.xml?temp=.5849573</a><br /><br />长SQL语句的查询提速。<br /><a href="http://community.csdn.net/Expert/topic/5074/5074057.xml?temp=.6983148">http://community.csdn.net/Expert/topic/5074/5074057.xml?temp=.6983148</a></p>
<img src ="http://www.blogjava.net/franlk/aggbug/77731.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/franlk/" target="_blank">见酒就晕</a> 2006-10-27 21:05 <a href="http://www.blogjava.net/franlk/articles/77731.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>