[20191219]降序索引与取最大值.txt --//开发滥用降序索引,今天发现一个问题就是取最大值.通过例子说明: 1.环境: SCOTT@book> @ ver1 PORT_STRING VERSION BANNER ------------------- -------------- ---------------------------------------------------------------------------- x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production SCOTT@book> alter system set pga_aggregate_target=4G; System altered. SCOTT@book> create table t (id1 number,id2 number,vc varchar2(50)); Table created. create index i_t_id1 on t (id1); create index i_t_id2desc on t (id2 desc); SCOTT@book> insert into t select rownum,rownum,lpad('a',50,'a') from dual connect by level<=1e6; 1000000 rows created. SCOTT@book> commit ; Commit complete. --//分析略. SCOTT@book> select index_name,index_type,blevel,leaf_blocks,distinct_keys from dba_indexes where owner=user and table_name='T'; INDEX_NAME INDEX_TYPE BLEVEL LEAF_BLOCKS DISTINCT_KEYS ------------------------------ --------------------------- ---------- ----------- ------------- I_T_ID1 NORMAL 2 1999 1000000 I_T_ID2DESC FUNCTION-BASED NORMAL 2 4283 1000000 --//I_T_ID2DESC的LEAF_BLOCKS=4283. 2.测试: SCOTT@book> select max(id1) from t; MAX(ID1) ---------- 1000000 SCOTT@book> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID 25ktx1ht4fs1u, child number 0 ------------------------------------- select max(id1) from t Plan hash value: 2049239052 -------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | -------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 3 (100)| | 1 |00:00:00.01 | 3 | | 1 | SORT AGGREGATE | | 1 | 1 | 5 | | | 1 |00:00:00.01 | 3 | | 2 | INDEX FULL SCAN (MIN/MAX)| I_T_ID1 | 1 | 1 | 5 | 3 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | -------------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / T@SEL$1 --//id1字段建立的是普通索引,取最大值仅仅3个逻辑读. SCOTT@book> select max(id2) from t; MAX(ID2) ---------- 1000000 SCOTT@book> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID gtagtkz33v9n8, child number 0 ------------------------------------- select max(id2) from t Plan hash value: 2966233522 --------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | --------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 2743 (100)| | 1 |00:00:00.22 | 9285 | | 1 | SORT AGGREGATE | | 1 | 1 | 5 | | | 1 |00:00:00.22 | 9285 | | 2 | TABLE ACCESS FULL| T | 1 | 1000K| 4882K| 2743 (1)| 00:00:33 | 1000K|00:00:00.13 | 9285 | --------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / T@SEL$1 --//执行计划走的是全表扫描.无法充分利用降序索引. SCOTT@book> alter table t modify (id2 not null); Table altered. SCOTT@book> select max(id2) from t; MAX(ID2) ---------- 1000000 SCOTT@book> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID 6pj15dkuv35kb, child number 0 ------------------------------------- select max(id2) from t Plan hash value: 2206409122 ------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 1166 (100)| | 1 |00:00:00.25 | 4362 | | 1 | SORT AGGREGATE | | 1 | 1 | 5 | | | 1 |00:00:00.25 | 4362 | | 2 | INDEX FAST FULL SCAN| I_T_ID2DESC | 1 | 1000K| 4882K| 1166 (1)| 00:00:14 | 1000K|00:00:00.11 | 4362 | ------------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / T@SEL$1 --//即使设置id2 not null,执行计划选择的也是INDEX FAST FULL SCAN,逻辑读依旧很高. --//几乎很少有人这么写: SCOTT@book> select id2 from (select id2 from t order by id2 desc) where rownum=1; ID2 ---------- 1000000 SCOTT@book> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID 8aska3nqm81p2, child number 0 ------------------------------------- select id2 from (select id2 from t order by id2 desc) where rownum=1 Plan hash value: 893305471 --------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | --------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 3 (100)| | 1 |00:00:00.01 | 3 | |* 1 | COUNT STOPKEY | | 1 | | | | | 1 |00:00:00.01 | 3 | | 2 | VIEW | | 1 | 1 | 13 | 3 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | | 3 | INDEX FULL SCAN| I_T_ID2DESC | 1 | 1000K| 4882K| 3 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | --------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$2 / from$_subquery$_001@SEL$1 3 - SEL$2 / T@SEL$2 Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM=1) 3.继续探究: --//如果执行如下,看执行计划可以发现: select * from t where id2=1 ; Predicate Information (identified by operation id): --------------------------------------------------- 2 - access(SYS_OP_DESCEND("ID2")=HEXTORAW('3EFDFF') ) filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("ID2"))=1) --//但是如果你执行如下: SCOTT@book> select SYS_OP_UNDESCEND(SYS_OP_DESCEND("ID2")),id2 from t where rownum=1; SYS_OP_UNDESCEND(SYS_OP_DESCEND("ID2")) ID2 --------------------------------------- --- C20539 456 --//利用这样的也可以获得对应编码.但是SYS_OP_UNDESCEND(SYS_OP_DESCEND("ID2"))不会等于id2. SCOTT@book> select SYS_OP_UNDESCEND(SYS_OP_DESCEND(1)),1 from dual; SYS_ 1 ---- ---------- C102 1 --//为什么oracle执行中filter可以(SYS_OP_UNDESCEND(SYS_OP_DESCEND("ID2"))=1)?有点搞不懂.... --//而实际上返回的是对应数字的oracle编码. SCOTT@book> select utl_raw.cast_to_number(x) from (select (SYS_OP_UNDESCEND(min(SYS_OP_DESCEND(ID2)))) x from t); UTL_RAW.CAST_TO_NUMBER(X) ------------------------- 1000000 --//注意是取最小值.开发更不可能这样写!! SCOTT@book> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID 3vk18a82yxt7y, child number 0 ------------------------------------- select utl_raw.cast_to_number(x) from (select (SYS_OP_UNDESCEND(min(SYS_OP_DESCEND(ID2)))) x from t) Plan hash value: 2062024120 ------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 3 (100)| | 1 |00:00:00.01 | 3 | | 1 | VIEW | | 1 | 1 | 19 | 3 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | | 2 | SORT AGGREGATE | | 1 | 1 | 6 | | | 1 |00:00:00.01 | 3 | | 3 | INDEX FULL SCAN (MIN/MAX)| I_T_ID2DESC | 1 | 1 | 6 | 3 (0)| 00:00:01 | 1 |00:00:00.01 | 3 | ------------------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$2 / from$_subquery$_001@SEL$1 2 - SEL$2 3 - SEL$2 / T@SEL$2 --//补充一点如果这些写: SCOTT@book> select utl_raw.cast_to_number(SYS_OP_UNDESCEND(min(SYS_OP_DESCEND(ID2)))) from t; UTL_RAW.CAST_TO_NUMBER(SYS_OP_UNDESCEND(MIN(SYS_OP_DESCEND(ID2)))) ------------------------------------------------------------------ 1000000 SCOTT@book> @ dpc '' '' PLAN_TABLE_OUTPUT ------------------------------------- SQL_ID 9bd7fdyvd2sh6, child number 0 ------------------------------------- select utl_raw.cast_to_number(SYS_OP_UNDESCEND(min(SYS_OP_DESCEND(ID2))) ) from t Plan hash value: 2206409122 ------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 1166 (100)| | 1 |00:00:00.22 | 4362 | | 1 | SORT AGGREGATE | | 1 | 1 | 6 | | | 1 |00:00:00.22 | 4362 | | 2 | INDEX FAST FULL SCAN| I_T_ID2DESC | 1 | 1000K| 5859K| 1166 (1)| 00:00:14 | 1000K|00:00:00.12 | 4362 | ------------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / T@SEL$1 21 rows selected. --//这样写oracle无法充分利用取min/max的特性.不知道为什么,那位解析看看. 4.总结: --//1.降序索引不能乱用. --//2.降序索引适应的场景很少,仅仅oraer by a desc,b asc之类的一正一反可以使用.我仅仅能找到这个例子. --//3.降序索引对于自增序列字段会导致索引变大的可能. --//4.总之不要张冠李戴不加思索的乱用任何技术,再次看到一个豆腐渣中豆腐渣工程.
[20191219]降序索引与取最大值.txt
来源:这里教程网
时间:2026-03-03 14:43:46
作者:
编辑推荐:
- [20191219]降序索引与取最大值.txt03-03
- 2011-11-28 取单行数据03-03
- [20191219]oracle timestamp数据类型的存储.txt03-03
- Oracle数据访问组件ODAC的安装方法03-03
- 2011-11-29 11G新功能:PL/SCOPE03-03
- [20191220]格式化执行计划.txt03-03
- 2011-11-30 一致读03-03
- 禁用sql tuning advisor功能03-03
下一篇:
相关推荐
-
雷神推出 MIX PRO II 迷你主机:基于 Ultra 200H,玻璃上盖 + ARGB 灯效
2 月 9 日消息,雷神 (THUNDEROBOT) 现已宣布推出基于英
-
制造商 Musnap 推出彩色墨水屏电纸书 Ocean C:支持手写笔、第三方安卓应用
2 月 10 日消息,制造商 Musnap 现已在海外推出一款 Oce
热文推荐
- 北京活动预告丨来ACOUG 年会过个温暖的冬天吧!
北京活动预告丨来ACOUG 年会过个温暖的冬天吧!
26-03-03 - RAC环境单节点启动数据库报ORA-29702
RAC环境单节点启动数据库报ORA-29702
26-03-03 - Oracle 19c和20c新特性最全解密
Oracle 19c和20c新特性最全解密
26-03-03 - 手机APP为什么要获取这3个权限?能不能随意授权呢?看完就知道了
手机APP为什么要获取这3个权限?能不能随意授权呢?看完就知道了
26-03-03 - Serverless 实战 —— 函数计算 + Typescript 实践
- 分布式事务 GTS 的价值和原理浅析
分布式事务 GTS 的价值和原理浅析
26-03-03 - 从零开始入门 | Kubernetes 中的服务发现与负载均衡
从零开始入门 | Kubernetes 中的服务发现与负载均衡
26-03-03 - 原来华为手机不亮屏也能看时间,点击这个按钮,30秒即可开启
原来华为手机不亮屏也能看时间,点击这个按钮,30秒即可开启
26-03-03 - 阿里云视频云正式支持AV1编码格式 为视频编码服务降本提效
阿里云视频云正式支持AV1编码格式 为视频编码服务降本提效
26-03-03 - 等保2.0正式实施,阿里云发布全国首个《阿里公共云用户等保2.0合规能力白皮书》
