Oracle单表查询某列最大最小值的性能问题
在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也不行,我测试过了。

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

全表扫描在MySQL中可能比使用索引更快,具体情况包括:1)数据量较小时;2)查询返回大量数据时;3)索引列不具备高选择性时;4)复杂查询时。通过分析查询计划、优化索引、避免过度索引和定期维护表,可以在实际应用中做出最优选择。

InnoDB的全文搜索功能非常强大,能够显着提高数据库查询效率和处理大量文本数据的能力。 1)InnoDB通过倒排索引实现全文搜索,支持基本和高级搜索查询。 2)使用MATCH和AGAINST关键字进行搜索,支持布尔模式和短语搜索。 3)优化方法包括使用分词技术、定期重建索引和调整缓存大小,以提升性能和准确性。

是的,可以在 Windows 7 上安装 MySQL,虽然微软已停止支持 Windows 7,但 MySQL 仍兼容它。不过,安装过程中需要注意以下几点:下载适用于 Windows 的 MySQL 安装程序。选择合适的 MySQL 版本(社区版或企业版)。安装过程中选择适当的安装目录和字符集。设置 root 用户密码,并妥善保管。连接数据库进行测试。注意 Windows 7 上的兼容性问题和安全性问题,建议升级到受支持的操作系统。

MySQL是一个开源的关系型数据库管理系统。1)创建数据库和表:使用CREATEDATABASE和CREATETABLE命令。2)基本操作:INSERT、UPDATE、DELETE和SELECT。3)高级操作:JOIN、子查询和事务处理。4)调试技巧:检查语法、数据类型和权限。5)优化建议:使用索引、避免SELECT*和使用事务。

聚集索引和非聚集索引的区别在于:1.聚集索引将数据行存储在索引结构中,适合按主键查询和范围查询。2.非聚集索引存储索引键值和数据行的指针,适用于非主键列查询。

MySQL 和 MariaDB 可以共存,但需要谨慎配置。关键在于为每个数据库分配不同的端口号和数据目录,并调整内存分配和缓存大小等参数。连接池、应用程序配置和版本差异也需要考虑,需要仔细测试和规划以避免陷阱。在资源有限的情况下,同时运行两个数据库可能会导致性能问题。

MySQL 数据库中,用户和数据库的关系通过权限和表定义。用户拥有用户名和密码,用于访问数据库。权限通过 GRANT 命令授予,而表由 CREATE TABLE 命令创建。要建立用户和数据库之间的关系,需创建数据库、创建用户,然后授予权限。

MySQL支持四种索引类型:B-Tree、Hash、Full-text和Spatial。1.B-Tree索引适用于等值查找、范围查询和排序。2.Hash索引适用于等值查找,但不支持范围查询和排序。3.Full-text索引用于全文搜索,适合处理大量文本数据。4.Spatial索引用于地理空间数据查询,适用于GIS应用。
