https://blog.csdn.net/biww620/article/details/73003880java
目錄是索引的一個最好的例子,每條目錄包含對應章節的標題和頁碼,類比索引的每條索引項包含了數據記錄的某些鍵值組合幷包含了對應數據塊的訪問路徑(rowid)。目錄的存在就是爲了快速定位到感興趣的內容,索引的存在也是問了加快對錶數據的隨機訪問。sql
經常被說起的索引可能有單鍵索引、組合索引、惟一索引、B-Tree索引、位圖索引、函數索引、全局索引、局部索引等等。這裏只是列舉出鏡率較高的索引類型,並無去作嚴格的劃分,各種型間有重疊,好比函數索引能夠是B-Tree索引也能夠是位圖索引。在Oracle中索引和表同樣屬於邏輯結構中的段(segment)。每一個索引都擁有獨立的結構,不管是從物理結構仍是邏輯結構來看與其所關聯的表徹底分開,即使索引失效也不會形成原有SQL沒法執行,只是改變了執行計劃,下降了執行效率。數據庫
B-Tree索引
查找樹有徹底二叉樹、二叉查找樹、平衡二叉樹、紅黑樹,B-Tree,B+-Tree,B*-Tree等。對於二叉樹其目的是要將查詢複雜度控制在O(lgN)之內。(注:這裏的lgN表示log2N),查詢效率與樹的高度有關。在少許數據構造的二叉樹查詢是很高效的,可是在數據庫應用中,數據量巨大,若是構造二叉樹那麼樹的高度將也很巨大,勢必增長讀取索引節點的I/O次數,影響查詢效率。因而B-Tree自告奮勇,在很大的數據量範圍內可以保持B-Tree樹的層級不會增長。網絡
圖片來自網絡函數
從上圖中能夠看出在oraccle中B-Tree索引具備如下結構特色:
B-Tree索引包含根節點(Root Node)、分支節點(Branch Node)和葉子節點(Leaf Node)。
索引樹高度通常都很低,上百億記錄的索引樹的高度也只有5,6層。
索引自己有序。葉子節點是一個雙向鏈表,所以能夠按照索引的升序或降序進行索引掃描。
索引項包含鍵值信息和ROWID。索引項由索引頭部、索引列的長度、索引值以及對應記錄的rowid。其中惟一索引對應的rowid是惟一的,非惟一索引對應的rowid是可能有多個(多個rowid是有序的)。
索引列值所有爲NULL的索引項是不會被記錄的。
B-Tree索引簡要分析
1、提升查詢效率
200w條記錄的表test_index_t1,查找條件col1 = 98765的記錄沒有索引的執行計劃以下:性能
在test_index_t1表的col1列添加索引
create index index_col1 on test_index_t1(col1);
再次執行查詢的執行計劃以下:大數據
未創建索引時執行計劃是TABLE ACCESS FULL用時1100ms,創建索引後執行計劃是INDEX RANGE SCAN用時90ms,效率提升了10倍以上。這裏test_index_t1的數據量不大。若是是大數據量的表執行效率的差距會更加明顯。
2、索引樹高度較低
經過如下sql能夠查詢索引的統計信息,其中BLEVEL表示索引樹的高度,高度爲BLEVEL + 1
SELECT
index_name,
blevel,
leaf_blocks,
num_rows,
distinct_keys,
clustering_factor
FROM
user_ind_statistics
WHERE
table_name = UPPER('test_index_t1');.net
對於200w條記錄的表test_index_t1執行索引統計信息查詢後獲得的結果爲:blog
能夠看出BLEVEL = 2也就是說索引樹的高度爲3。構建了記錄數分別爲10條,20w條和300w條的表並創建相同的索引,索引樹高度分別爲2,2,3。所以能夠看出B-Tree索引的高度是比較低的,可以在大數據量的狀況下保證樹高度值很低。在經過索引執行查詢時一個層級每每就表明一次I/O操做,所以保持索引樹高度較低對查詢性能有很大的好處。
3、索引包含鍵值
索引包含索引鍵值,單鍵或鍵組合,若是查詢所需的字段均在索引項中則能夠避免回表讀數,提升查詢性能。建立表test_index_t1包含三個字段col1,col2,col3初始化爲300w條記錄,並創建了(col1,col2)組合索引。
create index index_col1_col2 on test_index_t1(col1, col2);
1. 執行sql
select col1 from test_index_t1 where col1 between 10 and 20;排序
2. 執行sql
select col1, col2 from test_index_t1 where col1 between 10 and 20;
3. 執行sql
select * from test_index_t1 where col1 between 10 and 20;
從上面三次查詢結果能夠看出:
(1) 三次執行SQL均用到了索引INDEX_COL1_COL2,索引執行方式爲Index Range Scan
(2) 第一次和第二次查詢(col1)、(col一、col2)均未回表讀數,而第三次查詢存在TABLE ACCESS BY INDEX ROWID回表讀數,緣由是組合索引INDEX_COL1_COL2中不包含列col3,所以經過索引掃描獲得最終記錄的rowid後還會根據rowid到表中讀取col3。
整體來看,若是所需列包含於索引中那麼能夠經過索引避免回表讀數從而提升查詢性能。但須要注意的是索引自己也有性能消耗,並非包含的列越多越好。通常建議索引列不超過3個,從實際的經驗來看5,6個也仍是能夠接受。
4、索引自己有序
在前面提到的索引結構中能夠看出索引葉子結點自己是按照索引鍵升序排列,至關於一個雙向鏈表,能夠進行升序或降序掃描。刪除test_index_t1表的索引,再執行查詢
select col1, col2 from test_index_t1 where col1 between 10 and 20 order by col1;
從執行計劃和統計信息中能夠看出執行了排序過程並使用了內存空間。給test_index_t1表col1字段加上索引後的執行計劃以下
執行計劃走索引後SORT ORDER BY不存在了。所以,若是由於排序致使查詢性能下降能夠考慮在索引中包含須要排序的列,這樣利用索引自己的有序性能夠避免排序帶來的性能損耗。
5、索引不保存索引鍵值所有爲NULL的記錄
這個特色跟count,sum/avg,max/min的執行計劃息息相關,能夠總結爲如下兩點:
COUNT/SUM/AVG必須在索引列爲非空的狀況下才能夠走到索引。(建表是列指定爲Not Null或爲主鍵或在where條件中指明爲is not null)。
MIN/MAX則不會受到空值的影響,均能走到索引。
表test_index_t1有300w條記錄,在col1上創建了索引,執行:
select count(1) from test_index_t1;
能夠看出是走了全表掃描。在where條件中增長col1 is not null後的執行計劃爲:
用INDEX FAST FULL SCAN的方式使用索引INDEX_COL1。最後col1添加屬性not null後的執行計劃爲:
能夠看出給列col1添加了not null屬性後執行計劃跟在where條件中指明is not null相同。這裏再也不對sum/avg,min/max作驗證。————————————————版權聲明:本文爲CSDN博主「biww620」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/biww620/java/article/details/73003880