<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_killkill</title><subtitle type="text">专注于技术</subtitle><id>http://feed.cnblogs.com/blog/u/21523/rss</id><updated>2011-12-22T03:51:03Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><generator>CNBlogs BlogServer</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/21523/rss"/><entry><id>http://www.cnblogs.com/killkill/archive/2011/12/22/2297539.html</id><title type="text">MySQL重复记录删除</title><summary type="text">一种诡异的写法</summary><published>2011-12-22T03:50:00Z</published><updated>2011-12-22T03:50:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/12/22/2297539.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/12/22/2297539.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 一种诡异的写法：&lt;/p&gt;  &lt;pre &gt;delete t  &#xD;
from t, &#xD;
( select table_name,max(id) id &#xD;
  from t &#xD;
  group by table_name &#xD;
  having count(*)&amp;gt;1 ) d &#xD;
where t.table_name=d.table_name &#xD;
  and t.id&amp;lt;d.id;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 没见过这种语法，记录一下。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2297539.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/12/22/2297539.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/09/19/2181915.html</id><title type="text">使用Screen抵御杯具</title><summary type="text">Linux screen的简单用法</summary><published>2011-09-19T15:27:00Z</published><updated>2011-09-19T15:27:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/09/19/2181915.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/09/19/2181915.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 当DBA远程做一个大操作的时候最怕的是什么？断网！有木有啊！！&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 建一个20G的索引，进度到98%的时候突然断网，前功尽弃，有木有啊！！&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 怎么样才能抵御这种杯具呢？找一台Windows的机器作为终端，上面装上SSH工具，那Linux呢？靠它——screen&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;Screen是一个可以在多个进程之间多路复用一个物理终端的窗口管理器。Screen中有会话的概念，用户可以在一个screen会话中创建多个screen窗口，在每一个screen窗口中就像操作一个真实的telnet/SSH连接窗口那样。&lt;/strong&gt;简单来说就是一个命令行版本的SecureCRT。&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 当远程会话不幸关闭的时候，screen还能驻留在服务器端，并且很容易地重连（attach），这样就保证我们的工作不会因为网络问题而终端，这是多么好的功能啊。&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 键入screen即可使用screen&lt;/p&gt;  &lt;pre &gt;[oracle@alifina-dev12 ~]$ screen&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 如果报以下错：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;Cannot open your terminal '/dev/pts/10' - please check.&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 使用以下命令将输出重定向即可：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;[oracle@alifina-dev12 ~]$ script /dev/null &lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 然后我们开始一个任务，譬如用vim写小说，突然抓狂把终端强行关闭了，那时不是之前的努力都没有了呢？ &lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 我们重连一个会话，用以下命令查看并且再次attach即可，我们的成果还在！&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;[oracle@alifina-dev12 ~]$ screen -ls&#xD;
There is a screen on:&#xD;
        7366.pts-0.alifina-dev12        (Detached)&#xD;
1 Socket in /var/run/screen/S-oracle.&#xD;
&#xD;
[oracle@alifina-dev12 ~]$ screen -r 7366 &lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 这绝对是screen的杀手锏功能！！&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; screen还能做得更好吗？当然！&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 修改~/.screenrc，如果整台服务器都是你用的话也可以修改/etc/screenrc&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;## general tweaks&#xD;
vbell off&#xD;
autodetach on&#xD;
startup_message off&#xD;
defscrollback 1000&#xD;
attrcolor b &amp;quot;.I&amp;quot;&#xD;
termcap xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'&#xD;
defbce &amp;quot;on&amp;quot; &#xD;
escape &amp;quot;^Kk&amp;quot;&#xD;
defencoding UTF-8&#xD;
encoding UTF-8 UTF-8&#xD;
hardstatus alwayslastline '%{gk}[%= %{wk}%?%-Lw%?%{=b kR}[%{W}%n%f %t%?(%u)%?%{=b kR}]%{= kw}%?%+Lw%?%?%= %{g}]%{=b C}[%m/%d %C%a]%{W}'&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 现在screen开起来会像这样：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/killkill/201109/201109192326439805.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="Powered By killkill" border="0" alt="Powered By killkill" src="http://images.cnblogs.com/cnblogs_com/killkill/201109/201109192326432836.png" width="644" height="344" /&gt;&lt;/a&gt; &lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 看到没，下面那一行彩色的东西，输入Ctrl+k，紧接着马上输入c，多了一个：&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/killkill/201109/201109192326432280.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/killkill/201109/201109192326431723.png" width="644" height="342" /&gt;&lt;/a&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 输入 Ctrl+k n 就可以移动到下一个window（输入Ctrl+k p是上一个window），功能和SecureCRT的tab一样。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 有朋友会问为什么是Ctrl+k 呢？这个是在screenrc(.screenrc)中定义的，还有个特别的名字——命令键，我受Visual Studio的毒害很深，爱上了Ctrl+k，所以把它设为 Ctrl+k。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 一些有用的操作：&lt;/p&gt;&#xD;
&#xD;
&lt;ol&gt;&#xD;
  &lt;ol&gt;&#xD;
    &lt;li&gt;命令键 A（注意是大写的A，平时输入是shift+A）：将window改名。&lt;/li&gt;&#xD;
&#xD;
    &lt;li&gt;命令键 c：创建一个新的window&lt;/li&gt;&#xD;
