一条简单的sql在11g和12c中的不同(r5笔记第2天)
今天在查看awr报告的时候,有一句很简单的sql语句引起了我的注意,因为它排在SQL Order by Reads的第2位。
Physical Reads |
Executions |
Reads per Exec |
%Total |
Elapsed Time (s) |
%CPU |
%IO |
SQL Id |
SQL Module |
---|---|---|---|---|---|---|---|---|
13,092,700 |
0 |
9.47 |
294.8 |
52.7 |
41.06 |
6src3hcd9mpt3 |
T.O.A.D. |
SQL Text |
---|
select * from mo1_memo where entity_id in (11889308, 11889311, 11888262, 11888261, 11889301) order by memo_date desc |
这条语句看起来很简单,自己印象中这个表中有一个相关的索引。
INDEX_NAME INDEX_TYPE UNIQUENES PAR COLUMN_LIST TABLE_TYPE STATUS NUM_ROWS LAST_ANAL G
------------------------------ ---------- ---------- --------- --- ------------------------------ ---------- ------ ---------- --------- -
MO1_MEMO_1IX FUNCTION-BASED NORMAL NONUNIQUE YES SYS_NC00031$,ENTITY_TYPE_ID,APP_ID TABLE N/A 554899259 01-APR-15 N
MO1_MEMO_2IX NORMAL NONUNIQUE YES MEMO_EXTERNAL_ID TABLE N/A 478847583 01-APR-15 N
MO1_MEMO_PK NORMAL UNIQUE YES MEMO_ID,APP_ID,ENTITY_KEY,PERIOD_KEY TABLE N/A 554900387 01-APR-15 N
有一个基于函数的索引,我们可以通过exp 或者dbms_metadata来得到相关的语句,发现索引是类似下面的形式。 create index MO1_MEMO_1IX on MO1_MEMO(entity_id desc,entity_type_id,app_id); 这是一个降序索引。对于这种降序索引,会在表中创建一个隐藏列。
SQL> select owner,column_name from all_tab_cols where table_name='MO1_MEMO' and hidden_column='YES';
APPO SYS_NC00031$
有了这些信息,感觉应该是可以走索引扫描的。
但是得到的执行计划中却走了全表扫描,对一个数据量5亿多数据的表走全表扫描,杀伤力是很大的。
但是奇怪的是使用下面两种形式就没有任何问题,索引都能正常启用。
select * from mo1_memo where entity_id in (11889308) order by memo_date desc
select * from mo1_memo where entity_id =11889308 order by memo_date desc
一般来说降序索引在其值不为空的情况会启用,根据目前的表结构来看entity_type_id和app_id有着not null constraint,所以应该能够启用才对。
带着这个问题,我在11g的环境中简单模拟了一把。
SQL> create table test as select *from all_objects where rownum<10000;
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(30)
OBJECT_NAME NOT NULL VARCHAR2(30)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(19)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
NAMESPACE NOT NULL NUMBER
EDITION_NAME VARCHAR2(30)
SQL> create index idx_test on test(object_id desc,object_name,object_type);
Index created.
SQL> select object_id from test where rownum<3;
OBJECT_ID
----------
2880583
2880575
SQL> set autot trace exp stat
下面两种情况的执行计划是一致的。
SQL> select *from test where object_id in (2880583,2880575);
SQL> select *from test where object_id=2880583;
Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020
----------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 127 | 20066 | 5 |
|* 1 | TABLE ACCESS FULL| TEST | 127 | 20066 | 5 |
----------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=2880575 OR "OBJECT_ID"=2880583)
SQL> select *from test where object_id in (2880583)
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 316 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 2 | 316 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_TEST | 1 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3BFCA6F9ABFF') )
filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=2880583)
根据上面的输出,感觉降序索引的细节上还有存在一定的问题,在优化器中可能没有很好的支持,查看MOS也没有找到相关的bug. 但是在12c的环境中,结果却明显不同,可见再优化器内部对于这种场景已经做了优化。
SQL> create table test as select *from all_objects where rownum<10000;
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER NOT NULL VARCHAR2(128)
OBJECT_NAME NOT NULL VARCHAR2(128)
SUBOBJECT_NAME VARCHAR2(128)
OBJECT_ID NOT NULL NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(23)
CREATED NOT NULL DATE
LAST_DDL_TIME NOT NULL DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
NAMESPACE NOT NULL NUMBER
EDITION_NAME VARCHAR2(128)
SHARING VARCHAR2(13)
EDITIONABLE VARCHAR2(1)
ORACLE_MAINTAINED VARCHAR2(1)
SQL> create index idx_test on test(object_id desc,object_name,object_type);
Index created.
SQL> select object_id from test where rownum<3;
OBJECT_ID
----------
10359
10358
SQL> set autot trace exp stat
SQL> select object_name from test where object_id in(10359,10358);
Execution Plan
----------------------------------------------------------
Plan hash value: 3459894390
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 158 | 3 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
|* 2 | INDEX RANGE SCAN| IDX_TEST | 2 | 158 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3CFDFBC4FF') OR
SYS_OP_DESCEND("OBJECT_ID")=HEXTORAW('3CFDFBC3FF'))
filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=10358 OR
SYS_OP_UNDESCEND(SYS_OP_DESCEND("OBJECT_ID"))=10359)
所以技术的进步总是一点一滴,新版本中已经做了修复,但是目前来看11g还是主流,所以我们在创建降序索引的时候还是需要注意,避免一些不必要的情况发生。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【STM32F407】第7章 RL-TCPnet V7.X网络协议栈移植(RTX5)
- 【STM32F429】第7章 RL-TCPnet V7.X网络协议栈移植(RTX5)
- [白话解析] 深入浅出 极大似然估计 & 极大后验概率估计
- 【STM32H7】第7章 RL-TCPnet V7.X网络协议栈移植(RTX5)
- TinyMCE 富文本编辑器的使用实例指导
- dotnet 在国产 UOS 系统利用 dotnet tool 工具做文件传输
- [白话解析] 深入浅出支持向量机(SVM)之核函数
- C# 线程同步之事件信号阻塞 AutoResetEvent
- [白话解析] 深入浅出最大熵模型
- [白话解析] 带你一起梳理Word2vec相关概念
- 利用SSE服务器主动向浏览器端发送消息
- [白话解析] Flink的Watermark机制
- [源码分析] 从源码入手看 Flink Watermark 之传播过程
- [白话解析]以水浒传为例学习隐马尔可夫模型
- [白话解析]用水浒传为例学习最大熵马尔科夫模型