您的位置:首页 > 数据库

SQL优化-同SQL不同执行计划(一)

2008-05-14 20:36 357 查看
问题来源:CSDN Oracle技术论坛

问题 :myepoch提出相同SQL因为检索的值,不同执行效率差别巨大。
问题环境:Oracle 10g,TBNC_P表在adminaccount有B树索引,
TBNC_P总记录数:33422行
TBNC_A总记录数:40782行
结果 :已经解决,优化后的SQL执行时间,均小于0.032
【SQL 1】:
[align=left]select art.article_id, art.article_title, aps.adminaccount[/align]
[align=left] from TBNC_A art, TBNC_P aps[/align]
[align=left] where art.column_id = aps.scopestr[/align]
[align=left] and aps.funcnodepath = 'A001B002C002D002E003'[/align]
and aps.adminaccount = 'lgm';

【SQL 2】:
[align=left]select art.article_id, art.article_title, aps.adminaccount[/align]
[align=left] from TBNC_A art, TBNC_P aps[/align]
[align=left] where art.column_id = aps.scopestr[/align]
[align=left] and aps.funcnodepath = 'A001B002C002D002E003'[/align]
and aps.adminaccount = 'admin_two';

两个SQL除了【aps.adminaccount】等于的值不同,其他完全一致,
执行时间(平均) 执行结果数
【SQL 1】 3.906 S 148
【SQL 2】 0.531 S 11421

执行计划如下:
【SQL1】
3 -----------------------------------------------------------------------------------------------------
4 ¦ Id ¦ Operation ¦ Name ¦ Rows ¦ Bytes ¦ Cost (%CPU) ¦ Time ¦
5 -----------------------------------------------------------------------------------------------------
6 ¦ 0 ¦ SELECT STATEMENT ¦ ¦ 888 ¦ 65712 ¦ 4291 (1) ¦ 00:00:52 ¦
7 ¦* 1 ¦ HASH JOIN ¦ ¦ 888 ¦ 65712 ¦ 4291 (1) ¦ 00:00:52 ¦
8 ¦* 2 ¦ TABLE ACCESS BY INDEX ROWID ¦ POWERSCOPE ¦ 11 ¦ 330 ¦ 3 (0) ¦ 00:00:01 ¦
9 ¦* 3 ¦ INDEX RANGE SCAN ¦ SYS_LGM ¦ 87 ¦ ¦ 1 (0) ¦ 00:00:01 ¦
10 ¦ 4 ¦ TABLE ACCESS FULL ¦ CMSARTICLE ¦ 40782 ¦ 1752K ¦ 4288 (1) ¦ 00:00:52 ¦
11 -----------------------------------------------------------------------------------------------------
【SQL2】
3 -------------------------------------------------------------------------------------------
4 ¦ Id ¦ Operation ¦ Name ¦ Rows ¦ Bytes ¦ Cost (%CPU) ¦ Time ¦
5 -------------------------------------------------------------------------------------------
6 ¦ 0 ¦ SELECT STATEMENT ¦ ¦ 44229 ¦ 3196K ¦ 4344 (1) ¦ 00:00:53 ¦
7 ¦* 1 ¦ HASH JOIN ¦ ¦ 44229 ¦ 3196K ¦ 4344 (1) ¦ 00:00:53 ¦
8 ¦* 2 ¦ TABLE ACCESS FULL ¦ POWERSCOPE ¦ 541 ¦ 16230 ¦ 56 (2) ¦ 00:00:01 ¦
9 ¦ 3 ¦ TABLE ACCESS FULL ¦ CMSARTICLE ¦ 40782 ¦ 1752K ¦ 4288 (1) ¦ 00:00:52 ¦
10 -------------------------------------------------------------------------------------------

【疑惑四】【执行计划成本】等价于【执行时间】
【疑惑三】SQL1检索的数据比SQL2的少,为什还比SQL2慢?
【疑惑二】SQL1中使用了索引【SYS_LGM】反而还比SQL2【全表扫描】慢?
【疑惑一】相同SQL语句,为什么存在【执行计划】的差别?