&#xD;
    &lt;li&gt;命令键 d：detache当前这个screen&lt;/li&gt;&#xD;
&#xD;
    &lt;li&gt;命令键 ?：帮助……&lt;/li&gt;&#xD;
  &lt;/ol&gt;&#xD;
&lt;/ol&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2181915.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/09/19/2181915.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/06/15/2081317.html</id><title type="text">[摘]Oracle 11g Flashback_transaction_query的undo_sql为空？</title><summary type="text"/><published>2011-06-15T03:14:00Z</published><updated>2011-06-15T03:14:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/06/15/2081317.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/06/15/2081317.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 近日测试的时候发现 flashback_transaction_query中 undo_sql 为空，我记得以前明明不为空的，而且还做个&lt;a href="http://www.cnblogs.com/killkill/archive/2010/05/08/1730783.html" target="_blank"&gt;一单数据恢复&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://forums.oracle.com/forums/thread.jspa?threadID=1107387" target="_blank"&gt;经查证&lt;/a&gt;这个问题是 Oracle 11g 默认把 supplemental logging 禁用了导致的。&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 使用如下语句，把 supplemental logging 打开就好了：&lt;/p&gt;  &lt;pre &gt;alter database add supplemental log data;&lt;/pre&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2081317.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/06/15/2081317.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/05/29/2062118.html</id><title type="text">Duplicate Active Database 遇到 ORA-01017 invalid username/password</title><summary type="text">Duplicate Active Database 遇到挺蛋疼的问题。</summary><published>2011-05-29T07:21:00Z</published><updated>2011-05-29T07:21:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/05/29/2062118.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/05/29/2062118.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Oracle 11g 的新特性Duplicate Active Database可以在不备份target database的情况下构建 duplicate database，特别适合于为VLDB构建standby的场景。今天特意试一下，但是却让我遇上了 ORA-01017 invalid username/password，过程如下：&lt;/p&gt;  &lt;pre &gt;oracle@dev18:abank /home/oracle&amp;gt;rman target / auxiliary sys/__password__@abank_123 &#xD;
&#xD;
Recovery Manager: Release 11.2.0.1.0 - Production on Sun May 29 14:16:08 2011&#xD;
&#xD;
Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.&#xD;
&#xD;
connected to target database: abank (DBID=433589790)&#xD;
connected to auxiliary database: abank (not mounted)&#xD;
&#xD;
RMAN&amp;gt; duplicate target database for standby from active database ;  &#xD;
&#xD;
Starting Duplicate Db at 2011-05-29 14:16:17&#xD;
using target database control file instead of recovery catalog&#xD;
allocated channel: ORA_AUX_DISK_1&#xD;
channel ORA_AUX_DISK_1: SID=1149 device type=DISK&#xD;
&#xD;
contents of Memory Script:&#xD;
{&#xD;
   backup as copy reuse&#xD;
   targetfile  '/opt/app/oracle/product/11.2.0/db/dbs/orapwabank' auxiliary format &#xD;
 '/opt/app/oracle/product/11.2.0/db/dbs/orapwabank'   ;&#xD;
}&#xD;
executing Memory Script&#xD;
&#xD;
Starting backup at 2011-05-29 14:16:18&#xD;
allocated channel: ORA_DISK_1&#xD;
channel ORA_DISK_1: SID=594 device type=DISK&#xD;
RMAN-00571: ===========================================================&#xD;
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============&#xD;
RMAN-00571: ===========================================================&#xD;
RMAN-03002: failure of Duplicate Db command at 05/29/2011 14:16:19&#xD;
RMAN-03015: error occurred in stored script Memory Script&#xD;
RMAN-03009: failure of backup command on ORA_DISK_1 channel at 05/29/2011 14:16:19&#xD;
ORA-17629: Cannot connect to the remote database server&#xD;
ORA-17627: ORA-01017: invalid username/password; logon denied&#xD;
ORA-17629: Cannot connect to the remote database server&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 打开rman的时候已经进行了验证，理论上不应在有验证的问题，google得知使用Duplicate Active Database要这样登入rman：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;rman target sys/__password__ auxiliary sys/__password__@abank_123 &lt;/pre&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2062118.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/05/29/2062118.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/05/14/2046321.html</id><title type="text">[摘]如何抓住蝴蝶效应中的那只蝴蝶</title><summary type="text">看了老白分享的一个案例，感触很深，特此摘录。</summary><published>2011-05-14T07:34:00Z</published><updated>2011-05-14T07:34:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/05/14/2046321.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/05/14/2046321.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 原文地址：&lt;a href="http://www.oraclefans.cn/forum/showblog.jsp?rootid=32059" target="_blank"&gt;如何抓住蝴蝶效应中的那只蝴蝶&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 蝴蝶效应可以参考&lt;a href="http://baike.baidu.com/view/1180.htm" target="_blank"&gt;这里&lt;/a&gt;。&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 南美丛林的一只蝴蝶煽动翅膀，可能导致莫斯科下大雪，说明的大气系统的复杂性。而DBA在日常工作中叶经常会面临类似的问题，我们从故障的表象上分析问题处理问题，而往往我们采取的措施仅仅是解决一些表象的问题，并没有找到问题的关键。也就是说，我们并没有抓到扇翅膀的那只蝴蝶，而仅仅抓住了莫斯科上空的乌云。&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 前几天碰到一个案例，写出来和大家共享。客户有一套系统下午1点多的时候，突然出现了故障，服务无法响应，新会话连不上去。最后只能通过杀掉了大量的会话，才恢复正常。客户想找到问题的原因。找到我的时候已经是下午的4点多了。出现故障的时段有大量这样的信息：&lt;/p&gt;  &lt;pre &gt;Mon Apr 11 12:52:24 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_10410.trc:&#xD;
ORA-00603: ORACLE server session terminated by fatal error&#xD;
ORA-27544: Failed to map memory region for export&#xD;
ORA-27300: OS system dependent operation:bind failed with status: 227&#xD;
ORA-27301: OS failure message: Can't assign requested address&#xD;
ORA-27302: failure occurred at: sskgxpcre3&#xD;
Mon Apr 11 12:55:01 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_13426.trc:&#xD;
ORA-00603: ORACLE server session terminated by fatal error&#xD;
ORA-27544: Failed to map memory region for export&#xD;
ORA-27300: OS system dependent operation:bind failed with status: 227&#xD;
ORA-27301: OS failure message: Can't assign requested address&#xD;
ORA-27302: failure occurred at: sskgxpcre3&#xD;
Mon Apr 11 12:55:25 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_13934.trc:&#xD;
ORA-00603: ORACLE server session terminated by fatal error&#xD;
ORA-27544: Failed to map memory region for export&#xD;
ORA-27300: OS system dependent operation:bind failed with status: 227&#xD;
ORA-27301: OS failure message: Can't assign requested address&#xD;
ORA-27302: failure occurred at: sskgxpcre3&#xD;
Mon Apr 11 12:55:25 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_13936.trc:&#xD;
ORA-00603: ORACLE server session terminated by fatal error&#xD;
ORA-27504: IPC error creating OSD context&#xD;
ORA-27300: OS system dependent operation:bind failed with status: 227&#xD;
ORA-27301: OS failure message: Can't assign requested address&#xD;
ORA-27302: failure occurred at: sskgxpcre3&#xD;
Mon Apr 11 12:55:25 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_13938.trc:&#xD;
ORA-00603: ORACLE server session terminated by fatal error&#xD;
ORA-27504: IPC error creating OSD context&#xD;
ORA-27300: OS system dependent operation:bind failed with status: 227&#xD;
ORA-27301: OS failure message: Can't assign requested address&#xD;
ORA-27302: failure occurred at: sskgxpcre3&#xD;
Mon Apr 11 12:56:00 2011&#xD;
Thread 2 advanced to log sequence 2945 (LGWR switch)&#xD;
  Current log# 4 seq# 2945 mem# 0: /redolog/sjzzw2/redo04.log&#xD;
