﻿<?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-I am Thinking !-文章分类-Database</title><link>http://www.blogjava.net/Juizes361/category/42484.html</link><description>路漫漫兮其修远兮,吾将上下而求索!</description><language>zh-cn</language><lastBuildDate>Thu, 10 Dec 2009 09:14:13 GMT</lastBuildDate><pubDate>Thu, 10 Dec 2009 09:14:13 GMT</pubDate><ttl>60</ttl><item><title>oracle性能调整的十大要点(转)</title><link>http://www.blogjava.net/Juizes361/articles/305289.html</link><dc:creator>残叶舞风</dc:creator><author>残叶舞风</author><pubDate>Wed, 09 Dec 2009 07:55:00 GMT</pubDate><guid>http://www.blogjava.net/Juizes361/articles/305289.html</guid><wfw:comment>http://www.blogjava.net/Juizes361/comments/305289.html</wfw:comment><comments>http://www.blogjava.net/Juizes361/articles/305289.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Juizes361/comments/commentRss/305289.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Juizes361/services/trackbacks/305289.html</trackback:ping><description><![CDATA[<span style="font-family: Comic Sans MS;"><span style="font-size: 10pt;">
<p><strong><span style="color: #2000ff;">&nbsp;&nbsp; 一、SGA</span></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、Shared pool tunning<br />
&nbsp;&nbsp;&nbsp; Shared pool的优化应该放在优先考虑，因为一个cache
miss在shared pool中发生比在data buffer中发生导致的成本更高，由于dictionary数据一般比library
cache中的数据在内存中保存的时间长，所以关键是library cache的优化。<br />
&nbsp;&nbsp;&nbsp; Gets：（parse）在namespace中查找对象的次数；<br />
&nbsp;&nbsp;&nbsp; Pins：（execution）在namespace中读取或执行对象的次数；<br />
&nbsp;&nbsp;&nbsp; Reloads：(reparse)在执行阶段library cache misses的次数，导致sql需要重新解析。</p>
<p>&nbsp;&nbsp;&nbsp; 1） 检查v$librarycache中sql area的gethitratio是否超过90％，如果未超过90％，应该检查应用代码，提高应用代码的效率。<br />
&nbsp;&nbsp;&nbsp; Select gethitratio from v$librarycache where namespace=&#8217;sql area&#8217;;</p>
<p>&nbsp;&nbsp;&nbsp; 2) v$librarycache中reloads/pins的比率应该小于1％，如果大于1％，应该增加参数shared_pool_size的值。<br />
&nbsp;&nbsp;&nbsp; Select sum(pins) &#8220;executions&#8221;,sum(reloads) &#8220;cache misses&#8221;,sum(reloads)/sum(pins) from v$librarycache;</p>
<p>&nbsp;&nbsp;&nbsp; reloads/pins&gt;1%有两种可能，一种是library cache空间不足，一种是sql中引用的对象不合法。</p>
<p>&nbsp;&nbsp;&nbsp; 3）shared pool reserved size一般是shared pool
size的10％，不能超过50％。V$shared_pool_reserved中的request
misses＝0或没有持续增长，或者free_memory大于shared pool reserved size的50%，表明shared
pool reserved size过大，可以压缩。</p>
<p>&nbsp;&nbsp;&nbsp; 4）将大的匿名pl/sql代码块转换成小的匿名pl/sql代码块调用存储过程。</p>
<p>&nbsp;&nbsp;&nbsp; 5）从9i开始，可以将execution plan与sql语句一起保存在library cache中，方便进行性能诊断。从v$sql_plan中可以看到execution plans。</p>
<p>&nbsp;&nbsp;&nbsp; 6）保留大的对象在shared pool中。大的对象是造成内存碎片的主要原因，为了腾出空间许多小对象需要移出内存，从而影响了用户的性能。因此需要将一些常用的大的对象保留在shared pool中，下列对象需要保留在shared pool中：<br />
&nbsp;&nbsp;&nbsp; a. 经常使用的存储过程；<br />
&nbsp;&nbsp;&nbsp; b. 经常操作的表上的已编译的触发器<br />
&nbsp;&nbsp;&nbsp; c. Sequence，因为Sequence移出shared pool后可能产生号码丢失。<br />
&nbsp;&nbsp;&nbsp; 查找没有保存在library cache中的大对象：<br />
&nbsp;&nbsp;&nbsp;
Select * from v$db_object_cache where sharable_mem&gt;10000 and type in
('PACKAGE','PROCEDURE','FUNCTION','PACKAGE BODY') and kept='NO';<br />
&nbsp;&nbsp;&nbsp; 将这些对象保存在library cache中：<br />
&nbsp;&nbsp;&nbsp; Execute dbms_shared_pool.keep(&#8216;package_name&#8217;);<br />
&nbsp;&nbsp;&nbsp; 对应脚本：dbmspool.sql</p>
<p>&nbsp;&nbsp;&nbsp; 7) 查找是否存在过大的匿名pl/sql代码块。两种解决方案：<br />
&nbsp;&nbsp;&nbsp; A．转换成小的匿名块调用存储过程<br />
&nbsp;&nbsp;&nbsp; B．将其保留在shared pool中<br />
&nbsp;&nbsp;&nbsp; 查找是否存在过大的匿名pl/sql块：<br />
&nbsp;&nbsp;&nbsp; Select sql_text from v$sqlarea where command_type=47 and length(sql_text)&gt;500;</p>
<p>&nbsp;&nbsp;&nbsp; 8）Dictionary cache的 优化 <br />
&nbsp;&nbsp;&nbsp; 避免出现Dictionary cache的misses，或者misses的数量保持稳定,只能通过调整shared_pool_size来间接调整dictionary cache的大小。</p>
<p>&nbsp;&nbsp;&nbsp; Percent misses应该很低：大部分应该低于2％，合计应该低于15％<br />
&nbsp;&nbsp;&nbsp; Select sum(getmisses)/sum(gets) from v$rowcache;<br />
&nbsp;&nbsp;&nbsp; 若超过15％，增加shared_pool_size的值。</p>
<p>&nbsp;&nbsp;&nbsp; 2、Buffer Cache</p>
<p>&nbsp;&nbsp;&nbsp; 1）granule大小的设置，db_cache_size以字节为单位定义了default buffer pool的大小。<br />
&nbsp;&nbsp;&nbsp; 如果SGA&lt;128M，granule=4M,否则granule＝16M，即需要调整sga的时候以granule为单位增加大小，并且sga的大小应该是granule的整数倍。</p>
<p>&nbsp;&nbsp;&nbsp; 2) 根据v$db_cache_advice调整buffer cache的大小<br />
&nbsp;&nbsp;&nbsp; SELECT
size_for_estimate,buffers_for_estimate,estd_physical_read_factor,estd_physical_reads
FROM v$db_cache_advice WHERE NAME='DEFAULT' AND advice_status='ON' AND
block_size=(SELECT Value FROM v$parameter WHERE NAME='db_block_size');</p>
<p>&nbsp;&nbsp;&nbsp; estd_physical_read_factor&lt;=1</p>
<p>&nbsp;&nbsp;&nbsp; 3) 统计buffer cache的cache hit ratio&gt;90%，如果低于90％，可以用下列方案解决：</p>
<p>&nbsp;&nbsp;&nbsp; 增加buffer cache的值；<br />
&nbsp;&nbsp;&nbsp; 使用多个buffer pool；<br />
&nbsp;&nbsp;&nbsp; Cache table；<br />
&nbsp;&nbsp;&nbsp; 为 sorting and parallel reads 建独立的buffer cache；</p>
<p>&nbsp;&nbsp;&nbsp; SELECT NAME,value FROM v$sysstat WHERE NAME IN ('session logical
reads','physical reads','physical reads direct','physical reads
direct(lob)');</p>
<p>&nbsp;&nbsp;&nbsp; Cache hit ratio=1-(physical reads-physical reads direct-physical reads direct (lob))/session logical reads;</p>
<p>&nbsp;&nbsp;&nbsp; Select 1-(phy.value-dir.value-lob.value)/log.value from
v$sysstat log, v$sysstat phy, v$sysstat dir, v$sysstat LOB where
log.name='session logical reads' and phy.name='physical reads' and
dir.name='physical reads direct' and lob.name='physical reads direct
(lob)';</p>
<p>&nbsp;&nbsp;&nbsp; 影响cache hit ratio的因素：<br />
&nbsp;&nbsp;&nbsp; 全表扫描；应用设计；大表的随机访问；cache hits的不均衡分布</p>
<p>&nbsp;&nbsp;&nbsp; 4）表空间使用自动空间管理，消除了自由空间列表的需求，可以减少数据库的竞争</p>
<p>&nbsp;&nbsp;&nbsp; 3、其他SGA对象</p>
<p>&nbsp;&nbsp;&nbsp; 1）redo log buffer<br />
&nbsp;&nbsp;&nbsp; 对应的参数是log_buffer，缺省值与 OS相关，一般是500K。检查v$session_wait中是否存在log buffer wait,v$sysstat中是否存在redo buffer allocation retries</p>
<p>&nbsp;&nbsp;&nbsp; A、检查是否存在log buffer wait：<br />
&nbsp;&nbsp;&nbsp; Select * from v$session_wait where event=&#8217;log buffer wait&#8217; ;<br />
&nbsp;&nbsp;&nbsp; 如果出现等待，一是可以增加log buffer的大小，也可以通过将log 文件移到访问速度更快的磁盘来解决。</p>
<p>&nbsp;&nbsp;&nbsp; B、Select name,value from v$sysstat where name in (&#8216;redo buffer allocation retries&#8217;,&#8217;redo entries&#8217;)<br />
&nbsp;&nbsp;&nbsp;
Redo buffer allocation retries接近0，小于redo entries
的1％，如果一直在增长，表明进程已经不得不等待redo buffer的空间。如果Redo buffer allocation
retries过大，增加log_buffer的值。</p>
<p>&nbsp;&nbsp;&nbsp; C、检查日志文件上是否存在磁盘IO竞争现象<br />
&nbsp;&nbsp;&nbsp; Select event,total_waits,time_waited,average_wait from v$system_event where event like &#8216;log file switch completion%&#8217;;<br />
&nbsp;&nbsp;&nbsp; 如果存在竞争，可以考虑将log文件转移到独立的、更快的存储设备上或增大log文件。</p>
<p>&nbsp;&nbsp;&nbsp; D、检查点的设置是否合理<br />
&nbsp;&nbsp;&nbsp; 检查alert.log文件中，是否存在&#8216;checkpoint not complete&#8217;；<br />
&nbsp;&nbsp;&nbsp; Select event,total_waits,time_waited,average_wait from v$system_event where event like &#8216;log file switch (check%&#8217;;</p>
<p>&nbsp;&nbsp;&nbsp; 如果存在等待，调整log_checkpoint_interval、log_checkpoint_timeout的设置。</p>
<p>&nbsp;&nbsp;&nbsp; E、检查log archiver的工作<br />
&nbsp;&nbsp;&nbsp; Select event,total_waits,time_waited,average_wait from v$system_event where event like &#8216;log file switch (arch%&#8217;;</p>
<p>&nbsp;&nbsp;&nbsp; 如果存在等待，检查保存归档日志的存储设备是否已满，增加日志文件组，调整log_archiver_max_processes。</p>
<p>&nbsp;&nbsp;&nbsp; F、DB_block_checksum=true，因此增加了性能负担。（为了保证数据的一致性，oracle的写数据的时候加一个checksum在block上，在读数据的时候对checksum进行验证）</p>
<p>&nbsp;&nbsp;&nbsp; 2）java pool<br />
&nbsp;&nbsp;&nbsp; 对于大的应用，java_pool_size应&gt;=50M，对于一般的java存储过程，缺省的20M已经够用了。<br />
&nbsp;&nbsp;&nbsp; 3）检查是否需要调整DBWn<br />
&nbsp;&nbsp;&nbsp; Select total_waits from v$system_event where event=&#8217;free buffer waits&#8217;;</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><strong><span style="color: #2000ff;">二、数据库配置和IO问题</span></strong></strong></p>
<p>&nbsp;&nbsp;&nbsp; 降低磁盘的IO<br />
&nbsp;&nbsp;&nbsp; 分散磁盘的IO<br />
&nbsp;&nbsp;&nbsp; 表空间使用本地管理<br />
&nbsp;&nbsp;&nbsp; 1、将文件分散到不同的设备上<br />
&nbsp;&nbsp;&nbsp; 1）将数据文件与日志文件分开<br />
&nbsp;&nbsp;&nbsp; 2）减少与服务器无关的磁盘IO<br />
&nbsp;&nbsp;&nbsp; 3）评估裸设备的使用<br />
&nbsp;&nbsp;&nbsp; 4）分割表数据</p>
<p>&nbsp;&nbsp;&nbsp; 2、表空间的使用</p>
<p>&nbsp;&nbsp;&nbsp; 系统表空间保留给数据字典对象<br />
&nbsp;&nbsp;&nbsp; 创建本地管理表空间以避免空间管理问题<br />
&nbsp;&nbsp;&nbsp; 将表和索引分散到独立的表空间中<br />
&nbsp;&nbsp;&nbsp; 使用独立的回滚表空间<br />
&nbsp;&nbsp;&nbsp; 将大的数据库对象保存在各自独立的表空间中<br />
&nbsp;&nbsp;&nbsp; 创建一个或多个独立的临时表空间</p>
<p>&nbsp;&nbsp;&nbsp; 下列数据库对象应该有单独的表空间：<br />
&nbsp;&nbsp;&nbsp; 数据字典、回滚段、索引、临时段、表、大对象</p>
<p>&nbsp;&nbsp;&nbsp; 3、检查IO统计数据<br />
&nbsp;&nbsp;&nbsp; Select phyrds,phywrts,d.name from v$datafile d,v$filestat f where f.file#=d.file# order by d.name;<br />
&nbsp;&nbsp;&nbsp; 检查最有可能引起磁盘IO瓶颈的文件。</p>
<p>&nbsp;&nbsp;&nbsp; 4、分割文件<br />
&nbsp;&nbsp;&nbsp; 可以通过RAID和手工进行<br />
&nbsp;&nbsp;&nbsp; Alter table table_name allocate extent (datafile &#8216;fiile_name&#8217; size 10M);<br />
&nbsp;&nbsp;&nbsp; 但手工操作工作量很大。</p>
<p>&nbsp;&nbsp;&nbsp; 5、优化全表扫描操作</p>
<p>&nbsp;&nbsp;&nbsp; 1）检查有多少全表发生：<br />
&nbsp;&nbsp;&nbsp; Select name,value from v$sysstat where name like &#8216;%table scan%&#8217;;<br />
&nbsp;&nbsp;&nbsp;
table scans (short tables)/ table scans (long tables)与全表扫描相关，如果table
scans (long tables)的值很高，说明大部分的table access
没有经过索引查找，应该检查应用或建立索引，要确保有效的索引在正确的位置上。</p>
<p>&nbsp;&nbsp;&nbsp; 合理的DB_FILE_MULTIBLOCK_READ_COUNT能减少table scan需要调用的IO次数，提高性能（与OS相关）。</p>
<p>&nbsp;&nbsp;&nbsp; 2）查看full table scan操作：<br />
&nbsp;&nbsp;&nbsp; Select
sid,serial#,opname,target，to_char(start_time,&#8217;HH24:MI:SS&#8217;)
&#8220;start&#8221;,(sofar/totalwork)*100 &#8220;percent_complete&#8221; from v$session_longops;<br />
&nbsp;&nbsp;&nbsp; 通过v$session_longops里的sql_hash_value与v$sqltext关联，可以查询导致full table scan的sql。<br />
&nbsp;&nbsp;&nbsp; 6、Checkpoint<br />
&nbsp;&nbsp;&nbsp; Checkpoint进行的操作：DBWn进行IO操作；CKPT更新数据文件头和控制文件。<br />
&nbsp;&nbsp;&nbsp; 经常进行Checkpoint的结果：减少恢复所需的时间；降低了系统运行时的性能。</p>
<p>&nbsp;&nbsp;&nbsp; LGWR以循环的方式将日志写到各个日志组，当一个日志组满时，oracle
server必须进行一个Checkpoint，这意味着：DBWn将对应log覆盖的所有或部分脏数据块写进数据文件；CKPT更新数据文件头和控制文
件。如果DBWn没有完成操作而LGWR需要同一个文件，LGWR只能等待。<br />
&nbsp;&nbsp;&nbsp; 在OLTP环境下，如果SGA很大并且checkpoint的次数不多，在Checkpoint的过程中容易出现磁盘竞争的状况，在这种情况下，经常进行Checkpoint可以减少每次Checkpoint涉及到的脏数据块的数目。</p>
<p>&nbsp;&nbsp;&nbsp; 调节Checkpoint次数的办法：<br />
&nbsp;&nbsp;&nbsp; 增大日志文件；增加日志组以增加覆盖的时间间隔。</p>
<p>&nbsp;&nbsp;&nbsp; 7、日志文件</p>
<p>&nbsp;&nbsp;&nbsp; 建立大小合适的日志文件以最小化竞争；<br />
&nbsp;&nbsp;&nbsp; 提供足够的日志文件组以消除等待现象；<br />
&nbsp;&nbsp;&nbsp; 将日志文件存放在独立的、能快速访问的存储设备上（日志文件可以创建在裸设备上）。日志文件以组的方式组织管理，每个组里的日志文件的内容完全相同。</p>
<p>&nbsp;&nbsp;&nbsp; 8、归档日志文件<br />
&nbsp;&nbsp;&nbsp; 如果选择归档模式，必须要有两个或两个以后的日志组，当从一个组切换到另一个组时，会引起两种操作：DBWn进行Checkpoint；一个日志文件进行归档。</p>
<p>&nbsp;&nbsp;&nbsp; 归档有时候会报错：<br />
&nbsp;&nbsp;&nbsp; ARC0：Beginning to archive log# 4 seq# 2772<br />
&nbsp;&nbsp;&nbsp; Current log# 3 seq# 2773&#8230;&#8230;<br />
&nbsp;&nbsp;&nbsp; ARC0: Failed to archive log# 4 seq# 2772<br />
&nbsp;&nbsp;&nbsp; ARCH: Completed to archiving log#4 seq# 2772<br />
&nbsp;&nbsp;&nbsp; 建议init参数修改如下：<br />
&nbsp;&nbsp;&nbsp; log_archive_max_processes=2<br />
&nbsp;&nbsp;&nbsp; #log_archive_dest = &#8216;/u05/prodarch&#8217;<br />
&nbsp;&nbsp;&nbsp; log_archive_dest_1 = "location=/u05/prodarch MANDATORY&#8217;<br />
&nbsp;&nbsp;&nbsp; log_archive_dest_state_1 = enable </p>
<p>&nbsp;&nbsp;&nbsp; log_archive_dest_2 = "location=/u05/prodarch2 OPTIONAL reopen=10" （或其它目录）<br />
&nbsp;&nbsp;&nbsp; log_archive_dest_state_2 = enable <br />
&nbsp;&nbsp;&nbsp; log_archive_min_succeed_dest=1</p>
<p>&nbsp;&nbsp;&nbsp; log_archive_dest_state_3 = DEFER<br />
&nbsp;&nbsp;&nbsp; log_archive_dest_state_4 = DEFER<br />
&nbsp;&nbsp;&nbsp; log_archive_dest_state_5 = DEFER</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><strong><span style="color: #2000ff;">三、优化排序操作</span></strong></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、概念<br />
&nbsp;&nbsp;&nbsp;
服务器首先在sort_area_size指定大小的内存区域里排序，如果所需的空间超过sort_area_size，排序会在临时表空间里进行。在专
用服务器模式下，排序空间在PGA中，在共享服务器模式下，排序空间在UGA中。如果没有建立large pool，UGA处于shared
pool中，如果建立了large pool，UGA就处于large pool中，而PGA不在sga中，它是与每个进程对应单独存在的。</p>
<p>&nbsp;&nbsp;&nbsp; &nbsp;PGA：program global area,为单个进程（服务器进程或后台进程）保存数据和控制信息的内存区域。PGA与进程一一对应，且只能被起对应的进程读写，PGA在用户登录数据库创建会话的时候建立。</p>
<p>&nbsp;&nbsp;&nbsp; 有关排序空间自动管理的两个参数：<br />
&nbsp;&nbsp;&nbsp; Pga_aggregate_target: 10M-4000G，等于分配给oracle instance的所有内存减去SGA后的大小。 <br />
&nbsp;&nbsp;&nbsp; Workarea_size_policy: auto/manual，只有Pga_aggregate_target已定义时才能设置为auto。<br />
&nbsp;&nbsp;&nbsp; 这两个参数会取代所有的*_area_size参数。</p>
<p>&nbsp;&nbsp;&nbsp; 措施：</p>
<p>&nbsp;&nbsp;&nbsp; 尽可能避免排序；尽可能在内存中排序；分配合适的临时空间以减少空间分配调用。</p>
<p>&nbsp;&nbsp;&nbsp; 2、需要进行排序的操作：<br />
&nbsp;&nbsp;&nbsp; A、创建索引；<br />
&nbsp;&nbsp;&nbsp; B、涉及到索引维护的并行插入<br />
&nbsp;&nbsp;&nbsp; C、order by或者group by（尽可能对索引字段排序）<br />
&nbsp;&nbsp;&nbsp; D、Distinct<br />
&nbsp;&nbsp;&nbsp; E、union/intersect/minus<br />
&nbsp;&nbsp;&nbsp; F、sort-merge join<br />
&nbsp;&nbsp;&nbsp; G、analyze命令（仅可能使用estamate而不是compute）</p>
<p>&nbsp;&nbsp;&nbsp; 3、诊断和措施<br />
&nbsp;&nbsp;&nbsp; Select * from v$sysstat where name like &#8216;%sort%&#8217;;<br />
&nbsp;&nbsp;&nbsp; Sort(disk):要求Io去临时表空间的排序数目<br />
&nbsp;&nbsp;&nbsp; Sort(memory)：完全在memory中完成的排序数目<br />
&nbsp;&nbsp;&nbsp; Sort(rows)：被排序的行数合计</p>
<p>&nbsp;&nbsp;&nbsp; Sort（disk）/ Sort（memory）&lt;5%,如果超过5％，增加sort_area_size的值。<br />
&nbsp;&nbsp;&nbsp;
SELECT disk.Value disk,mem.Value mem,(disk.Value/mem.Value)*100 ratio
FROM v$sysstat disk,v$sysstat mem WHERE mem.NAME='sorts (memory)' AND
disk.NAME='sorts (disk)';</p>
<p>&nbsp;&nbsp;&nbsp; 4、监控临时表空间的使用情况及其配置<br />
&nbsp;&nbsp;&nbsp; Select
tablespace_name,current_users,total_extents,used_extents,extent_hits,max_used_blocks,max_sort_blocks
FROM v$sort_segment ;</p>
<p>&nbsp;&nbsp;&nbsp; Column Description <br />
&nbsp;&nbsp;&nbsp; CURRENT_USERS Number of active users <br />
&nbsp;&nbsp;&nbsp; TOTAL_EXTENTS Total number of extents <br />
&nbsp;&nbsp;&nbsp; USED_EXTENTS Extents currently allocated to sorts <br />
&nbsp;&nbsp;&nbsp; EXTENT_HITS Number of times an unused extent was found in the pool <br />
&nbsp;&nbsp;&nbsp; MAX_USED_BLOCKS Maximum number of used blocks <br />
&nbsp;&nbsp;&nbsp; MAX_SORT_BLOCKS Maximum number of blocks used by an individual sort </p>
<p>&nbsp;&nbsp;&nbsp; 临时表空间的配置：<br />
&nbsp;&nbsp;&nbsp; A、initial/next设置为sort_area_size的整数倍，允许额外的一个block作为segment的header<br />
&nbsp;&nbsp;&nbsp; B、pctincrease=0<br />
&nbsp;&nbsp;&nbsp; C、基于不同的排序需要建立多个临时表空间<br />
&nbsp;&nbsp;&nbsp; D、将临时表空间文件分散到多个磁盘上</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><strong><span style="color: #2000ff;">四、诊断latch竞争</span></strong></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、概念<br />
&nbsp;&nbsp;&nbsp; Latch是简单的、低层次的序列化技术，用以保护SGA中的共享数据结构，比如并发用户列表和buffer
cache里的blocks信息。一个服务器进程或后台进程在开始操作或寻找一个共享数据结构之前必须获得对应的latch，在完成以后释放latch。
不必对latch本身进行优化，如果latch存在竞争，表明SGA的一部分正在经历不正常的资源使用。</p>
<p>&nbsp;&nbsp;&nbsp; 1）Latch的作用：<br />
&nbsp;&nbsp;&nbsp; A、序列化访问：保护SGA中的共享数据结构；保护共享内存的分配。<br />
&nbsp;&nbsp;&nbsp; B、序列化执行：避免同时执行某些关键代码；避免互相干扰。</p>
<p>&nbsp;&nbsp;&nbsp; 2）Latch请求的两种类型：<br />
&nbsp;&nbsp;&nbsp; A、willing-to-wait：请求的进程经过短时间的等待后再次发出请求，直到获得latch<br />
&nbsp;&nbsp;&nbsp; B、immediate：如果没有获得latch，请求的进程不等待，而是继续处理其他指令。<br />
&nbsp;&nbsp;&nbsp; 2、检查Latch竞争<br />
&nbsp;&nbsp;&nbsp; 检查latch free是不是主要的wait event：<br />
&nbsp;&nbsp;&nbsp; Select * from v$system_event order by time_waited;</p>
<p>&nbsp;&nbsp;&nbsp; 检查latch的使用情况：<br />
&nbsp;&nbsp;&nbsp; Select * from v$latch:<br />
&nbsp;&nbsp;&nbsp; 与willing-to-wait请求有关的列：gets、misses、sleeps、wait_time、cwait_time、spin_gets<br />
&nbsp;&nbsp;&nbsp; 与immediate请求有关的列：immediate_gets、immediate_misses</p>
<p>&nbsp;&nbsp;&nbsp; Gets: number of successful willing-to-wait requests for a latch;<br />
&nbsp;&nbsp;&nbsp; Misses: number of times an initial wiling-to-wait request was unsuccessful;<br />
&nbsp;&nbsp;&nbsp; Sleeps: number of times a process waited after an initial willing-to-wait request;<br />
&nbsp;&nbsp;&nbsp; Wait_time: number of milliseconds waited after willing-to-wait request;<br />
&nbsp;&nbsp;&nbsp;
Cwait_time: a measure of the cumulative wait time including the time
spent spinning and sleeping,the overhead of context switches due to OS
time slicing and page faults and interrupts;<br />
&nbsp;&nbsp;&nbsp; Spin_gets: gets that misses first try but succeed after spinning.</p>
<p>&nbsp;&nbsp;&nbsp; Immediate_gets: number of successful immediate requests for each latch;<br />
&nbsp;&nbsp;&nbsp; Immediate_misss: number of unsuccessful immediate requests for each latch;</p>
<p>&nbsp;&nbsp;&nbsp; 一般无需调整latch，但是下列的措施是有用的：<br />
&nbsp;&nbsp;&nbsp; A、对处于竞争中的latch做进一步的调查<br />
&nbsp;&nbsp;&nbsp; B、如果竞争主要存在于shared pool和library cache中，可以考虑调整应用<br />
&nbsp;&nbsp;&nbsp; C、如果进一步的调查显示需要调整shared pool和buffer cache，就进行调整</p>
<p>&nbsp;&nbsp;&nbsp; Select * from v$latch where name like &#8216;%shared pool%&#8217; or name like &#8216;%library cache%&#8217;；</p>
<p>&nbsp;&nbsp;&nbsp; 如果竞争是在shared pool或library cache上，表示下列集中情况：<br />
&nbsp;&nbsp;&nbsp; A、不能共享的sql,应检查他们是否相似，考虑以变量代替sql中的常量：<br />
&nbsp;&nbsp;&nbsp; Select sql_text from v$sqlarea where executions=1 order by upper(sql_text);<br />
&nbsp;&nbsp;&nbsp; B、共享sql被重新编译，考虑library cache的大小是否需要调整：<br />
&nbsp;&nbsp;&nbsp; SELECT sql_text,parse_calls,executions FROM v$sqlarea where parse_calls&gt;5;<br />
&nbsp;&nbsp;&nbsp; C、library cache不够大。</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><span style="color: #2000ff;">五、Rollback(undo) Segment 优化</span></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、概念<br />
&nbsp;&nbsp;&nbsp; Transaction以轮循的方式使用rollback
segment里的extent，当前所在的extent满时就移动到下一个extent。可能有多个transaction同时向同一个extent写
数据，但一个rollback segment block中只能保存一个transaction的数据。</p>
<p>&nbsp;&nbsp;&nbsp; Oracle 在每个Rollback segment header中保存了一个transaction
table，包括了每个rollback segment中包含的事务信息，rollback segment
header的活动控制了向rollbak segment写入被修改的数据。rollback segment
header是经常被修改的数据库块，因此它应该被长时间留在buffer cache中，为了避免在transaction
table产生竞争导致性能下降，应有多个rollback segment或应尽量使用oracle server 自动管理的rollback
segment。</p>
<p>&nbsp;&nbsp;&nbsp; 2、诊断rollback segment header的竞争<br />
&nbsp;&nbsp;&nbsp; 如果rollback segment 由手工管理，下列措施诊断rollback segment header的竞争<br />
&nbsp;&nbsp;&nbsp; SELECT class,count FROM v$waitstat WHERE class LIKE '%undo%' ;<br />
&nbsp;&nbsp;&nbsp; SELECT Sum(Value) sum FROM v$sysstat WHERE NAME IN ('db block gets','consistent gets');<br />
&nbsp;&nbsp;&nbsp; 任何类型的等待次数（count）与总请求数(sum)的比率，不能超过1％。<br />
&nbsp;&nbsp;&nbsp; 或<br />
&nbsp;&nbsp;&nbsp; select sum(waits)*100/sum(gets) "Ratio", sum(waits) "Waits", sum(gets) "Gets" from v$rollstat;<br />
&nbsp;&nbsp;&nbsp; waits的汇总数与gets的汇总数的比率应低于1％，如果超过1％，应创建更多的rollback segment。</p>
<p>&nbsp;&nbsp;&nbsp; 下列字段数值如果大于0，则表明在rollback segment header上存在竞争：<br />
&nbsp;&nbsp;&nbsp; A、v$rollstat 中的waits<br />
&nbsp;&nbsp;&nbsp; B、v$waitstat中的undo header行<br />
&nbsp;&nbsp;&nbsp; C、v$system_event中的undo segment tx slot事件</p>
<p>&nbsp;&nbsp;&nbsp; 3、消耗更少的rollback segment<br />
&nbsp;&nbsp;&nbsp; 1）如果是删除表里所有的数据，尽可能使用trauncate而不是delete。<br />
&nbsp;&nbsp;&nbsp; 2）在应用中允许用户有规律的提交，尽可能不用长事务。<br />
&nbsp;&nbsp;&nbsp; 3）? Import<br />
&nbsp;&nbsp;&nbsp; &#8211; Set COMMIT = Y<br />
&nbsp;&nbsp;&nbsp; &#8211; Size the set of rows with BUFFER<br />
&nbsp;&nbsp;&nbsp; ? Export: Set CONSISTENT=N<br />
&nbsp;&nbsp;&nbsp; ? SQL*Loader: Set the COMMIT intervals with ROWS</p>
<p>&nbsp;&nbsp;&nbsp; 4、小回滚段可能出现的问题<br />
&nbsp;&nbsp;&nbsp; A、事务由于缺少回滚空间失败<br />
&nbsp;&nbsp;&nbsp; B、由于下列原因导致的&#8220;Snapshot too old&#8221;问题：<br />
&nbsp;&nbsp;&nbsp; Block里的事务列表被刷新，block里的SCN比列表Interested Transaction List（ITL）里起始事务的SCN更新；<br />
&nbsp;&nbsp;&nbsp; Rollback segment header里的Transaction slot被重用；<br />
&nbsp;&nbsp;&nbsp; 回滚数据已经被重写；</p>
<p>&nbsp;&nbsp;&nbsp; 5、9i的自动回滚管理<br />
&nbsp;&nbsp;&nbsp; Undo_managment指定了回滚空间的管理方式：Auto：自动管理；Manual：手工管理回滚段。<br />
&nbsp;&nbsp;&nbsp; Undo_retention指定了回滚数据的保留期限；<br />
&nbsp;&nbsp;&nbsp; Undo_tablespace指定了被使用的回滚表空间；</p>
<p>&nbsp;&nbsp;&nbsp;
Oracle自动管理的表空间可以在常见数据库的时候创建，也可以单独建立。回滚表空间可以相互转换（switch），但在某一时刻只能有一个回滚表空间
处于活动状态。回滚表空间处于非活动状态时可以删除，如果有对处于被删除回滚表空间里的已提交事务的查询时，oracle会返回一个错误。</p>
<p>&nbsp;&nbsp;&nbsp; 估计undo tablespace大小的公式：<br />
&nbsp;&nbsp;&nbsp; Undo space = (undo_retention * (undo blocks per second * db_block_size)) + db_block_size;</p>
<p>&nbsp;&nbsp;&nbsp; 可以使用下列的sql设定undo_retention和undo tablespace：<br />
&nbsp;&nbsp;&nbsp; select
(rd*(ups*overhead)+overhead) "bytes" from (select value rd from
v$parameter where name ='undo_retention'),(select
(sum(undoblks)/sum(((end_time-begin_time)*10800))) ups from
v$undostat),(select value overhead from v$parameter where
name='db_block_size');</p>
<p>&nbsp;&nbsp;&nbsp; 其中：<br />
&nbsp;&nbsp;&nbsp; Rd：undo_retention设置的时间；<br />
&nbsp;&nbsp;&nbsp; Ups：undo blocks per second；<br />
&nbsp;&nbsp;&nbsp; Overhead：rollback segment header；</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><strong><span style="color: #2000ff;">六、Lock Contention</span></strong></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、概念<br />
&nbsp;&nbsp;&nbsp; DML事务使用row-level locks,查询不会锁定数据。锁有两种模式：exlusive、share。<br />
&nbsp;&nbsp;&nbsp; 锁的类型：<br />
&nbsp;&nbsp;&nbsp; ? DML or data locks:<br />
&nbsp;&nbsp;&nbsp; &#8211; Table-level locks（TM）<br />
&nbsp;&nbsp;&nbsp; &#8211; Row-level locks（TX）<br />
&nbsp;&nbsp;&nbsp; ? DDL or dictionary locks<br />
&nbsp;&nbsp;&nbsp; 一个transaction至少获得两个锁：一个共享的表锁，一个专有的行锁。Oracle server将所有的锁维护在一个队列里，队列跟踪了等待锁的用户、申请锁的类型以及用户的顺序信息。<br />
&nbsp;&nbsp;&nbsp;
Lock在下列情况会释放：commit；rollback；terminated（此时由pmon清理locks）。Quiesced
database：一个数据库如果除了sys和system之外没有其他活动session，这个数据库即处于quiesced状态。活动session
是指这个session当前处于一个transaction中，或一个查询中，一个fetch中，或正占有某种共享资源。</p>
<p>&nbsp;&nbsp;&nbsp; 2、可能引起lock contention的原因<br />
&nbsp;&nbsp;&nbsp; 不必要的高层次的锁；<br />
&nbsp;&nbsp;&nbsp; 长时间运行的transaction；<br />
&nbsp;&nbsp;&nbsp; 未提交的修改；<br />
&nbsp;&nbsp;&nbsp; 其他产品施加的高层次的锁。</p>
<p>&nbsp;&nbsp;&nbsp; 解决lock contention的方法：锁的拥有者提交或回滚事务；杀死用户会话。</p>
<p>&nbsp;&nbsp;&nbsp; 3、死锁<br />
&nbsp;&nbsp;&nbsp; Oracle自动检测和解决死锁，方法是通过回滚引起死锁的语句（statement），但是这条语句对应的transaction并没有回滚，因此当收到死锁的错误信息后，应该去回滚改transaction的剩余部分。</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><strong><span style="color: #2000ff;">七、应用优化</span></strong></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、概念<br />
&nbsp;&nbsp;&nbsp; 为了提高性能，可以使用下列数据访问方法：<br />
&nbsp;&nbsp;&nbsp; A、Clusters<br />
&nbsp;&nbsp;&nbsp; B、Indexes<br />
&nbsp;&nbsp;&nbsp; -B-tree（normal or reverse key）<br />
&nbsp;&nbsp;&nbsp; -bitmap<br />
&nbsp;&nbsp;&nbsp; -function-based<br />
&nbsp;&nbsp;&nbsp; C、Index-organized tables<br />
&nbsp;&nbsp;&nbsp; D、Materialized views</p>
<p>&nbsp;&nbsp;&nbsp; 索引的层次越多，效率越低，如果索引中含有许多已删除的行，这个索引也会变得低效，如果索引数据的15％已经被删除，应该考虑重建索引。</p>
<p>&nbsp;&nbsp;&nbsp; 2、应用问题<br />
&nbsp;&nbsp;&nbsp; A、使用可声明的约束而不是通过代码限制<br />
&nbsp;&nbsp;&nbsp; B、代码共享<br />
&nbsp;&nbsp;&nbsp; C、使用绑定变量而不是文字来优化共享sql<br />
&nbsp;&nbsp;&nbsp; D、调整cursor_sharing的值（EXACT/SIMILAR/FORCE）</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><strong><span style="color: #2000ff;">八、提升block的效率</span></strong></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、避免动态分配的缺陷<br />
&nbsp;&nbsp;&nbsp; 创建本地管理的表空间；<br />
&nbsp;&nbsp;&nbsp; 合理设置segment的大小；<br />
&nbsp;&nbsp;&nbsp; 监控将要扩展的segment：<br />
&nbsp;&nbsp;&nbsp; SELECT owner, table_name, blocks, empty_blocks FROM dba_tables WHERE empty_blocks / (blocks+empty_blocks) &lt; .1;</p>
<p>&nbsp;&nbsp;&nbsp; 2、high water mark<br />
&nbsp;&nbsp;&nbsp; 记录在segment header block中，在segment创建的时候设定在segment的起始位置，当记录被插入的时候以5个block的增量增加，truncate可以重设high water mark的位置，但delete不能。<br />
&nbsp;&nbsp;&nbsp; 在full table scan中，oracle会读取high water mark以下的所有的数据块，所以high water mark以上的块也许会浪费存储空间，但不会降低性能。</p>
<p>&nbsp;&nbsp;&nbsp; 可以通过下列方法收回表中high water mark以上的块：<br />
&nbsp;&nbsp;&nbsp; Alter table_name deallocate unused；<br />
&nbsp;&nbsp;&nbsp; 对于high water mark以下的块：<br />
&nbsp;&nbsp;&nbsp; 使用import/export工具：export数据；drop或truncate表；import数据。或者利用alter table tanle_name move命令去移动表的存储位置（此时需要重建索引）。</p>
<p>&nbsp;&nbsp;&nbsp; 3、表统计<br />
&nbsp;&nbsp;&nbsp; 用analyize命令生成表统计，然后到dba_table查询相关信息。<br />
&nbsp;&nbsp;&nbsp; ANALYZE TABLE ndls.t_wh_shipping_bill COMPUTE STATISTICS;<br />
&nbsp;&nbsp;&nbsp;
SELECT num_rows, blocks, empty_blocks as empty,avg_space, chain_cnt,
avg_row_len FROM dba_tables WHERE owner ='NDLS' AND
table_name='T_WH_SHIPPING_BILL';</p>
<p>&nbsp;&nbsp;&nbsp; Columns Description <br />
&nbsp;&nbsp;&nbsp; NUM_ROWS Number of rows in the table <br />
&nbsp;&nbsp;&nbsp; BLOCKS Number of blocks below the table high-water mark <br />
&nbsp;&nbsp;&nbsp; EMPTY_BLOCKS Number of blocks above the table high-water mark <br />
&nbsp;&nbsp;&nbsp; AVG_SPACE Average free space in bytes in the blocks below high-water mark<br />
&nbsp;&nbsp;&nbsp; AVG_ROW_LEN Average row length, including row overhead <br />
&nbsp;&nbsp;&nbsp; CHAIN_CNT Number of chained or migrated rows in the table </p>
<p>&nbsp;&nbsp;&nbsp; 4、block size<br />
&nbsp;&nbsp;&nbsp; 通过下列方法可以最小化block的访问次数：<br />
&nbsp;&nbsp;&nbsp; 使用更大的block
size；紧密压缩行；阻止行镜像。后两者存在冲突，越多的行被压缩在一个block里，越容易产生镜像。Block size
在数据库创建的时候设定，不能被轻易改变，是读取数据文件时最小的IO单元，大小范围是2K－64K，应该设置成OS块的整数倍，小于或等于OS
IO时能读取的存储区域。</p>
<p>&nbsp;&nbsp;&nbsp; 较小的block
size的优点：极少block竞争；有利于较小的行和随机访问。缺点是存在相当高的成本，每个block的行数更少，可能需要读取更多的index块。
Block size的选择影响系统的性能，在一个OLTP环境中，较小的block size更合适，而在DSS环境中，适宜选择较大的block
size。</p>
<p>&nbsp;&nbsp;&nbsp; 5、PCTFREE、PCTUSED</p>
<p>&nbsp;&nbsp;&nbsp; 1）PCTFREE、PCTUSED使你能控制一个segment里所有数据块里free space的使用。<br />
&nbsp;&nbsp;&nbsp; PCTFREE：一个数据块保留的用于块里已有记录的可能更新的自由空间占block size的最小比例。<br />
&nbsp;&nbsp;&nbsp; PCTUSED：在新记录被插入block里之前这个block可以用于存储行数据和其他信息的空间所占的最小比率。</p>
<p>&nbsp;&nbsp;&nbsp; 2）这两个参数的使用<br />
&nbsp;&nbsp;&nbsp; 如果创建表的时候指定pctfree＝20％，oracle会在这个表的data
segment的每个block都保留20％的空间用于已有记录的更新。Block的已使用空间上升到整个block
size的80％时，这个block将移出free list；在提交了delete、update之后，oracle
server处理这条语句并检查对应block的已使用空间是否低于PCTUSED，如果是，则这个block放进free list。</p>
<p>&nbsp;&nbsp;&nbsp; 3）PCTFREE、PCTUSED的设定<br />
&nbsp;&nbsp;&nbsp; ? PCTFREE<br />
&nbsp;&nbsp;&nbsp; &#8211; Default 10<br />
&nbsp;&nbsp;&nbsp; &#8211; Zero if no UPDATE activity<br />
&nbsp;&nbsp;&nbsp; &#8211; PCTFREE = 100 &#215; upd / (average row length)<br />
&nbsp;&nbsp;&nbsp; ? PCTUSED<br />
&nbsp;&nbsp;&nbsp; &#8211; Default 40<br />
&nbsp;&nbsp;&nbsp; &#8211; Set if rows deleted<br />
&nbsp;&nbsp;&nbsp; &#8211; PCTUSED = 100 &#8211; PCTFREE &#8211; 100 &#215; rows &#215; (average row length) / blocksize<br />
&nbsp;&nbsp;&nbsp;
其中，upd ： the average amount added by updates, in bytes。This is
determined by subtracting the average row length of intercurrent
average row length;<br />
&nbsp;&nbsp;&nbsp; average row length：在运行了analyize命令之后，这个值可以从dba_tables中的avg_row_len列中获得。<br />
&nbsp;&nbsp;&nbsp; rows ： the number of rows to be deleted before free list maintenance occurs。</p>
<p>&nbsp;&nbsp;&nbsp;
4）Delete、update可以增加block的自由空间，但是释放出来的空间有可能是不连续的，oracle在下列情况下会对碎片进行整理：一个
block有足够的自由空间容纳row piece，但是由于每个碎片都较小以至这个row piece不能存放在一个连续的section中。</p>
<p>&nbsp;&nbsp;&nbsp; 6、Migration和Chaining</p>
<p>&nbsp;&nbsp;&nbsp; 1）如果一行的数据太大以至一个单独的block容纳不下，会产生两种现象：<br />
&nbsp;&nbsp;&nbsp; A、Chaining：行数据太大以至一个空block容纳不下，oracle会将这一行的数据存放在一个或多个block 组成的block chain中，insert、update都可能导致这个问题，在某些情况下row chaining是不能避免的。<br />
&nbsp;&nbsp;&nbsp;
B、Migration：一次update操作可能导致行数据增大，以至它所在的block容纳不下，oracle
server会去寻找一个有足够自由空间容纳整行数据的block，如果这样的block存在，oracle
server把整行移到新的block，在原位置保存一个指向新存放位置的镜像行，镜像行的rowid和原来的rowid一致。<br />
&nbsp;&nbsp;&nbsp; Chaining、Migration的弊端：insert、update的性能降低，索引查询增加了IO次数。</p>
<p>&nbsp;&nbsp;&nbsp; 2）检测migration和chaining：<br />
&nbsp;&nbsp;&nbsp; Analyize table table_name compute statistics；<br />
&nbsp;&nbsp;&nbsp; Select num_rows,chain_cnt from dba_tables where table_name=&#8217;...&#8217;;<br />
&nbsp;&nbsp;&nbsp; 查询镜像行：<br />
&nbsp;&nbsp;&nbsp; Analyize table table_name list chained rows；<br />
&nbsp;&nbsp;&nbsp; Select owner_name,table_name,head_rowid from chained_rows where table_name=&#8217;...&#8217;;<br />
&nbsp;&nbsp;&nbsp; 产生Migration的原因可能是由于PCTFREE设置的太低以至没有保留足够的空间用于更新。<br />
&nbsp;&nbsp;&nbsp; 可以通过增加PCTFREE的值避免行镜像产生。</p>
<p>&nbsp;&nbsp;&nbsp; 3）消除镜像行的步骤：<br />
&nbsp;&nbsp;&nbsp; 运行analyize table ... list chained rows;<br />
&nbsp;&nbsp;&nbsp; 复制镜像行到另一个表tmp；<br />
&nbsp;&nbsp;&nbsp; 从源表中删除这些行；<br />
&nbsp;&nbsp;&nbsp; 从tmp中将这些行插回到源表中。<br />
&nbsp;&nbsp;&nbsp; 脚本：<br />
&nbsp;&nbsp;&nbsp; /* Get the name of the table with migrated rows */<br />
&nbsp;&nbsp;&nbsp; accept table_name prompt &#8217;Enter the name of the table with migrated rows: &#8217;<br />
&nbsp;&nbsp;&nbsp; /* Clean up from last execution */<br />
&nbsp;&nbsp;&nbsp; set echo off<br />
&nbsp;&nbsp;&nbsp; drop table migrated_rows;<br />
&nbsp;&nbsp;&nbsp; drop table chained_rows;<br />
&nbsp;&nbsp;&nbsp; /* Create the CHAINED_ROWS table */<br />
&nbsp;&nbsp;&nbsp; @?/rdbms/admin/utlchain<br />
&nbsp;&nbsp;&nbsp; set echo on<br />
&nbsp;&nbsp;&nbsp; spool fix_mig<br />
&nbsp;&nbsp;&nbsp; /* List the chained &amp; migrated rows */<br />
&nbsp;&nbsp;&nbsp; analyze table &amp;table_name list chained rows;<br />
&nbsp;&nbsp;&nbsp; /* Copy the chained/migrated rows to another table */<br />
&nbsp;&nbsp;&nbsp; create table migrated_rows as<br />
&nbsp;&nbsp;&nbsp; select orig.* from &amp;table_name orig, chained_rows cr<br />
&nbsp;&nbsp;&nbsp; where orig.rowid = cr.head_rowid<br />
&nbsp;&nbsp;&nbsp; and cr.table_name = upper(&#8217;&amp;table_name&#8217;);<br />
&nbsp;&nbsp;&nbsp; /* Delete the chained/migrated rows from the original table */<br />
&nbsp;&nbsp;&nbsp; delete from &amp;table_name<br />
&nbsp;&nbsp;&nbsp; where rowid in ( select head_rowid from chained_rows );<br />
&nbsp;&nbsp;&nbsp; /* Copy the chained/migrated rows back into the original table */<br />
&nbsp;&nbsp;&nbsp; insert into &amp;table_name select * from migrated_rows;<br />
&nbsp;&nbsp;&nbsp; spool off<br />
&nbsp;&nbsp;&nbsp; 使用这个脚本时，必须将涉及到的外键约束去掉。</p>
<p>&nbsp;&nbsp;&nbsp; 7、索引重组</p>
<p>&nbsp;&nbsp;&nbsp; 在一个不稳定的表上建索引会影响性能，一个索引block只有完全空时才能进入free list，即使一个索引block里只含有一个条目，它也必须被维护，因此索引需要进行阶段性的重建。</p>
<p>&nbsp;&nbsp;&nbsp; 1）检查索引是否需要重组<br />
&nbsp;&nbsp;&nbsp; A、收集一个index的使用统计<br />
&nbsp;&nbsp;&nbsp; ANALYZE INDEX acct_no_idx VALIDATE STRUCTURE;<br />
&nbsp;&nbsp;&nbsp; B、查看收集的统计数据<br />
&nbsp;&nbsp;&nbsp; SELECT NAME,(DEL_LF_ROWS_LEN/LF_ROWS_LEN) * 100 AS index_usage FROM index_stats;</p>
<p>&nbsp;&nbsp;&nbsp; Column Description <br />
&nbsp;&nbsp;&nbsp; LF_ROWS Number of values currently in the index <br />
&nbsp;&nbsp;&nbsp; LF_ROWS_LEN Sum in bytes of the length of all values <br />
&nbsp;&nbsp;&nbsp; DEL_LF_ROWS Number of values deleted from the index <br />
&nbsp;&nbsp;&nbsp; DEL_LF_ROWS_LEN Length of all deleted values </p>
<p>&nbsp;&nbsp;&nbsp; C、如果浪费超过20％则索引需要重建<br />
&nbsp;&nbsp;&nbsp; ALTER INDEX acct_no_idx REBUILD;<br />
&nbsp;&nbsp;&nbsp; D、或者对索引进行整理<br />
&nbsp;&nbsp;&nbsp; Alter index acct_no_idx coalesce;</p>
<p>&nbsp;&nbsp;&nbsp; 2）标记未使用的索引<br />
&nbsp;&nbsp;&nbsp; A、 开始监测索引的使用<br />
&nbsp;&nbsp;&nbsp; Alter index hr.emp_name_ix monitoring usage;<br />
&nbsp;&nbsp;&nbsp; B、 停止监测索引的使用<br />
&nbsp;&nbsp;&nbsp; Alter index hr.emp_name_ix nomonitoring usage;<br />
&nbsp;&nbsp;&nbsp; C、 查询索引的使用情况<br />
&nbsp;&nbsp;&nbsp; Select index_name,used from v$object_usage;<br />
&nbsp;&nbsp;&nbsp; 删除未使用过的索引，可以降低DML操作的成本，从而提升系统性能。</p>
<p>&nbsp;&nbsp;&nbsp; 为了尽可能经济的利用block，应对存在较多空block、镜像行的表进行重建，对建立不稳定表上的索引应有规律的进行重建，并尽可能创建本地管理的表空间。</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><strong><span style="color: #2000ff;">九、SQL优化</span></strong></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、优化器模式</p>
<p>&nbsp;&nbsp;&nbsp; Oracle9i有两种优化器模式可以选择：<br />
&nbsp;&nbsp;&nbsp; ? Rule-based:<br />
&nbsp;&nbsp;&nbsp; &#8211; Uses a ranking system<br />
&nbsp;&nbsp;&nbsp; &#8211; Syntax- and data dictionary&#8211;driven<br />
&nbsp;&nbsp;&nbsp; ? Cost-based:<br />
&nbsp;&nbsp;&nbsp; &#8211; Chooses least-cost path<br />
&nbsp;&nbsp;&nbsp; &#8211; Statistics-driven<br />
&nbsp;&nbsp;&nbsp; Rule-based模式满足向后兼容，而Cost-based模式中的成本大部分来自于逻辑读的次数，推荐使用Cost-based模式。</p>
<p>&nbsp;&nbsp;&nbsp; 2、固定optimizer plan</p>
<p>&nbsp;&nbsp;&nbsp; 1）概念<br />
&nbsp;&nbsp;&nbsp; 对于每一个查询，optimizer都会准备一个定义了操作执行顺序和方法的操作树（执行计划），oracle
server根据这个执行计划执行语句。通过固定执行计划，可以强制应用通过一种理想的方式访问数据，并且一个稳定的执行计划可以经历数据库的变化而保持
不变。固定执行计划通过创建stored
outline实现，outline使用cost-based的optimizer，因为其由一系列的hints组成。<br />
&nbsp;&nbsp;&nbsp; 执行计划的固定依赖于当判定一个查询是否存在stored outline时查询语句是否完全一致，与判定shared pool里一个执行计划是否可以重用时的匹配方式是一致的。<br />
&nbsp;&nbsp;&nbsp; Outline被保存在outln schema中。</p>
<p>&nbsp;&nbsp;&nbsp; 2） 创建stored outline<br />
&nbsp;&nbsp;&nbsp; alter session set CREATE_STORED_OUTLINES = train;<br />
&nbsp;&nbsp;&nbsp; create or replace OUTLINE co_cl_join<br />
&nbsp;&nbsp;&nbsp; FOR CATEGORY train ON<br />
&nbsp;&nbsp;&nbsp; select co.crs_id, ...<br />
&nbsp;&nbsp;&nbsp; from courses co，classes cl<br />
&nbsp;&nbsp;&nbsp; where co.crs_id = cl.crs_id;</p>
<p>&nbsp;&nbsp;&nbsp; stored outline通过category组织，相同的sql语句可以在多个category同时拥有stored outline，如果categoey没有指定，缺省是default category。<br />
&nbsp;&nbsp;&nbsp; 当CREATE_STORED_OUTLINES等于true或category名时，oracle会为所有被执行的sql语句创建stored outline，也可以通过create outline手工创建。</p>
<p>&nbsp;&nbsp;&nbsp; 3） 使用stored outline<br />
&nbsp;&nbsp;&nbsp; 将USE_STORED_OUTLINES设置为true或category名。<br />
&nbsp;&nbsp;&nbsp; alter session set USE_STORED_OUTLINES = train;</p>
<p>&nbsp;&nbsp;&nbsp; 当为一个查询寻找stored outline时，查询语句与stored outline里的语句必须完全一致，在outline里的hints也必须在查询语句中出现。</p>
<p>&nbsp;&nbsp;&nbsp; 3、private outline</p>
<p>&nbsp;&nbsp;&nbsp; Private outline是当前保存的stored outline的副本，可以被编辑而不影响正在运行的系统，一个private outline只能被当前session看到，它的数据被保存在当前被解析的schema里。，知道显示的将其公布。<br />
&nbsp;&nbsp;&nbsp;
当USE_PRIVATE_OUTLINES=TRUE时，一个已有outline的sql被提交时，optimizer会检查是否存在private
outline，如果不存在，optimizer就不使用optimizer编译语句，而不会去检查公布的stored outline。</p>
<p>&nbsp;&nbsp;&nbsp; 4、在sql中使用hints<br />
&nbsp;&nbsp;&nbsp; Create index gen_idx on customers(cust_gender);<br />
&nbsp;&nbsp;&nbsp; Select /*+ index(customers gen_idx)*/<br />
&nbsp;&nbsp;&nbsp; Cust_last_name,cust_street_address,cust_postal_code<br />
&nbsp;&nbsp;&nbsp; From sh.customers where upper(gender)=&#8217;M&#8217;;</p>
<p>&nbsp;&nbsp;&nbsp; 5、EXPLAIN PLAN<br />
&nbsp;&nbsp;&nbsp; 可以不通过tracing，需要建立plan_table表：<br />
&nbsp;&nbsp;&nbsp; Sql&gt;@oracle_home/rdbms/admin/utlxplan;<br />
&nbsp;&nbsp;&nbsp; 建立explain plan：<br />
&nbsp;&nbsp;&nbsp; Explain plan for select last_name from hr.emp;<br />
&nbsp;&nbsp;&nbsp; 查询plan_table中的explain plan，可以直接查询，也可以通过脚本utlxplx.sql(隐藏并行查询信息)、utlxplp.sql（显示并行查询信息）查询。</p>
<p>&nbsp;&nbsp;&nbsp; 6、管理统计信息<br />
&nbsp;&nbsp;&nbsp; 利用analyize命令收集或删除信息。<br />
&nbsp;&nbsp;&nbsp; 参数：<br />
&nbsp;&nbsp;&nbsp; Compute：统计精确的数据；<br />
&nbsp;&nbsp;&nbsp; Estimate：估计的统计数据。</p>
<p>&nbsp;&nbsp;&nbsp; 各类统计数据的位置：<br />
&nbsp;&nbsp;&nbsp; 表：dba_tables;<br />
&nbsp;&nbsp;&nbsp; 索引：dba_indexes;<br />
&nbsp;&nbsp;&nbsp; 列：user_tab_col_statistics;<br />
&nbsp;&nbsp;&nbsp; 柱状图（histogram）详细的描述了一个特定列中数据的分布情况，可以通过analyize table ... for columns... 命令创建，保存在dba_histogram/dba_tab_histograms中。</p>
<p><br />
</p>
<p>&nbsp;&nbsp;&nbsp; <strong><strong><span style="color: #2000ff;">十、操作系统优化和使用资源管理器</span></strong></strong></p>
<p>&nbsp;&nbsp;&nbsp; 1、操作系统优化<br />
&nbsp;&nbsp;&nbsp; 1）概念<br />
&nbsp;&nbsp;&nbsp; 操作系统优化时应该考虑的因素有：内存的使用；Cpu的使用；IO级别；网络流量。各个因素互相影响，正确的优化次序是内存、IO、CPU。<br />
&nbsp;&nbsp;&nbsp;
操作系统使用了虚拟内存的概念，虚拟内存使每个应用感觉自己是使用内存的唯一的应用，每个应用都看到地址从0开始的单独的一块内存，虚拟内存被分成4K或
8K的page，操作系统通过MMU（memory management unit）将这些page与物理内存映射起来，这个映射关系通过page
table控制。<br />
&nbsp;&nbsp;&nbsp; Raw device是没有文件结构或目录结构的磁盘或磁盘分区，由于它忽略了操作系统缓存，在某些情况下可以显着提升性能，但是在windows NT下，由于操作系统IO操作本身不使用文件系统缓存，所以raw device不能显示性能上的优点。</p>
<p>&nbsp;&nbsp;&nbsp; 2）Guideline<br />
&nbsp;&nbsp;&nbsp; CPU的最高使用率：90％；<br />
&nbsp;&nbsp;&nbsp; OS/USER进程数之比：40/60；<br />
&nbsp;&nbsp;&nbsp; 各个CPU的负载应该大致均衡。</p>
<p>&nbsp;&nbsp;&nbsp; 3）服务器安全性检查<br />
&nbsp;&nbsp;&nbsp; A、检查UNIX系统用户口令<br />
&nbsp;&nbsp;&nbsp; 检查：/etc/passwd、/etc/shadow，UNIX密码采用了shadow机制，安全性能高<br />
&nbsp;&nbsp;&nbsp; 建议：参考UNIX命令passwd，修改/etc/default/passwd文件的某些设置如MAXWEEKS、MINWEEKS、PASSLENGTH使口令修改更加合理化。<br />
&nbsp;&nbsp;&nbsp; 建议：定期更改UNIX系统的如下用户口令：<br />
&nbsp;&nbsp;&nbsp; root、oraprod、applprod、appprod</p>
<p>&nbsp;&nbsp;&nbsp; B、检查 Remote Login<br />
&nbsp;&nbsp;&nbsp; 启动了rlogin，服务器数据库a、数据库b、数据库c，终端console1、console2、console3及T3形成相互非常信任的关系，用户只要拥有一个服务器的超级权限就可以rlogin到.rhosts指明的任一主机而无需要口令。<br />
&nbsp;&nbsp;&nbsp; 建议：非常不安全，参考UNIX命令rlogin和/目录下的文件.rhosts。在正式环境服务器和测试环境服务器之间不要建立这种远程信任的机制。</p>
<p>&nbsp;&nbsp;&nbsp; C、检查FTP服务<br />
&nbsp;&nbsp;&nbsp; 检查可以FTP到服务器的用户（/etc/ftpusers），注释了root用户，就是说用户可以用root权限FTP到服务器上。权限太大。<br />
&nbsp;&nbsp;&nbsp; 建议：把这种权力取消，将/etc/ftpusers中root的注释符号（#）去掉，在列表中添加oraprod、applprod、appprod等用户使之不能FTP服务器。必要时（如上传PATCH时）再打开applprod的FTP权限。<br />
&nbsp;&nbsp;&nbsp; D、建议：UNIX系统管理员定期检查/var/adm下的messages、sulog；/etc/syslog.conf 等信息。检查是否有非法用户登陆UNIX。<br />
&nbsp;&nbsp;&nbsp; 建议：与UNIX工程师探讨更好的监控方式</p>
<p>&nbsp;&nbsp;&nbsp; 4）数据库与应用产品安全性检查<br />
&nbsp;&nbsp;&nbsp; A、建议：修改oracle用户根目录下的.profile文件，修改该文件的权限为500。即使得用户登陆时并不执行和数据库或应用相关的环境变量，增加安全性。<br />
&nbsp;&nbsp;&nbsp; B、检查数据库DBA权限的用户密码和应用系统用户密码：SYSTEM、APPS密码都已经改变，SYS密码还是初始安装密码Change_on_install<br />
&nbsp;&nbsp;&nbsp; 建议：立即修改SYS用户密码，定期更改APPS、SYSTEM、SYS密码。<br />
&nbsp;&nbsp;&nbsp; C、定期检查并清除$ORACLE_HOME/admin/bdump目录下的alert_PROD.log文件和后台进程trace文件。定期清除$ORACLE_HOME/admin/udump目录下的trc文件。<br />
&nbsp;&nbsp;&nbsp; D、建议：给应用产品登陆的用户设置口令过期限制，如口令访问次数限制或时间（天数）限制。<br />
&nbsp;&nbsp;&nbsp; 建议：不要给使用应用产品的用户共享用户名和口令，每个用户分配一个应用产品用户名。<br />
&nbsp;&nbsp;&nbsp; 建议：对有应用系统管理员权限的用户登记，不适合有系统管理员权限的用户要把权限回收，统一管理。<br />
&nbsp;&nbsp;&nbsp; E、定期检查并清除与Apache Server有关的log文件，目录为:<br />
&nbsp;&nbsp;&nbsp; /u01/prodora/iAS/Apache/Apache/logs/acccess_log、error_log<br />
&nbsp;&nbsp;&nbsp; /u01/prodora/iAS/Apache/Jserv/logs/jserv.log、mod_jserv.log<br />
&nbsp;&nbsp;&nbsp; F、定期检查清除listener、tnsname的log文件，文件存放在:<br />
&nbsp;&nbsp;&nbsp; /u01/prodora/8.0.6/network/admin/apps_prod.log、<br />
&nbsp;&nbsp;&nbsp; /u01/proddb/8.1.7/network/admin/prod.log<br />
&nbsp;&nbsp;&nbsp; /u01/proddb/8.1.7/network/log/listener.log、sqlnet.log&#8230;<br />
&nbsp;&nbsp;&nbsp; G、数据库控制文件做多个镜像，放在多个磁盘位置，提高安全性。</p>
<p>&nbsp;&nbsp;&nbsp; 5）网络安全性检查<br />
&nbsp;&nbsp;&nbsp; 检查$ORACLE_HOME/dbs/initPROD.ora文件<br />
&nbsp;&nbsp;&nbsp; #remote_login_passwordfile=EXCLUSIVE<br />
&nbsp;&nbsp;&nbsp; 设置为REMOTE_LOGIN_PASSWORDFILE=NONE，不允许远程客户用INTERNAL方式登陆。<br />
&nbsp;&nbsp;&nbsp; 2、资源管理器（Resource Manager）<br />
&nbsp;&nbsp;&nbsp; 通过资源管理器可以管理混合工作负载，控制系统性能。数据库资源管理器包括：<br />
&nbsp;&nbsp;&nbsp; ? Resource plans：包括 resource plan directives, 它指定了被分配到各个 resource consumer group的资源。<br />
&nbsp;&nbsp;&nbsp; ? Resource consumer groups：定义了具有类似资源使用需求的一组用户。<br />
&nbsp;&nbsp;&nbsp; ? Resource plan directives：包括下列内容:为consumer groups 或 subplans 指定resource plans；在各个 consumer groups 或资源计划的subplans 分配资源。</p>
<p><br />
</p>
<p><br />
</p>
</span></span>
<img src ="http://www.blogjava.net/Juizes361/aggbug/305289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Juizes361/" target="_blank">残叶舞风</a> 2009-12-09 15:55 <a href="http://www.blogjava.net/Juizes361/articles/305289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何开发Oracle存储过程(转)</title><link>http://www.blogjava.net/Juizes361/articles/303612.html</link><dc:creator>残叶舞风</dc:creator><author>残叶舞风</author><pubDate>Wed, 25 Nov 2009 06:33:00 GMT</pubDate><guid>http://www.blogjava.net/Juizes361/articles/303612.html</guid><wfw:comment>http://www.blogjava.net/Juizes361/comments/303612.html</wfw:comment><comments>http://www.blogjava.net/Juizes361/articles/303612.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Juizes361/comments/commentRss/303612.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Juizes361/services/trackbacks/303612.html</trackback:ping><description><![CDATA[<p>　　在我的上一个银行项目中，我接到编写ORACLE<a href="http://storage.it168.com/" target="_blank" class="nounderline" title="存储">存储</a>过
程的任务，我是程序员，脑袋里只有一些如何使用CALLABLE接口调用存储过程的经验，一时不知如何下手，我查阅了一些资料，通过实践发现编写
ORACLE存储过程是非常不容易的工作，即使上路以后，调试和验证非常麻烦。简单地讲，Oracle存储过程就是存储在Oracle数据库中的一个程
序。</p>
<p>　　<strong>一. 概述</strong></p>
<p>　　Oracle存储过程开发的要点是：</p>
<p>　　&#8226; 使用Notepad文本编辑器，用Oracle PL/SQL编程语言写一个存储过程;</p>
<p>　　&#8226; 在Oracle数据库中创建一个存储过程;</p>
<p>　　&#8226; 在Oracle数据库中使用SQL*Plus工具运行存储过程;</p>
<p>　　&#8226; 在Oracle数据库中修改存储过程;</p>
<p>　　&#8226; 通过编译错误调试存储过程;</p>
<p>　　&#8226; 删除存储过程;</p>
<p>　<strong>　二.环境配置</strong></p>
<p>　　包括以下内容：</p>
<p>　　&#8226; 一个文本编辑器Notepad;</p>
<p>　　&#8226; Oracle SQL*Plus工具，提交Oracle SQL和PL/SQL 语句到Oracle database。</p>
<p>　　&#8226; Oracle 10g express数据库，它是免费使用的版本;</p>
<p>　　需要的技巧：</p>
<p>　　&#8226; SQL基础知识,包括插入、修改、删除等</p>
<p>　　&#8226; 使用Oracle's SQL*Plus工具的基本技巧;</p>
<p>　　&#8226; 使用Oracle's PL/SQL 编程语言的基本技巧;</p>
<p>　　<strong>三.写一个存储过程</strong></p>
<p>　　存储过程使用Oracle's PL/SQL 程序语言编写，让我们写一个什么工作都不做的存储过程，我们可以编译和运行它而不用担心会对数据库产生任何损害。</p>
<p>　　在Notepad, 写下：</p>
<p>　　CREATE OR REPLACE PROCEDURE skeleton</p>
<p>　　IS</p>
<p>　　BEGIN</p>
<p>　　NULL;</p>
<p>　　END;</p>
<p>　　把文件存为skeleton.sql.</p>
<p>　　让我们一行行遍历这个存储过程:</p>
<p>　　1 CREATE OR REPLACE PROCEDURE skeleton</p>
<p>　　2 IS</p>
<p>　　3 BEGIN</p>
<p>　　4 NULL;</p>
<p>　　5 END;</p>
<p>　　行1:</p>
<p>　　CREATE OR REPLACE PROCEDURE 是一个SQL语句通知Oracle数据库去创建一个叫做skeleton存储过程, 如果存在就覆盖它;</p>
<p>　　行2:</p>
<p>　　IS关键词表明后面将跟随一个PL/SQL体。</p>
<p>　　行3:</p>
<p>　　BEGIN关键词表明PL/SQL体的开始。</p>
<p>　　行4:</p>
<p>　　NULL PL/SQL语句表明什么事都不做，这句不能删去，因为PL/SQL体中至少需要有一句;</p>
<p>　　行5:</p>
<p>　　END关键词表明PL/SQL体的结束</p>
<p>　　<strong>四.创建一个存储过程</strong></p>
<p>　　SQL语句CREATE OR REPLACE PROCEDURE在Oracle数据库中创建、编译和保存一个存储过程。</p>
<p>　　从Window打开SQL*Plus并且从SQL*Plus登录到你的数据库;打开skeleton.sql文件.</p>
<p>　　在SQL&gt;命令提示符下输入以下命令：</p>
<p>　　SQL&gt;@skeleton</p>
<p>　　SQL&gt;/</p>
<p>　　SQL*Plus装载skeleton.sql文件的内容到SQL*Plus缓冲区并且执行SQL*Plus语句;SQL*Plus 会通知你存储过程已经被成功地创建。</p>
<p>　　现在你的存储过程被创建，编译和保存在你的Oracle数据库，我们可以运行它。</p>
<p>　　<strong>五.运行一个存储过程</strong></p>
<p>　　从SQL*Plus 命令行提示符运行你的存储过程使用EXECUTE命令，如下:</p>
<p>　　SQL&gt; EXECUTE skeleton;</p>
<p>　　SQL*Plus 输出一下信息确信存储过程成功执行: PL/SQL procedure successfully completed.</p>
<p>　　你也可以在一个无名PL/SQL块内运行你的存储过程，在SQL*Plus命令提示符下，它看起来像：</p>
<p>　　SQL&gt; BEGIN</p>
<p>　　2 SKELETON;</p>
<p>　　3 END;</p>
<p>　　4 /</p>
<p>　　现在我们已经运行了我们的存储过程，我们如何修改它呢?</p>
<p>　　<strong>六.修改一个存储过程</strong></p>
<p>　　让我们写一个输出字符串&#8220;Hello World!&#8221;的存储过程，用Notepad打开你的skeleton.sql 文件，. 用DBMS_OUTPUT.PUT_LINE 过程调用去替换NULL语句，如下所示:</p>
<p>　　CREATE OR REPLACE PROCEDURE skeleton</p>
<p>　　IS</p>
<p>　　BEGIN</p>
<p>　　DBMS_OUTPUT.PUT_LINE('Hello World!');</p>
<p>　　END;</p>
<p>　　保存到文件skeleton.sql.</p>
<p>　　从SQL*Plus命令行, 打开文件skeleton.sql .</p>
<p>　　SQL&gt; @skeleton</p>
<p>　　SQL&gt;</p>
<p>　　1 CREATE OR REPLACE PROCEDURE skeleton</p>
<p>　　2 IS</p>
<p>　　3 BEGIN</p>
<p>　　4 DBMS_OUTPUT.PUT_LINE('Hello World!');</p>
<p>　　5* END;</p>
<p>　　SQL&gt; /</p>
<p>　　SQL*Plus 通知你存储过程成功创建并输出提示信息：Procedure created.</p>
<p>　　SQL&gt;</p>
<p>　　用EXECUTE 命令运行你的存储过程:</p>
<p>　　SQL&gt; EXECUTE skeleton;</p>
<p>　　SQL*Plus显示存储过程运行成功：PL/SQL procedure successfully completed.</p>
<p>　　我们想要的输出字符串 "Hello World!"没有出来，在显示一个DBMS_OUTPUT.PUT_LINE 结果前需要运行一个SET命令，在SQL*Plus 命令行提示符,键入：</p>
<p>　　SQL&gt; SET SERVEROUTPUT ON</p>
<p>　　再次执行你的存储过程：</p>
<p>　　SQL&gt; EXECUTE skeleton;</p>
<p>　　现在结果输出了：Hello World!</p>
<p>　　PL/SQL procedure successfully completed.</p>
<p>　　<strong>七.调试一个存储过程</strong></p>
<p>　　当调试一个存储过程时，遵循一样的步骤，修改SQL文件，创建存储过程，执行存储过程，根据编译器反馈的出错信息进行修改，这一步是非常繁琐的，需要依靠经验。</p>
<p>　　在实际的商用存储过程的开发调试过程中，由于涉及很多表、类型、光标、循环、条件等复杂的逻辑，和PL/SQL语句的灵活运用，编译时会产生很多错误提示信息，程序员在根据这些错误信息定位，进行修正，再编译最后得到正确的结构;</p>
<p>　<strong>　八.放弃一个存储过程</strong></p>
<p>
如果在数据库中你不在需要一个存储过程你可以删除它，SQL语句 DROP PROCEDURE 完成从数据库中删除一个存储过程，DROP
PROCEDURE 在SQL中被归类为数据定义语言(DDL) 类操作，其他的例子有CREATE, ALTER, RENAME
和TRUNCATE。.</p>
<p>　　在SQL*Plus 命令提示符下，使用DROP PROCEDURE SQL 语句删除你的叫做skeleton的存储过程：</p>
<p>　　SQL&gt; DROP PROCEDURE skeleton;</p>
<p>　　SQL*Plus assures us the procedure has been removed:</p>
<p>　　Procedure dropped.</p>
<p>　<strong>　总结</strong></p>
<p>　　本文详细讨论了如何使用Oracle工具开发Oracle商用存储过程的步骤。最后在存储过程的使用中可能是程序直接调用，也可能被触发器调用。</p>
<img src ="http://www.blogjava.net/Juizes361/aggbug/303612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Juizes361/" target="_blank">残叶舞风</a> 2009-11-25 14:33 <a href="http://www.blogjava.net/Juizes361/articles/303612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Postgres模板数据库(转)</title><link>http://www.blogjava.net/Juizes361/articles/300304.html</link><dc:creator>残叶舞风</dc:creator><author>残叶舞风</author><pubDate>Fri, 30 Oct 2009 02:00:00 GMT</pubDate><guid>http://www.blogjava.net/Juizes361/articles/300304.html</guid><wfw:comment>http://www.blogjava.net/Juizes361/comments/300304.html</wfw:comment><comments>http://www.blogjava.net/Juizes361/articles/300304.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Juizes361/comments/commentRss/300304.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Juizes361/services/trackbacks/300304.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt;"><span style="font-family: Comic Sans MS;">
<p><tt class="COMMAND"><br />
</tt></p>
<p><tt class="COMMAND">CREATE DATABASE</tt>
实际上是通过拷贝一个现有的数据库进行工作的。缺省时，它拷贝名为 <tt class="LITERAL">template1</tt>
的标准系统数据库。所以该数据库是创建新数据库的"模板"。如果你给 <tt class="LITERAL">template1</tt>
增加对象，这些对象将被拷贝到随后创建的用户数据库中。这样的行为允许节点对数据库中的标准套件进行修改。比如，如果你把过程语言
PL/pgSQL 安装到 <tt class="LITERAL">template1</tt>
里，那么你在创建用户数据库的时候它们就会自动可得，而不需要额外的动作。</p>
<p>系统里还有名为 <tt class="LITERAL">template0</tt> 的第二个标准系统数据库，这个数据库包含和
<tt class="LITERAL">template1</tt> 初始时一样的数据内容，也就是说，只包含标准的
PostgreSQL 对象。在 <tt class="COMMAND">initdb</tt> 之后，我们不应该对
<tt class="LITERAL">template0</tt> 做任何修改。通过告诉 <tt class="COMMAND">CREATE DATABASE</tt> 使用 <tt class="LITERAL">template0</tt> 而不是 <tt class="LITERAL">template1</tt>
进行拷贝，你可以创建一个"纯净"的用户数据库，它不会包含任何 <tt class="LITERAL">template1</tt>
里所特有的东西。这一点在恢复 <tt class="LITERAL">pg_dump</tt>
转储的时候是非常方便的：转储脚本应该在一个纯净的数据库中恢复以确保我们正确创建了被转储出的数据库内容，而不和任何现在可能已经存在于
<tt class="LITERAL">template1</tt> 中的附加物相冲突。</p>
<p>要通过拷贝 <tt class="LITERAL">template0</tt>
的方法创建一个数据库，可使用下列方法之一：</p>
</span></span><br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">CREATE</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">DATABASE</span><span style="color: #000000;">&nbsp;dbname&nbsp;TEMPLATE&nbsp;template0;<br />
<br />
</span><span style="color: #000000;">createdb&nbsp;</span><span style="color: #808080;">-</span><span style="color: #000000;">T&nbsp;template0&nbsp;dbname</span><br />
</div>
<span style="font-size: 10pt;"><span style="font-family: Comic Sans MS;">
<p><br />
</p>
<p>前者用于 SQL 环境，后者用于 shell 环境。</p>
<p>我们可以创建额外的模板数据库，而且实际上我们可以在一个集群中通过将 <tt class="COMMAND">CREATE
DATABASE</tt> 的模板声明为相应的数据库名拷贝任何数据库。不过，我们必需明白，这个功能并非一般性的<span class="QUOTE">"<tt class="COMMAND">COPY
DATABASE</tt>"</span>工具。实际上，在拷贝操作的过程中，源数据库必需是空闲状态(没有正在处理的数据修改事务)。如果在
<tt class="COMMAND">CREATE DATABASE</tt> 开始的时候存在其它连接，那么操作将会失败，否则在
<tt class="COMMAND">CREATE DATABASE</tt> 的执行过程中新连接都将被锁定，直到拷贝完成。</p>
<p>在 <tt class="LITERAL">pg_database</tt>
里有两个有用的标志可以用于每个数据库：<tt class="LITERAL">datistemplate</tt> 和
<tt class="LITERAL">datallowconn</tt> 字段。<tt class="LITERAL">datistemplate</tt> 表示该数据库是准备用作 <tt class="COMMAND">CREATE
DATABASE</tt> 模板的。如果设置了这个标志，那么该数据库可以由任何有 <tt class="LITERAL">CREATEDB</tt> 权限的用户克隆；如果没有设置，那么只有超级用户和该数据库的所有者可以克隆它。如果
<tt class="LITERAL">datallowconn</tt>
为假，那么将不允许与该数据库发生任何新的连接(不过现有的会话不会因为把该标志设置为假而被杀死)。<tt class="LITERAL">template0</tt> 数据库通常被标记为 <tt class="LITERAL">datallowconn
= false</tt> 以避免对它的修改。<tt class="LITERAL">template0</tt> 和
<tt class="LITERAL">template1</tt> 都应该总是标记为 <tt class="LITERAL">datistemplate = true</tt> 。</p>
<p><strong>【注意】</strong><tt class="LITERAL">template1</tt> 和 <tt class="LITERAL">template0</tt> 没有任何特殊的状态，除了 <tt class="LITERAL">template1</tt> 是 <tt class="COMMAND">CREATE DATABASE</tt>
的缺省源数据库名之外。比如，我们可以删除 <tt class="LITERAL">template1</tt> 然后从
<tt class="LITERAL">template0</tt> 中创建它而不会有任何不良效果。如果我们不小心在
<tt class="LITERAL">template1</tt> 里加了一堆垃圾，那么我们就会建议做这样的操作。</p>
<p>&nbsp;</p>
<p>在初始化数据库集群的时候，也会创建 <tt class="LITERAL">postgres</tt>
数据库。这个数据库用于做为用户和应用连接的缺省数据库。它只是 <tt class="LITERAL">template1</tt>
的一个简单拷贝，需要的时候可以删除或者重建。</p>
<p><br />
</p>
<p><br />
</p>
</span></span>
<img src ="http://www.blogjava.net/Juizes361/aggbug/300304.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Juizes361/" target="_blank">残叶舞风</a> 2009-10-30 10:00 <a href="http://www.blogjava.net/Juizes361/articles/300304.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle 中rownum 用法总结! (转) </title><link>http://www.blogjava.net/Juizes361/articles/298017.html</link><dc:creator>残叶舞风</dc:creator><author>残叶舞风</author><pubDate>Tue, 13 Oct 2009 00:30:00 GMT</pubDate><guid>http://www.blogjava.net/Juizes361/articles/298017.html</guid><description><![CDATA[<span style="font-size: 10pt;">
<span style="font-size: 8pt;"><span style="font-size: 8pt;"><span><span style="font-size: 10pt;"><span style="font-size: 8pt; font-family: Comic Sans MS;">
<p><br />
&nbsp;&nbsp;&nbsp; 对于 Oracle 的 rownum 问题，很多资料都说不支持&gt;,&gt;=,=,between...and，只能用以上符号(&lt;、&lt;=、!=)，并非说用&gt;, &gt;=, =, between..and 时会提示SQL语法错误，而是经常是查不出一条记录来，还会出现似乎是莫名其妙的结果来，其实您只要理解好了这个 rownum 伪列的意义就不应该感到惊奇，同样是伪列，rownum 与 rowid 可有些不一样，下面以例子说明<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;假设某个表 t1(c1) 有20 条记录, 如果用 select rownum,c1 from t1 where rownum &lt; 10, 只要是用小于号，查出来的结果很容易地与一般理解在概念上能达成一致，应该不会有任何疑问的。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;可如果用 select rownum,c1 from t1 where rownum &gt; 10 (如果写下这样的查询语句，这时候在您的头脑中应该是想得到表中后面10条记录)，你就会发现，显示出来的结果要让您失望了，也许您还会怀疑是不谁删了一些记录，然后查看记录数，仍然是 20 条啊？那问题是出在哪呢？<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;先好好理解 rownum 的意义吧。因为ROWNUM是对结果集加的一个伪列，即先查到结果集之后再加上去的一个列 (强调：先要有结果集)。简单的说 rownum 是对符合条件结果的序列号。它总是从1开始排起的。所以你选出的结果不可能没有1，而有其他大于1的值。所以您没办法期望得到下面的结果集：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;11&nbsp; aaaaaaaa<br />
&nbsp;&nbsp;&nbsp;&nbsp;12&nbsp; bbbbbbb<br />
&nbsp;&nbsp;&nbsp;&nbsp;13&nbsp; ccccccc<br />
&nbsp;&nbsp;&nbsp;&nbsp;.................<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;rownum &gt;10 没有记录，因为第一条不满足去掉的话，第二条的ROWNUM又成了1，所以永远没有满足条件的记录。或者可以这样理解：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;ROWNUM是一个序列，是oracle数据库从数据文件或缓冲区中读取数据的顺序。它取得第一条记录则rownum值为1，第二条为2，依次类推。如果你用&gt;,&gt;=,=,between...and这些条件，因为从缓冲区或数据文件中得到的第一条记录的rownum为1，则被删除，接着取下条，可是它的rownum还是1，又被删除，依次类推，便没有了数据。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;有了以上从不同方面建立起来的对 rownum 的概念，那我们可以来认识使用 rownum 的几种现像<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;1. select rownum,c1 from t1 where rownum != 10 为何是返回前9条数据呢？它与 select rownum,c1 from tablename where rownum &lt; 10 返回的结果集是一样的呢？<br />
因为是在查询到结果集后，显示完第 9 条记录后，之后的记录也都是 != 10,或者 &gt;=10,所以只显示前面9条记录。也可以这样理解，rownum 为9后的记录的 rownum为10，因条件为 !=10，所以去掉，其后记录补上，rownum又是10，也去掉，如果下去也就只会显示前面9条记录了<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;2. 为什么 rownum &gt;1 时查不到一条记录，而 rownum &gt;0 或 rownum &gt;=1 却总显示所以的记录<br />
因为 rownum 是在查询到的结果集后加上去的，它总是从1开始<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;3. 为什么 between 1 and 10 或者 between 0 and 10 能查到结果，而用 between 2 and 10 却得不到结果<br />
原因同上一样，因为 rownum 总是从 1 开始<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;从上可以看出，任何时候想把 rownum = 1 这条记录抛弃是不对的，它在结果集中是不可或缺的，少了rownum=1 就像空中楼阁一般不能存在，所以你的 rownum 条件要包含到 1<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;但如果就是想要用 rownum &gt; 10 这种条件的话话就要用嵌套语句,把 rownum 先生成，然后对他进行查询。<br />
<br />
</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 58.79%; height: 71px; background-color: #eeeeee;"><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">select</span><span style="color: #000000;">&nbsp;</span><span style="color: #808080;">*</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">from</span><span style="color: #000000;">&nbsp;(selet&nbsp;rownum&nbsp;</span><span style="color: #0000ff;">as</span><span style="color: #000000;">&nbsp;rn，t1.</span><span style="color: #808080;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">from</span><span style="color: #000000;">&nbsp;a&nbsp;</span><span style="color: #0000ff;">where</span><span style="color: #000000;">&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" />)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">where</span><span style="color: #000000;">&nbsp;rn&nbsp;</span><span style="color: #808080;">&gt;</span><span style="font-weight: bold; color: #800000;">10</span></div>
<p><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;一般代码中对结果集进行分页就是这么干的。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;另外：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rowid 与 rownum 虽都被称为伪列，但它们的存在方式是不一样的，rowid 可以说是物理存在的，表示记录在表空间中的唯一位置ID，在DB中唯一。只要记录没被搬动过，rowid是不变的。rowid 相对于表来说又像表中的一般列，所以以 rowid 为条件就不会有 rownum那些情况发生。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rownum不能以任何基表的名称作为前缀。<br />
<br />
<br />
<br />
</p>
</span></span></span></span></span>
<p>&nbsp;</p>
</span>
<img src ="http://www.blogjava.net/Juizes361/aggbug/298017.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Juizes361/" target="_blank">残叶舞风</a> 2009-10-13 08:30 <a href="http://www.blogjava.net/Juizes361/articles/298017.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>