利用B*TREE的特性,為列值分佈極端不平衡的表建立特殊索引來提高效率
首先來看看錶結構,簡化後如下:
ID NUMBER(10) Y
COMMITDATE DATE Y
STATUS NUMBER(1) Y
其中ID是主鍵,唯一的標明瞭一個訂單,COMMITDATE表示訂單的提交時間,STATUS表示訂單的處理狀態,其中0表示未處理,1表示已處理。當然此表還有很多列來描述一筆訂單,這裡只是簡化的結構。此表當初建立了tab_order(commitdate desc,status)的索引。那麼查詢最早提交併且未處理的sql的實現如下:
SELECT *
FROM (SELECT A.*, ROWNUM RW
FROM (SELECT *
FROM TAB_ORDER
WHERE STATUS = 0
ORDER BY COMMITDATE DESC) A)
WHERE RW = 1;
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 460 | 22080 | 49 (0)| 00:00:01 |
|* 1 | VIEW | | 460 | 22080 | 49 (0)| 00:00:01 |
| 2 | COUNT | | | | | |
| 3 | VIEW | | 460 | 16100 | 49 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| TAB_ORDER | 460 | 16100 | 49 (0)| 00:00:01 |
|* 5 | INDEX FULL SCAN | IDX_ORDER | 435 | | 49 (3)| 00:00:01 |
--------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
325 consistent gets
0 physical reads
0 redo size
716 bytes sent via SQL*Net to client
469 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
可以看到,首先是對索引進行全掃描,然後得到表中的資料,再進行過濾,得到時間最早的一行。因為前面建立的是基於COMMITDATE的倒序索引,所以把排序的過程省略了。但是當資料量很大的時候,全掃描這個索引的cost也是很大的,而且業務規定不能限定COMMITDATE時間,那麼因為可能由於某種原因導致的很早的訂單一直沒有得到處理。那麼這樣的環境肯定會導致資料越來越多,速度越來越慢。
改進方案:
考慮到系統中99%以上的訂單都是已經處理掉的,而未處理的訂單永遠是少數,因此可以利用B*TREE中不會包含NULL值的特性,只為status為0的建立索引,這樣索引的大小就永遠和status為0的記錄數相關,只要未處理的訂單不會很多,這個索引就永遠會很小,那麼效率就不會隨著資料的增長而下降。建立索引如下:
create index idx_order on tab_order(decode(status,0,0,null));
改寫sql如下以便讓執行計劃走索引:
SELECT *
FROM (SELECT A.*, ROWNUM RW
FROM (SELECT *
FROM TAB_ORDER
WHERE DECODE(STATUS, 0, 0, NULL) = 0
ORDER BY COMMITDATE DESC) A)
WHERE RW = 1;
執行計劃如下:
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 460 | 22080 | 2 (50)| 00:00:01 |
|* 1 | VIEW | | 460 | 22080 | 2 (50)| 00:00:01 |
| 2 | COUNT | | | | | |
| 3 | VIEW | | 460 | 16100 | 2 (50)| 00:00:01 |
| 4 | SORT ORDER BY | | 460 | 16100 | 2 (50)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| TAB_ORDER | 460 | 16100 | 1 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_ORDER | 435 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
716 bytes sent via SQL*Net to client
469 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed
經過對比可以發現,consistent gets已經大大的下降,程式效率得到提升,最關鍵的問題是,程式的效率不會隨著資料量的增加而下降。
總結:當表中某些列的資料分佈極端不平衡,而符合查詢條件的返回結果又相當少的時候,可以透過DECODE函式轉換和利用B*TREE不儲存NULL值的特性,使得需要使用的索引很小,而且索引大小不隨資料量的變大而變大,從而提高了程式效率。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25373498/viewspace-719648/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL的B-tree索引SQL索引
- MySQL Hash索引和B-Tree索引的區別MySql索引
- 表為多列為null的表之索引示例Null索引
- oracle的B-tree索引結構分析Oracle索引
- 轉儲B*Tree索引的分枝結構索引
- [轉]:bitmap索引和B*tree索引分析索引
- 極端類別不平衡資料下的分類問題研究綜述
- 【索引】Bitmap點陣圖索引與普通的B-Tree索引鎖的比較索引
- MySQL探索(一):B-Tree索引MySql索引
- 平衡樹索引(b-tree index)索引Index
- 索引特性之儲存列值及ROWID索引
- 如何轉儲B*Tree索引的分枝結構(轉)索引
- 【Java面試】Mysql為什麼使用B+Tree作為索引結構Java面試MySql索引
- 不平衡的索引?Unbalanced Indexes索引Index
- MySQL 效能優化——B+Tree 索引MySql優化索引
- 關於B*tree索引(index)的中度理解及bitmap 索引的一點探究(zt)索引Index
- 跳過索引某些列任然使用索引的特性索引
- B-tree和B+tree 一種為資料查詢而生的結構
- B-Tree索引與Bitmap點陣圖索引的鎖代價比較研究索引
- Oracle 找出需要建立索引的表Oracle索引
- Oracle如何建立B樹索引Oracle索引
- 如何讓table表的null列由不走索引變為可走索引Null索引
- 【陣列】1608. 特殊陣列的特徵值(簡單)陣列特徵
- MySQL建立表的時候建立聯合索引的方法MySql索引
- 【Bitmap Index】B-Tree索引與Bitmap點陣圖索引的鎖代價比較研究Index索引
- MySQL的索引為什麼用B+Tree?InnoDB的資料儲存檔案和MyISAM的有何不同?MySql索引
- 在不清楚資料表欄位資料分佈的情況下,應該建立什麼型別的索引?型別索引
- 11g分佈表新特性——Interval分割槽(上)
- 11g分佈表新特性——Interval分割槽(下)
- 【MySQL(1)| B-tree和B+tree】MySql
- 利用ORACLE_DATAPUMP為驅動建立外部表Oracle
- 研究 b-tree 索引結構的指令碼 (文件 ID 1577374.1)索引指令碼
- oracle查詢表資訊(索引,外來鍵,列等)Oracle索引
- PG 12-2 B-Tree 索引 分析 分裂 level = 1索引
- Oracle 對某列的部分資料建立索引Oracle索引
- MySQL的B+Tree索引到底是咋回事?聚簇索引到底是如何長高的?MySql索引
- OCM實驗-建立含特殊欄位型別的表型別
- 多路查詢樹:B-tree/b+tree