Oracle单表查询某列最大最小值的性能问题

php中文网
发布: 2016-06-07 17:30:56
原创
1585人浏览过

在Oracle 10g中,有一个单表查询的SQL语句,它没有where子句,只是简单地同时求某列最大值和最小值。按照理解,它应该走全索引扫描

在oracle 10g中,有一个单表查询的sql语句,它没有where子句,只是简单地同时求某列最大值和最小值。
按照理解,它应该走全索引扫描,但它却走了全表扫描。单表的数据量有点大,组成也有点复杂,lob字段很多,索引有点多,加lob的索引一起有13个。这下性能就差很多,本来预计毫秒级别的操作变成了分钟。在其他同版本的库上,索引较少时,会走全索引扫描,但性能也不好,查询时的一致性读也很大。

sql是这样:select max(updateid),min(updateid) from dbcenter.table_name ;
很简单,而且updateid列上有一个唯一索引。索引也分析过,但现在执行起来却性能差的很,致命的全表扫描。


首先,使用set autotrace trace exp stat得到真实的执行计划。
sql> set timing on
sql> set autotrace trace exp stat
sql> set linesize 300

-------------------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
-------------------------------------------------------------------------------------
| 0 | select statement | | 1 | 7 | 373k (1)| 01:14:42 |
| 1 | sort aggregate | | 1 | 7 | | |
| 2 | table access full| table_name | 8665k| 57m| 373k (1)| 01:14:42 |
-------------------------------------------------------------------------------------

statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1700621 consistent gets
1506260 physical reads
0 redo size
602 bytes sent via sql*net to client
492 bytes received via sql*net from client
2 sql*net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

sql>

从结果中可以看到走的就是全表扫描。从统计值看,也是真正的全表扫描了,从头扫到尾巴的那种,没办法,表中这个字段的值又不是排序的,不全部扫完不知道最大最小值的。

很显然,这不是最优的结果。我认为最理想应该是走updateid列的索引,一个索引快速全扫描就行。

猜测,会不会是索引多了不知道如何选择。在select子句中是不主动选择索引的?

但是,我使用hint也没有效果,优化器依然没有选择走这个索引。


select/*+index_ffs(table_name idx55021287)*/ max(updateid), min(updateid) from dbcenter.table_name;

elapsed: 00:03:28.77

execution plan
----------------------------------------------------------


-------------------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
-------------------------------------------------------------------------------------
| 0 | select statement | | 1 | 7 | 373k (1)| 01:14:42 |
| 1 | sort aggregate | | 1 | 7 | | |
| 2 | table access full| table_name | 8665k| 57m| 373k (1)| 01:14:42 |
-------------------------------------------------------------------------------------
statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1701902 consistent gets
1497285 physical reads
0 redo size
602 bytes sent via sql*net to client
492 bytes received via sql*net from client
2 sql*net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

但是,如果只查max或min时,,会走索引。

select min(updateid) from dbcenter.table_name ;

execution plan
----------------------------------------------------------
plan hash value: 3935799349

------------------------------------------------------------------------------------------
| id | operation | name | rows | bytes | cost (%cpu)| time |
------------------------------------------------------------------------------------------
| 0 | select statement | | 1 | 7 | 373k (1)| 01:14:42 |
| 1 | sort aggregate | | 1 | 7 | | |
| 2 | index full scan (min/max)| idx55021287 | 8665k| 57m| | |
------------------------------------------------------------------------------------------


statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
524 bytes sent via sql*net to client
492 bytes received via sql*net from client
2 sql*net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

性能也好的很,一致性读只有3。这样的结果也很好理解。索引是唯一索引,已经排序好的,求一个最大值,肯定只要扫描索引的开始或者结束部分的数据块即可。


因此,需要分析一下这个sql的执行计划产生的过程。我使用event 10053 trace name context forever ,level 1方法来完成这个操作。

alter system flush shared_pool;
alter session set "_optimizer_search_limit"=15;
oradebug setmypid;
oradebug event 10053 trace name context forever ,level 1;
explain plan for select max(updateid),min(updateid) from dbcenter.table_name ;

***************************************
single table access path
-----------------------------------------
begin single table cardinality estimation
-----------------------------------------
table: table_name alias: table_name
card: original: 8663996 rounded: 8663996 computed: 8663996.00 non adjusted: 8663996.00
-----------------------------------------
end single table cardinality estimation
-----------------------------------------
access path: tablescan
cost: 373495.00 resp: 373495.00 degree: 0
cost_io: 372211.00 cost_cpu: 18442053762
resp_io: 372211.00 resp_cpu: 18442053762
******** begin index join costing ********
****** trying bitmap/domain indexes ******
access path: index (fullscan)
index: idx242025
resc_io: 25019.00 resc_cpu: 1911171307
ix_sel: 1 ix_sel_with_filters: 1
cost: 2515.21 resp: 2515.21 degree: 0
access path: index (fullscan)
index: idx94341804
resc_io: 31023.00 resc_cpu: 1953914433
ix_sel: 1 ix_sel_with_filters: 1
cost: 3115.90 resp: 3115.90 degree: 0
access path: index (fullscan)
index: pk_table_name
resc_io: 25217.00 resc_cpu: 1912567352
ix_sel: 1 ix_sel_with_filters: 1
cost: 2535.02 resp: 2535.02 degree: 0
access path: index (fullscan)
index: idx242025
resc_io: 25019.00 resc_cpu: 1911171307
ix_sel: 1 ix_sel_with_filters: 1
cost: 2515.21 resp: 2515.21 degree: 0
****** finished trying bitmap/domain indexes ******
******** end index join costing ********
best:: accesspath: tablescan
cost: 373495.00 degree: 1 resp: 373495.00 card: 8663996.00 bytes: 0
***************************************

从结果看,优化器在index join costing操作时,并没有将idx55021287索引计算进来。

即使我使用了alter session set "_optimizer_search_limit"=15;将限制值从5提升到15也没有效果。或许,index join costing操作时引入的索引数量不是这个参数控制。

最大最小值的查询操作,就不应该在SQL中一步完成,应该分步骤实现。很显然,oracle的查询重写没有那么智能,没有将其分开。即使在11g也不行,我测试过了。

linux

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号