Mon Apr 11 12:56:01 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_14554.trc:&#xD;
ORA-00603: ORACLE server session terminated by fatal error&#xD;
ORA-27544: Failed to map memory region for export&#xD;
ORA-27300: OS system dependent operation:bind failed with status: 227&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 同时还存在一些类似的ORA-27XXX错误：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;Mon Apr 11 12:56:33 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_22957.trc:&#xD;
ORA-27509: IPC error receiving a message&#xD;
ORA-27300: OS system dependent operation:recvmsg failed with status: 216&#xD;
ORA-27301: OS failure message: Socket operation on non-socket&#xD;
ORA-27302: failure occurred at: sskgxprcv1&#xD;
Mon Apr 11 12:56:33 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_25431.trc:&#xD;
ORA-27509: IPC error receiving a message&#xD;
ORA-27300: OS system dependent operation:recvmsg failed with status: 216&#xD;
ORA-27301: OS failure message: Socket operation on non-socket&#xD;
ORA-27302: failure occurred at: sskgxprcv1&#xD;
Mon Apr 11 12:57:24 2011&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 根据&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;ORA-27300: OS system dependent operation:recvmsg failed with status: 216&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 现场工程师认为是BUG 6689903导致，建议关闭NUMA。客户准备晚上实施关闭NUMA的操作，想听听我的建议。我觉得关闭NUMA时一个十分大的操作，应该十分谨慎，因此先要搞清楚到底是什么导致了今天的问题。从ORA-27300来看，一般来说是某种OS资源不足导致的问题。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 因此我们首先要从分析错误信息开始，HP-UX的ERRNO=227，216&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;#  define ENOTSOCK              216     /* Socket operation on non-socket */&#xD;
#  define EADDRNOTAVAIL         227     /* Can't assign requested address */ &lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 216 是在非SOCKET上操作SOCKET操作，227是无法分配地址。对于BUG 6689903，Oracle官方解释是使用了NUMA后，Oracle存在一个BUG，导致一个会话使用了大量的UDP端口，造成UDP端口不足。可以通过打补丁或者关闭NUMA来解决这个问题。而UDP端口耗尽也可能出现ERRNO =227，无法分配地址的错误。因此可以初步判断是由于UDP端口耗尽导致了问题。在这种情况下打PATCH 6689903可以解决过多UDP端口被一个会话消耗的问题，但是不一定能解决所有的问题，当系统负载进一步加大（系统设置的 PROCESSES=4500，而出故障时发现会话数无法突破1600）,可能还会出问题。关闭NUMA虽然可以减少UDP端口的使用，但是会降低系统的性能，无法充分享受大型SMP系统的架构优势，也是不足取的。因此较好的解决这个问题是打PATCH 6689903，避免由于BUG过多消耗UDP端口，另外调整UDP端口的范围，从而让OS提供更多的UDP端口。通过下面命令：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;oracle@sjzzw22:/usr/include/sys$ ndd -get /dev/udp udp_largest_anon_port&#xD;
65535&#xD;
oracle@sjzzw22:/usr/include/sys$ ndd -get /dev/udp udp_smallest_anon_port&#xD;
49152&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 我们看到系统的UDP端口使用了缺省值，通过调整这两个值，使中间的区间变大，就能提供更多的UDP端口号了。问题分析道这里，看样子已经解决的差不多了。可能大多数DBA到此就大功告成了。而老白认为其实不然，如果说建议NUMA只是看到了下雪时莫斯科上空的乌云，那么分析到这里也仅仅看到了西伯利亚冷空气的影响。离那只南美洲的蝴蝶还有万里之遥呢。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 老白当然会继续分析下去，是什么原因导致了UDP端口号被消耗光呢？客户说平时这个系统会话数在1000出头，故障时会话数达到了1600。这个是UDP端口号被消耗光的一个很好的解释。但是为什么会话数会突增呢?通过对应用架构的了解，我们知道这个系统的大多数应用没有采用连接池，而是客户端直接连接的，当系统处理能力下降时，客户端连接数据库的连接会增加，以适应外部服务的请求。因此我们可以将怀疑点集中到系统出现了变慢的情况。如果在故障前的某个时段，系统突然变慢了，那么就有可能造成会话数增加的可能。会话数增加后，UDP端口配置过低的问题就暴露出来了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 那么接下来我们就需要分析系统为什么会变慢，在什么时间变慢的。我们继续分析ALERT LOG，发现第一次报错的时间是12点41分左右：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;Mon Apr 11 12:38:06 2011&#xD;
Thread 2 advanced to log sequence 2940 (LGWR switch)&#xD;
  Current log# 3 seq# 2940 mem# 0: /redolog/sjzzw2/redo03.log&#xD;
Mon Apr 11 12:40:58 2011&#xD;
Errors in file /oracle/app/oracle/admin/sjzzw2/udump/sjzzw22_ora_25451.trc:&#xD;
ORA-00603: ORACLE server session terminated by fatal error&#xD;
ORA-27544: Failed to map memory region for export&#xD;
ORA-27300: OS system dependent operation:bind failed with status: 227&#xD;
ORA-27301: OS failure message: Can't assign requested address&#xD;
ORA-27302: failure occurred at: sskgxpcre3&#xD;
Mon Apr 11 12:40:59 2011&#xD;
Trace dumping is performing id=[cdmp_20110411124059]&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 看样子故障点应该在12点41分之前。于是我们做一个ASH报告，来看看12：:00-12:40之间系统发生了什么，为了便于分析，我们先按照10分钟周期做4个报告，在前面三个报告中，一切正常，在12:30-12:40的报告中，我们发现了一个疑点：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;gcs drm freeze in enter server       24&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 在 1分钟内，活跃会话的采样中，出现了24次drm的等待平均等待时间600毫秒左右。而且这个时间段内的SQL执行次数，BUFFER GET等指标明显低于前面的时段。因此我们可以初步断定，这可能是导致会话数量突增的一个重要疑点。而这个系统的另外一个节点跑的是完全不同的应用，而且还没有投产，为什么会出现这么多DRM呢？通过LMD,LMON，LMS等的日志我们也看出，在12:36-38这段时间里的DRM数量比前面时段增加了数倍。于是我们在另外一个节点上的12:30-12:40生成了一个ASH报告，从这里我们终于看到了那只美丽的蝴蝶的真面目了，原来在这个时段，在另外一个节点上有人用SQLPLUS登陆上去，访问了大量的故障节点的数据。而这个操作导致了DRM事件增加，短暂降低了系统的性能。如果UDP端口号够用，这个影响不会被放大，而仅仅会在12点多钟业务不繁忙时段出现短暂几分钟的性能下降，很快就会平息。而正是由于UDP端口号不足，才放大了这个蝴蝶扇翅膀动作。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 抓住了这只蝴蝶，那么如何解决这个问题就很明显了，尽可能不要出现类似的操作肯定是要提的。不过另外一个问题也是需要我们考虑的，在这样的一个系统中，DRM其实是不必要的，因为正常情况下，两个节点会跑自己的数据，不会交叉。因此关闭DRM是一个更靠谱的选择。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 大家可能对关闭DRM这个结局感到意外，不过如果你看过了这个抓蝴蝶的全过程，你就会认为这是顺理成章的事情了。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 事情就是这么简单，但是我想大多数人只会走到这个过程中的某个步骤，就停下了。这就是DBA之间的差距，不仅仅是技术上的，更多的是态度的问题。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2046321.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/05/14/2046321.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/04/30/2033228.html</id><title type="text">[原]将Oracle 中的blob导出到文件中</title><summary type="text"/><published>2011-04-29T16:41:00Z</published><updated>2011-04-29T16:41:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/04/30/2033228.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/04/30/2033228.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 直接上代码：&lt;/p&gt;  &lt;pre &gt;declare&#xD;
  l_directory varchar(200) := '__dir__';&#xD;
	l_file UTL_FILE.FILE_TYPE;  &#xD;
	l_buffer RAW(32767);  &#xD;
	l_amount BINARY_INTEGER:=32767;  &#xD;
	l_pos NUMBER:=1;  &#xD;
	l_Blob Blob;  &#xD;
	l_Blob_len Number;  &#xD;
	l_lob_id number;&#xD;
	CURSOR cur is &#xD;
	  select __id__ from __table_name__;&#xD;