在SQL优化的方面没有什么定式,带着上述问题,开始在没有测试环境的前提下,开始和myepoch一起排查测试,寻找问题。

【疑惑一解答】
大多数人都会一样这样观点,相同SQL执行计划应该是相同的,这样的观点是错误,上面的问题就是很好的佐证,数据分布和存储特点都会影响执行计划的选择,Oracle选择的执行计划在统计信息正确的前提下,99%都不会有问题。

我做一个不算恰当的假设
假设我们有一个表,叫TableA,它有三个字段分别是ColA,ColB,ColC,表没有主键,所有字段都非空。每条记录存储在一个数据块中。
ColB值只能是('sys','user','costomer')这三种的其中一种,数据表中有一万条记录。
ColB数据的分布分别是(2%,95%,3%)
再假设,我们在ColB上有一个B树索引。
如果我们写这样的Sql:

SELECT *
FROM TableA
where ColB = 'user'

你说上面的SQL一定会使用在ColB上的索引吗? 结果是【不一定】
Oracle的执行计划会是根据统计分析做出的,执行计划会随着数据的变化而变化。
以上SQL多数时候是不使用索引的,因为Select字段的*影响了执行计划,
假设Oralce通过索引进行快速扫描,假设它会执行9500次检索,但为了取得ColA和ColC数据Oracle不得不在通过 Rowid获取数据,获取数据需要9500次,这样Oracle 就需要 19000次操作才能完成工作。
但要使用全表扫描只需要10000次就可以搞定了,所以这时候Oracle会选择全表扫描。不会选择使用索引。
当让Oralce不会执行10000次,它会通过好多种方法和手段去尽快完成工作,上面的说明只是方便说明而已,
但是基本原理相当。

如果我们改变SQL语句:
SELECT ColB
FROM TableA
where ColB = 'user'

你说Oracle还会选择【索引快速扫描】和【全表扫描】那种执行计划呢?
结果肯定是【索引快速扫描】。

如果我们再改变一下SQL语句:
SELECT *
FROM TableA
where ColB = 'sys'

你说Oracle 优化器会选择【索引快速扫描】和【全表扫描】那种执行计划呢?
结果是【索引快速扫描】,而不是【全表扫描】。
原因很简单,如果先通过【索引快速扫描】寻找到2%的数据的Rowid,然后在通过Rowid找到ColA和ColB的记录,
明显比【全表扫描】快,Oralce的代价不过400而已。

所以可以看出,Where不光是影响索引使用的唯一条件,Select也会影响索引使用。千万比忘记了这一点,很重要。
绝大多数时候Oracle自己可以自动收集【统计信息】,所以保证数据【统计信息】非常重要。

【统计信息】会影响【执行计划】。

综合上述,需要确认【统计信息】是否正确,确认语句如下:
select user_tables.num_rows,user_tables.last_analyzed,user_tables.*
from user_tables
where user_tables.table_name
in ('TBNC_A','TBNC_P');

更具上述分析,所以请求myepoch提供了【统计信息】,并且手动启动了【统计信息】包。
执行语句如下:
dbms_stats.gather_table_stats(ownname => '',tabname => 'TBNC_A');

【统计信息】包执行前,如下(摘要):
表名 记录数 最后统计时间 数据块数
TBNC_P 33422 2008-5-13 244
TBNC_A 40782 2008-2-15 19535

【统计信息】包执行后,如下(摘要):
表名 记录数 最后统计时间 数据块数
TBNC_P 33422 2008-5-13 244
TBNC_A 40782 2008-5-14 19535

统计后【SQL1】和【SQL2】未发生任何变化,判读错误,疑点排除,错误不在【执行计划】处。

接-> SQL优化-同SQL不同执行计划(二)
2008-05-14晚 凌蓝风
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: