[20191219]降序索引與取最大值.txt
[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.總之不要張冠李戴不加思索的亂用任何技術,再次看到一個豆腐渣中豆腐渣工程.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/267265/viewspace-2669477/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [20231116]降序索引取最大值.txt索引
- [20191209]降序索引疑問.txt索引
- [20191219]索引名裡帶回車符.txt索引
- [20191209]降序索引疑問2.txt索引
- [20200303]降序索引疑問5.txt索引
- [20191210]降序索引疑問3.txt索引
- [20191218]降序索引疑問4.txt索引
- [20181123]關於降序索引問題.txt索引
- [20190910]關於降序索引問題5.txt索引
- [20181124]關於降序索引問題4.txt索引
- [20181124]關於降序索引問題3.txt索引
- [20181124]關於降序索引問題2.txt索引
- [20191219]shared_pool_size設定躍變.txt
- [20191219]oracle timestamp資料型別的儲存.txtOracle資料型別
- [20210604]索引分裂與 itl ktbitflg.txt索引
- 不能建立降序索引的問題的解決索引
- [20190827]函式索引與選擇率.txt函式索引
- [20241012]cursor_sharing=force與函式索引.txt函式索引
- [20190527]注意表與索引的並行屬性.txt索引並行
- mongodb 取欄位最大值MongoDB
- [20201007]exadata儲存索引.txt索引
- [20180926]查詢相似索引.txt索引
- JavaScript 獲取陣列中最大值JavaScript陣列
- [20201110]oracle建立索引nosrt.txtOracle索引
- [20211231]函式索引測試.txt函式索引
- [20210603]如何跟蹤索引分裂.txt索引
- [20180509]函式索引問題.txt函式索引
- [20180503]檢視提示使用索引.txt索引
- [20211105]索引分裂塊清除日誌增加(唯一索引).txt索引
- [20220331]為什麼不使用索引.txt索引
- [20201203]為什麼不使用索引.txt索引
- [20181020]lob欄位的索引段.txt索引
- python小技巧:獲取列表最大值以及位置Python
- [20211108]索引分裂塊清除日誌增加(唯一索引)2.txt索引
- [20210220]全索引掃描快速索引掃描的邏輯讀.txt索引
- [20231024]NULL值在索引的情況.txtNull索引
- [20221010]使用toad管理索引改名問題.txt索引
- [20211105]索引分裂 塊清除 日誌增加.txt索引