BEGIN  &#xD;
  open cur;&#xD;
	loop&#xD;
	  fetch cur into l_lob_id;&#xD;
	  EXIT when cur%NOTFOUND; &#xD;
	  select __blob_fild__ into l_Blob from __table_name__ where __id__=l_lob_id ; &#xD;
	  l_file:=UTL_FILE.FOPEN(l_directory,'adapter_blob.'||to_char(l_lob_id)||'.bin','wb',32767); &#xD;
	  l_Blob_len:=dbms_lob.getlength(l_Blob);  &#xD;
	  l_pos := 1;&#xD;
	  WHILE l_pos&amp;lt;l_Blob_len LOOP  &#xD;
	    DBMS_LOB.READ(l_Blob,l_amount,l_pos,l_buffer);&#xD;
	    UTL_FILE.PUT_RAW(l_file,l_buffer,TRUE);  &#xD;
	    l_pos:=l_pos+l_amount;  &#xD;
	  end loop;  &#xD;
	  utl_file.fclose(l_file);  &#xD;
	end loop;	&#xD;
	exception  &#xD;
		when others then  &#xD;
		if utl_file.is_open(l_file) then  &#xD;
		utl_file.fclose(l_file);  &#xD;
		end if;  &#xD;
END;  &lt;/pre&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2033228.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/04/30/2033228.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/04/26/2029818.html</id><title type="text">[原]unique index和non unique index的区别</title><summary type="text"/><published>2011-04-26T14:13:00Z</published><updated>2011-04-26T14:13:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/04/26/2029818.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/04/26/2029818.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 今天做Schema评审的时候发现一个很奇怪的现象，也许是用工具生成的SQL语句，清一色的如下：&lt;/p&gt;  &lt;pre &gt;CREATE TABLE table_name (&#xD;
	id			NUMBER			NOT NULL,&#xD;
	......&#xD;
	......&#xD;
) ;&#xD;
&#xD;
CREATE INDEX table_name_PK ON table_name(ID) ;&#xD;
ALTER TABLE table_name &#xD;
  ADD CONSTRAINT table_name_PK PRIMARY KEY (ID) &#xD;
  USING INDEX table_name_PK ;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 通常来说主键（Primary Key，PK）的index是unique index，而现在变成了non-unique index，这有什么不同呢？于是我建了两张1000万数据的表，并用两种不同的index设定为PK的index，语句如下：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;create table tab1000w01 &#xD;
as &#xD;
select level id,'killkill Hello world' data&#xD;
from dual connect by level&amp;lt;=1000*10000;&#xD;
&#xD;
create table tab1000w02 &#xD;
as &#xD;
select level id,'killkill Hello world' data&#xD;
from dual connect by level&amp;lt;=1000*10000;&#xD;
&#xD;
CREATE UNIQUE INDEX tab1000w01_pk ON tab1000w01 (PK_ID)  ;&#xD;
ALTER TABLE  tab1000w01 ADD CONSTRAINT tab1000w01_PK PRIMARY KEY (PK_ID) USING INDEX tab1000w01_pk ;&#xD;
&#xD;
CREATE INDEX tab1000w02_pk ON tab500w02 (PK_ID)  ;&#xD;
ALTER TABLE  tab1000w02 ADD CONSTRAINT tab1000w02_PK PRIMARY KEY (PK_ID) USING INDEX tab1000w02_pk ;&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 以下是按照PK查找数据的语句：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;select * from tab1000w01 where id=34567;&#xD;
&#xD;
-------------------------------------------------------------------------------------------------&#xD;
| Id  | Operation                   | Name              | Rows  | Bytes | Cost (%CPU)| Time     |&#xD;
-------------------------------------------------------------------------------------------------&#xD;
|   0 | SELECT STATEMENT            |                   |     1 |    35 |     3   (0)| 00:00:01 |&#xD;
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB1000W01        |     1 |    35 |     3   (0)| 00:00:01 |&#xD;
|*  2 |   INDEX UNIQUE SCAN         | IDX_TAB1000W01_PK |     1 |       |     2   (0)| 00:00:01 |&#xD;
-------------------------------------------------------------------------------------------------&#xD;
&#xD;
Predicate Information (identified by operation id):&#xD;
---------------------------------------------------&#xD;
&#xD;
   2 - access(&amp;quot;ID&amp;quot;=34567)&#xD;
&#xD;
Statistics&#xD;
----------------------------------------------------------&#xD;
          0  recursive calls&#xD;
          0  db block gets&#xD;
          4  consistent gets&#xD;
