﻿<?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-生活·读书·新知</title><link>http://www.blogjava.net/perl5/</link><description>享受生活每一天</description><language>zh-cn</language><lastBuildDate>Thu, 07 May 2026 01:58:04 GMT</lastBuildDate><pubDate>Thu, 07 May 2026 01:58:04 GMT</pubDate><ttl>60</ttl><item><title>[Oracle性能模式] 查找某个号码是否在号码段列表中之性能模式</title><link>http://www.blogjava.net/perl5/archive/2011/04/30/349319.html</link><dc:creator>十次突击</dc:creator><author>十次突击</author><pubDate>Sat, 30 Apr 2011 08:01:00 GMT</pubDate><guid>http://www.blogjava.net/perl5/archive/2011/04/30/349319.html</guid><wfw:comment>http://www.blogjava.net/perl5/comments/349319.html</wfw:comment><comments>http://www.blogjava.net/perl5/archive/2011/04/30/349319.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/perl5/comments/commentRss/349319.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/perl5/services/trackbacks/349319.html</trackback:ping><description><![CDATA[<p>[Oracle性能模式] 查找某个号码是否在号码段列表中之性能模式(2011.04.30)<br />
【应用场景】<br />
&nbsp;&nbsp;&nbsp; 表test每行保存一个号码段(hm0, hm1)，不同记录的号码段不会出现交叉。需高效地判断出某个号码是否出现在某个号码段中。</p>
<p>-- 建测试表<br />
create table test (<br />
&nbsp; hm0&nbsp;number(8) not null,&nbsp;-- 号码起<br />
&nbsp; hm1&nbsp;number(8) not null&nbsp;-- 号码止<br />
);</p>
<p><br />
-- 插入2万条数据<br />
begin<br />
&nbsp; for i in 1..20000 loop<br />
&nbsp;&nbsp;&nbsp; insert into test values(i*100, i*100+10);&nbsp;-- hm0间隔100，每段10个号码，故不会交叉<br />
&nbsp; end loop;<br />
end;<br />
/<br />
commit;</p>
<p>-- 建索引<br />
create index i_test_1 on test(hm0, hm1);<br />
【低效模式】<br />
-- 查找号码 2000006 是否在号码段列表中<br />
select * from test a<br />
&nbsp; where a.hm0 &lt;= 2000006 and a.hm1&gt;= 2000006<br />
;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HM0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HM1<br />
---------- ----------<br />
&nbsp;&nbsp; 2000000&nbsp;&nbsp;&nbsp; 2000010</p>
<p>-- 注意查询计划中的 Search columns=1; 低效的原因在于Oracle会判断 hm0 &lt;= 2000006 的每条记录是否满足全部where条件<br />
SELECT STATEMENT, GOAL = CHOOSE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;INDEX RANGE SCAN&nbsp;Object owner=SCOTT&nbsp;Object name=I_TEST_1&nbsp;&nbsp;&nbsp;&nbsp;Search columns=1</p>
<p>Statistics<br />
----------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; recursive calls<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; db block gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 54&nbsp; consistent gets&nbsp;&nbsp;&nbsp;-- 记录数增多时，该值会加大<br />
&nbsp;&nbsp; <br />
【重构方案】<br />
-- 前提：<br />
-- 1. 需在 hm0 上建一 desc 索引<br />
-- 2. 利用 rownum&lt;... 特性,让Oracle找到第一条记录即停止扫描<br />
create index i_test_2 on test(hm0 desc);<br />
-- 利用表本身语义决定的号码段不会交叉的特性，这些Oracle优化器是不会知道的; index hint似乎不能少,否则Oracle不会自动走这个索引<br />
select * from(<br />
&nbsp; select /*+ index(a i_test_2) */ * from test a <br />
&nbsp;&nbsp;&nbsp; where a.hm0 &lt;= 2000006<br />
&nbsp;&nbsp;&nbsp; order by a.hm0 desc) b<br />
&nbsp; where rownum&lt;2 and b.hm1 &gt;= 2000006;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HM0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HM1<br />
---------- ----------<br />
&nbsp;&nbsp; 2000000&nbsp;&nbsp;&nbsp; 2000010</p>
<p>Execution Plan<br />
----------------------------------------------------------<br />
&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=26)<br />
&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; COUNT (STOPKEY)<br />
&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; VIEW (Cost=3 Card=1 Bytes=26)<br />
&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TABLE ACCESS (BY INDEX ROWID) OF 'TEST' (Cost=3 Card=1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bytes=26)</p>
<p>&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INDEX (RANGE SCAN) OF 'I_TEST_2' (NON-UNIQUE) (Cost=<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 Card=2)</p>
<p>Statistics<br />
----------------------------------------------------------<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; recursive calls<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; db block gets<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp; consistent gets</p>
<p>-- 结束测试删表<br />
drop table test;<br />
&nbsp; <br />
perl5原创@20110430</p>
<img src ="http://www.blogjava.net/perl5/aggbug/349319.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/perl5/" target="_blank">十次突击</a> 2011-04-30 16:01 <a href="http://www.blogjava.net/perl5/archive/2011/04/30/349319.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>