单表查询某列最大最小值的性能问题
在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。这样的结果也很好理解。索引是唯一索引,已经排序好的,求一个最大