&#xD;
&#xD;
select * from tab1000w02 where id=34567;&#xD;
&#xD;
-------------------------------------------------------------------------------------------------&#xD;
| Id  | Operation                   | Name              | Rows  | Bytes | Cost (%CPU)| Time     |&#xD;
-------------------------------------------------------------------------------------------------&#xD;
|   0 | SELECT STATEMENT            |                   |     1 |    35 |     3   (0)| 00:00:01 |&#xD;
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB1000W02        |     1 |    35 |     3   (0)| 00:00:01 |&#xD;
|*  2 |   INDEX RANGE SCAN          | IDX_TAB1000W02_PK |     1 |       |     2   (0)| 00:00:01 |&#xD;
-------------------------------------------------------------------------------------------------&#xD;
&#xD;
Predicate Information (identified by operation id):&#xD;
---------------------------------------------------&#xD;
&#xD;
   2 - access(&amp;quot;ID&amp;quot;=34567)&#xD;
&#xD;
Statistics&#xD;
----------------------------------------------------------&#xD;
          0  recursive calls&#xD;
          0  db block gets&#xD;
          5  consistent gets&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 从执行计划来看，一个是index unique scan，一个是index range scan，从consistent gets来看，一个是4，一个是5，使用unique index节省了1个，不要少看这1个consistent gets，它可是占了总体的20%啊。&lt;/p&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 不过这是为什么呢？这篇文章很好地介绍这两种索引的异同：&lt;a href="http://richardfoote.wordpress.com/2007/12/18/differences-between-unique-and-non-unique-indexes-part-i/" target="_blank"&gt;Differences Between Unique and Non-Unique Indexes&lt;/a&gt;，说到底是这两种索引的结构不同。引用一下这篇文章的分析：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;Leaf block dump&#xD;
===============&#xD;
header address 143336028=0x88b225c&#xD;
kdxcolev 0&#xD;
KDXCOLEV Flags = - - -&#xD;
kdxcolok 0&#xD;
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y&#xD;
kdxconco 2&#xD;
kdxcosdc 0&#xD;
kdxconro 500&#xD;
kdxcofbo 1036=0x40c&#xD;
kdxcofeo 1042=0x412&#xD;
kdxcoavs 6&#xD;
kdxlespl 0&#xD;
kdxlende 0&#xD;
kdxlenxt 75520140=0x480588c&#xD;
kdxleprv 75520138=0x480588a&#xD;
kdxledsz 0&#xD;
kdxlebksz 8036&#xD;
row#0[8022] flag: ------, lock: 0, len=14     &amp;lt;=== length is 14 bytes for the index row entry&#xD;
col 0; len 4; (4):  c3 60 61 1c&#xD;
col 1; len 6; (6):  04 80 50 3c 01 06         &amp;lt;=== rowid is stored as a second column for the index row entry&#xD;
row#1[8008] flag: ------, lock: 0, len=14&#xD;
col 0; len 4; (4):  c3 60 61 1d&#xD;
col 1; len 6; (6):  04 80 50 3c 01 07&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; non-unique index将 rowid 作为一个字段和数据字段组合成一个“唯一、复合”索引，而unique index的结构如下：&lt;/p&gt;&#xD;
&#xD;
&lt;pre &gt;Leaf block dump&#xD;
===============&#xD;
header address 143336028=0x88b225c&#xD;
kdxcolev 0&#xD;
KDXCOLEV Flags = - - -&#xD;
kdxcolok 0&#xD;
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y&#xD;
kdxconco 1&#xD;
kdxcosdc 0&#xD;
kdxconro 533&#xD;
kdxcofbo 1102=0x44e&#xD;
kdxcofeo 1112=0x458&#xD;
kdxcoavs 10&#xD;
kdxlespl 0&#xD;
kdxlende 0&#xD;
kdxlenxt 75527436=0x480750c&#xD;
kdxleprv 75527434=0x480750a&#xD;
kdxledsz 6&#xD;
kdxlebksz 8036&#xD;
row#0[8023] flag: ------, lock: 0, len=13, data:(6):  04 80 5e 34 02 82    &amp;lt;=== length is 13 byes and rowid not stored as a second column entry&#xD;
col 0; len 4; (4):  c3 60 30 2c&#xD;
row#1[8010] flag: ------, lock: 0, len=13, data:(6):  04 80 5e 34 02 83&#xD;
col 0; len 4; (4):  c3 60 30 2d&lt;/pre&gt;&#xD;
&#xD;
&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 从dump文件中可以看到结构不同导致index中的entry的长度是不一样的，unique index稍稍短一点，所以每个block可以容纳更多的index entry，从宏观来看unique index更小一点。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2029818.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/04/26/2029818.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/04/22/2024417.html</id><title type="text">[摘]Oracle限制某个数据库帐号只能在特定机器上连入数据库</title><summary type="text"/><published>2011-04-21T16:34:00Z</published><updated>2011-04-21T16:34:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/04/22/2024417.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/04/22/2024417.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 逛&lt;a href="http://www.itpub.net/thread-1421297-1-1.html" target="_blank"&gt;论坛&lt;/a&gt;的时候发现一个好脚本，记录下来以备日后有用：&lt;/p&gt;  &lt;pre &gt;CREATE OR REPLACE TRIGGER sys.trg_work_log&#xD;
AFTER LOGON ON DATABASE&#xD;
declare&#xD;
v_program_name varchar2(200);&#xD;
v_username varchar2(100);&#xD;
v_ip varchar2(18);&#xD;
v_error varchar2(1000);&#xD;
begin&#xD;
select username,program,SYS_CONTEXT('USERENV','IP_ADDRESS')   &#xD;
into v_username,v_program_name,v_ip&#xD;
from sys.v_$session where AUDSID = SYS_CONTEXT('USERENV', 'SESSIONID');&#xD;
if (upper(v_username)='TEST') then&#xD;
  if (UPPER(v_program_name) = 'SQLPLUS.EXE') then&#xD;
     if (v_ip = ('10.142.244.30')) then&#xD;
       RAISE_APPLICATION_ERROR(-20001,'You are not allowed to connect to the database,err01');&#xD;
         &#xD;
    end if;&#xD;
  ELSE&#xD;
     RAISE_APPLICATION_ERROR(-20001,'不能使用sqlplus登陸');&#xD;
        &#xD;
  end if;&#xD;
else&#xD;
   RAISE_APPLICATION_ERROR(-20001,'You are not allowed to connect to the database');&#xD;
   &#xD;
end if;&#xD;
&#xD;
END ;&#xD;
/&lt;/pre&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2024417.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/04/22/2024417.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/04/11/2013044.html</id><title type="text">[摘]将“相关值”导致的Nested Loop优化成Hash Join</title><summary type="text">一种“分片”处理的思想非常精妙。</summary><published>2011-04-11T14:46:00Z</published><updated>2011-04-11T14:46:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/04/11/2013044.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/04/11/2013044.html"/><content type="html">&lt;p&gt;原文地址：&lt;a href="http://www.itpub.net/thread-1376537-1-2.html"&gt;http://www.itpub.net/thread-1376537-1-2.html&lt;/a&gt;&lt;/p&gt; &lt;p&gt;“相关值”是我剽窃的一个词，与之相反的是“不相关值”，我借用来描述以下这种情况：在SQL中有两个表A和B要join，join条件是A.name=B.first_name，判定符“=”左右两边的值是“不相关”的，而substr(A.name,1,length(B.first_name))=B.first_name，判定符“=”左右两边的值是“相关”的，因为要通过“=”右边的值才能求出左边的值（相反亦然）。&lt;/p&gt; &lt;p&gt;由于这种“相关值”的情况，A、B表join的算法注定只能走Nested Loop了，因为每一个不同的驱动值（驱动表中的值，也就是B表中的值）将改变A表负责join的值，执行计划如下：&lt;/p&gt;&lt;pre &gt;select a.*,b.object_name from TEST_OBJECT a, TEST_OBJ1 b&#xD;
where substr(a.object_name,1,length(b.object_name))=b.object_name;&lt;/pre&gt;&lt;pre &gt;已选择108612行。&#xD;
&#xD;
已用时间:  00: 00: 21.54&#xD;
&#xD;
---------------------------------------------------------------------&#xD;
| Id  | Operation            |  Name        | Rows  | Bytes | Cost  |&#xD;
---------------------------------------------------------------------&#xD;
|   0 | SELECT STATEMENT     |              |       |       |       |&#xD;
|   1 |  NESTED LOOPS        |              |       |       |       |&#xD;
|   2 |   TABLE ACCESS FULL  | TEST_OBJ1    |       |       |       |&#xD;
|*  3 |   TABLE ACCESS FULL  | TEST_OBJECT  |       |       |       |&#xD;
---------------------------------------------------------------------&#xD;
&#xD;
Predicate Information (identified by operation id):&#xD;
---------------------------------------------------&#xD;
&#xD;
   3 - filter("B"."OBJECT_NAME"=SUBSTR("A"."OBJECT_NAME",1,LENGTH("B"."OBJ&#xD;
              ECT_NAME")))&#xD;
&#xD;
统计信息&#xD;
----------------------------------------------------------&#xD;
          1  recursive calls&#xD;
          0  db block gets&#xD;
    9262734  consistent gets&lt;/pre&gt;&#xD;
&lt;p&gt;这里展开一下，Nested Loop这个算法复杂度是 O(B*A) （B表示驱动表的记录数，A表示内部表），如果A、B都很大，那就杯具了，关于Nested Loop驱动表的选取就不展开了。&lt;/p&gt;&#xD;
&lt;p&gt;网友&lt;a href="http://anlinew.itpub.net/"&gt;anlinew&lt;/a&gt;提供了一种非常精妙的，决的优化方法，将语句改写成：&lt;/p&gt;&lt;pre &gt;select a.*,b.object_name from TEST_OBJECT a, TEST_OBJ1 b&#xD;
where substr(a.object_name,1,length(b.object_name))=b.object_name&#xD;
and substr(a.object_name,1,4)=substr(b.object_name,1,4)  &#xD;
and length(b.object_name)&amp;gt;3&#xD;
union all&#xD;
select a.*,b.object_name from TEST_OBJECT a, TEST_OBJ1 b&#xD;
where substr(a.object_name,1,length(b.object_name))=b.object_name&#xD;
and length(b.object_name)&amp;lt;4;&lt;/pre&gt;&lt;pre &gt;&lt;/pre&gt;&lt;pre &gt;已选择108612行。&#xD;
&#xD;
已用时间:  00: 06: 51.24&#xD;
&#xD;
-----------------------------------------------------------------------------------&#xD;
| Id  | Operation           | Name        | Rows  | Bytes | Cost (%CPU)| Time     |&#xD;
-----------------------------------------------------------------------------------&#xD;
|   0 | SELECT STATEMENT    |             |  3468 |   365K| 90997 (100)| 00:18:12 |&#xD;
|   1 |  UNION-ALL          |             |       |       |            |          |&#xD;
|*  2 |   HASH JOIN         |             |    34 |  3672 |   176   (2)| 00:00:03 |&#xD;
|*  3 |    TABLE ACCESS FULL| TEST_OBJ1   |   659 | 12521 |    35   (0)| 00:00:01 |&#xD;
|   4 |    TABLE ACCESS FULL| TEST_OBJECT | 52544 |  4566K|   139   (1)| 00:00:02 |&#xD;
|   5 |   NESTED LOOPS      |             |  3434 |   362K| 90821   (1)| 00:18:10 |&#xD;
|*  6 |    TABLE ACCESS FULL| TEST_OBJ1   |   659 | 12521 |    35   (0)| 00:00:01 |&#xD;
|*  7 |    TABLE ACCESS FULL| TEST_OBJECT |     5 |   445 |   138   (1)| 00:00:02 |&#xD;
-----------------------------------------------------------------------------------&#xD;
&#xD;
Predicate Information (identified by operation id):&#xD;
---------------------------------------------------&#xD;
&#xD;
   2 - access(SUBSTR("A"."OBJECT_NAME",1,4)=SUBSTR("B"."OBJECT_NAME",1,4))&#xD;
       filter("B"."OBJECT_NAME"=SUBSTR("A"."OBJECT_NAME",1,LENGTH("B"."OBJE&#xD;
              CT_NAME")))&#xD;
   3 - filter(LENGTH("B"."OBJECT_NAME")&amp;gt;3)&#xD;
   6 - filter(LENGTH("B"."OBJECT_NAME")&amp;lt;4)&#xD;
   7 - filter("B"."OBJECT_NAME"=SUBSTR("A"."OBJECT_NAME",1,LENGTH("B"."OBJE&#xD;
              CT_NAME")))&#xD;
&#xD;
统计信息&#xD;
----------------------------------------------------------&#xD;
          1  recursive calls&#xD;
          0  db block gets&#xD;
      33946  consistent gets&lt;/pre&gt;&#xD;
&lt;p&gt;执行计划虽然变复杂了，但是耗时大幅减少，consistent gets也大幅降低，作出巨大贡献的是Hash Join的引入。&lt;/p&gt;&#xD;
&lt;p&gt;这里再展开一下，Hash Join的复杂度是O(A+B)，简单来说就是对A、B表各扫描一次，如果A、B都比较大的情况来看，无疑Hash Join要比Nested Loop 优越很多。&lt;/p&gt;&#xD;
&lt;p&gt;扯远了，回到&lt;a href="http://anlinew.itpub.net/"&gt;anlinew&lt;/a&gt;的具体方法上吧，导致Hash Join出现的关键因素是一个谓词的引入：&lt;/p&gt;&lt;pre &gt;and substr(a.object_name,1,4)=substr(b.object_name,1,4)&lt;/pre&gt;&#xD;
&lt;p&gt;套用我剽窃的那个词来说，这是“不相关值”的对比！&lt;/p&gt;&#xD;
&lt;p&gt;&lt;a href="http://anlinew.itpub.net/"&gt;anlinew&lt;/a&gt;的核心思想是将数据“分片”，该例子中分片的依据是多少位首字母（这里是4），其中“大头”由Hash Join处理，而“小头”走Nested Loop，这种“抓大放小”的做法直接就从复杂度上进行了优化。&lt;/p&gt;&#xD;
&lt;p&gt;这种“分片”的思想非常值得借鉴，将“相关值”判断转化成“不相关值”的判断也是处理问题的一种有效手法。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/2013044.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/04/11/2013044.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/killkill/archive/2011/03/28/1997517.html</id><title type="text">[原]试用google的“手气不错”</title><summary type="text">写篇水文吧</summary><published>2011-03-28T02:43:00Z</published><updated>2011-03-28T02:43:00Z</updated><author><name>killkill</name><uri>http://www.cnblogs.com/killkill/</uri></author><link rel="alternate" href="http://www.cnblogs.com/killkill/archive/2011/03/28/1997517.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/killkill/archive/2011/03/28/1997517.html"/><content type="html">&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 第一次发现“手气不错”这个按钮竟然是我爸这个“电脑盲”，他认为这是个“算命”的功能，那时候是99年 ……&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 近来突然发现挺多人评论这个“手气不错”的功能，我也“手痒痒”地试一下搜索“数据仓库”这个关键字，但是竟然让我看到了两个 &amp;amp;nbsp; ^_^。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/killkill/201103/201103281042596783.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/killkill/201103/201103281042591210.png" width="607" height="476" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 点击“手气不错”之后，跳转到了“百度百科”-_-：&lt;/p&gt;  &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/killkill/201103/201103281043003686.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/killkill/201103/201103281043002257.png" width="764" height="221" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 感觉上还是给我一堆结果让我自己慢慢翻更爽一些。&lt;/p&gt;    &lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/killkill/201103/201103281050131019.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/killkill/201103/201103281050131509.png" width="734" height="479" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/killkill/aggbug/1997517.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/killkill/archive/2011/03/28/1997517.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
