ORACLE索引概述

linfeng_oracle發表於2014-06-04

                                                                                                        ORACLE索引概述

 
索引是資料庫中一種可選的資料結構,她通常與表或簇相關。使用者可以在表的一列或數列上建立索引,以提高在此表上執行 SQL 語句的效能。就像本文件的索引可以幫助讀者快速定位所需資訊一樣,Oracle 的索引提供了更為迅速地訪問表資料的方式。正確地使用索引能夠顯著的減少磁碟 I/O。

 

        使用者可以為一個表建立多個索引,只要不同索引使用的列或列的組合(combination of columns)不同即可。例如,下列語句中指定的列組合是有效的:

        CREATE INDEX employees_idx1 ON employees (last_name, job_id);

 

        CREATE INDEX employees_idx2 ON employees (job_id, last_name);

 

Oracle 提供了各種型別的索引,她們能夠互為補充地提升查詢效能:

 

平衡樹索引(B-tree index)

平衡樹簇索引(B-tree cluster index)

雜湊簇索引(hash cluster index)

反向鍵索引(reverse key indexes)

點陣圖索引(bitmap index)

點陣圖連線索引(bitmap join index)

        Oracle 還支援函式索引(function-based index),以及針對特定應用程式或程式模組(cartridge)的域索引(domain index)。

 

        無論索引是否存在都無需對已有的 SQL 語句進行修改。索引只是提供了一種快速訪問資料的路徑,因此她只會影響查詢的執行速度。當給出一個已經被索引的資料值後,就可以通過索引直接地定位到包含此值的所有資料行。

 

        索引在邏輯上和物理上都與其基表(base table)是相互獨立的。使用者可以隨時建立(create)或移除(drop)一個索引,而不會影響其基表或基表上的其他索引。當使用者移除一個索引時,所有的應用程式仍然能夠繼續工作,但是資料訪問速度有可能會降低。作為一種獨立的資料結構,索引需要佔用儲存空間。

 

        當索引被建立後,對其的維護與使用都是 Oracle 自動完成的。當索引所依賴的資料發生插入,更新,刪除等操作時,Oracle 會自動地將這些資料變化反映到相關的索引中,無需使用者的額外操作。

 

        即便索引的基表中插入新的資料,對被索引資料的查詢效能基本上能夠保持穩定不變。但是,如果在一個表上建立了過多的索引,將降低其插入,更新,及刪除的效能。因為 Oracle 必須同時修改與此表相關的索引資訊。

 

        優化器可以使用已有的索引來建立(build)新的索引。這將加快新索引的建立速度。

 

5.8.1 唯一索引和非唯一索引

         索引(index)可以是唯一(unique)的或非唯一(nonunique)的。在一個表上建立唯一索引(unique index)能夠保證此表的索引列(一列或多列)不存在重複值。而非唯一索引(nonunique index)並不對索引列值進行這樣的限制。

        Oracle 建議使用 CREATE UNIQUE INDEX 語句顯式地建立唯一索引(unique index)。通過主鍵(primary key)或唯一約束(unique constraint)來建立唯一索引不能保證建立新的索引,而且用這些方式建立的索引不能保證為唯一索引。
                                                                                                                                                                                 

 

5.8.2 複合索引

         複合索引(composite index)(也被稱為連結索引(concatenated index))是指建立在一個表的多列上的索引。複合索引內的列可以任意排列,她們在資料表中也無需相鄰。

 

        如果一個 SELECT 語句的 WHERE 子句中引用了複合索引(composite index)的全部列(all of the column)或自首列開始且連續的部分列(leading portion of the column),將有助於提高此查詢的效能。因此,索引定義中列的順序是很重要的。大體上說,經常訪問的列(most commonly accessed)或選擇性較大的列(most selective)應該放在前面。

 

        一個常規的(regular)複合索引(composite index)不能超過 32 列,而點陣圖索引(bitmap index)不能超過 30 列。索引中一個鍵值(key value)的總長度大致上不應超過一個資料塊(data block)總可用空間的一半。                                  

 

5.8.3 索引和鍵

        索引(index)與鍵(key)是連個不同的概念,但是這兩個術語經常被混用。索引是在資料庫中實際儲存的資料結構,使用者可以使用 SQL 語句對其進行建立(create),修改(alter),或移除(drop)。索引提供了一種快速訪問表資料的途徑。而鍵只是一個邏輯概念。鍵的概念主要在 Oracle 的完整性約束(integrity constraint)功能中使用,完整性約束用於保證資料庫中的業務規則(business rule)。

 

        因為 Oracle 也會使用索引(index)來實現某些完整性約束(integrity constraint),因此索引與鍵(key)這兩個術語經常被混用。注意不要將二者混淆。

                                 

 

5.8.4 索引和空值

        對於一個資料表的兩行或多行,如果其索引列(key column)中全部非空(non-NULL)的值完全相同(identical),那麼在索引中這些行將被認為是相同的;反之,在索引中這些行將被認為是不同的。因此使用 UNIQUE 索引可以避免將包含 NULL 的行視為相同的。以上討論並不包括索引列的列值(column value)全部為 NULL 的情況。

 

        Oracle 不會將索引列(key column)全部為 NULL 的資料行加入到索引中。不過點陣圖索引(bitmap index)是個例外,簇鍵(cluster key)的列值(column value)全部為 NULL 時也是例外。

 

                                                                                                                                                                                        

 

5.8.5 函式索引

        如果一個函式(function)或表示式(expression)使用了一個表的一列或多列,則使用者可以依據這些函式或表示式為表建立索引,這樣的索引被稱為函式索引(Function-Based Index)。函式索引能夠計算出函式或表示式的值,並將其儲存在索引中。使用者建立的函式索引既可以是平衡樹型別(B-tree index)的,也可以是點陣圖型別(bitmap index)的。

 

        用於建立索引的函式可以是一個數學表示式(arithmetic expression),也可以是使用了 PL/SQL 函式(PL/SQL function),包函式(package function),C 外部呼叫(C callout),或 SQL 函式(SQL function)的表示式。用於建立索引的函式不能包含任何聚合函式(ggregate function),如果為使用者自定義函式,則在宣告中必須使用 DETERMINISTIC關鍵字。如果在一個使用物件型別(object type)的列上建立函式索引,則可以使用此物件的方法(method)作為函式,例如此物件的 map 方法。使用者不能在資料型別為 LOB,REF,或巢狀表(nested table)的列上建立函式索引,也不能在包含 LOB,REF,或巢狀表等資料型別的物件型別列上建立函式索引。

 

5.8.5.1 使用函式索引

 

        如果一個 SQL 語句的 WHERE 子句中使用了函式,那麼建立相應的函式索引(function-based index)是提高資料訪問效能的有效機制。表示式(expression)的結果經過計算後將被儲存在索引中。但是當執行 INSERT 和 UPDATE 語句時,Oracle 需要進行函式運算以便維護索引。

 

        例如,如果使用者建立了以下函式索引:

 

        CREATE INDEX idx ON table_1 (a + b * (c – 1), a, b);

 

        當 Oracle 處理如下查詢時就可以使用之前建立的索引:

 

        SELECT a FROM table_1 WHERE a + b * (c – 1) < 100;

 

        使用 UPPER(column_name) 或 LOWER(column_name) 函式建立函式索引(function-based index)有助於與大小寫無關(case-insensitive)的查詢。例如建立以下函式索引:

 

        CREATE INDEX uppercase_idx ON employees (UPPER(first_name));

 

        有助於提高以下查詢的效能:

 

        SELECT * FROM employees WHERE UPPER(first_name) = ‘RICHARD’;

 

5.8.5.2 函式索引的優化

 

        使用者必須為優化器(optimizer)收集關於函式索引(unction-based index)的統計資訊(statistic)。否則處理 SQL 語句時將不會使用此索引。

 

        當一個查詢的 WHERE 子句中含有表示式(expression)時,優化器可以對函式索引(function-based index)進行索引區間掃描(index range scan)。例如以下查詢:

 

        SELECT * FROM t WHERE a + b < 10;

 

        如果使用表示式(expression) a+b 建立的索引,優化器(optimizer)就能夠進行索引區間掃描(index range scan)。如果謂詞(predicate,即 WHERE 子句)產生的選擇性(selectivity)較低,則對區間掃描極為有利。此外,如果表示式的結果物化在函式索引內(function-based index),優化器將能更準確地估計使用此表示式的謂詞的選擇性。

 

        優化器(optimizer)能夠將 SQL 語句及函式索引(function-based index)中的表示式解析為表示式樹(expression tree)並進行比較,從而實現表示式匹配。這個比較過程是大小寫無關的(case-insensitive),並將忽略所有空格(blank space)。

 

5.8.5.3 函式索引的依賴性

 

        函式索引(function-based index)依賴於索引定義表示式中使用的函式。如果此函式為 PL/SQL 函式(PL/SQL function)或包函式(package function),當函式宣告(function specification)發生變化時,索引將失效(disabled)。

 

        使用者需要被授予(grant)CREATE INDEX 或 CREATE ANY INDEX 許可權才能建立函式索引(function-based index)。

 

        要想使用函式索引(function-based index):

 

建立索引後,表必須經過分析(analyze)。

必須保證查詢的條件表示式不是 NULL 值, 因為 NULL 值不會被儲存到索引中。

        以下各節將講述使用函式索引的其他需求。

 

5.8.5.3.1 DETERMINISTIC 函式

 

        函式索引(function-based index)使用的使用者自定義函式(user-written function)必須宣告為 DETERMINISTIC,此關鍵字表明對於一定的輸入引數,此函式總會得到相同的輸出結果。

 

5.8.5.3.2 定義函式的許可權

 

        函式索引(function-based index)的所有者(owner)必須具備此索引定義中使用的函式的EXECUTE 許可權。當 EXECUTE 許可權被收回(revoke)後,Oracle 則將索引標識為 DISABLED。索引的所有者無須具備此函式的 EXECUTE WITH GRANT OPTION 許可權,即可將索引所在表的SELECT 許可權授予(grant)其他使用者。

 

5.8.5.3.3 解決函式索引的依賴性問題

 

        函式索引(function-based index)依賴於她使用的所有函式。如果函式或函式所在包的宣告(specification)被修改過(或索引所有者對函式的 EXECUTE 許可權被收回),將會出現以下情況:

 

索引被標記為 DISABLED。

如果優化器(optimizer)選擇了在標記為 DISABLED 的索引上執行查詢,那麼此查詢將失敗

使用標記為 DISABLED 的索引而執行的 DML 操作將失敗,除非此索引同時被標記為UNUSABLE 且初始化引數(initialization parameter) SKIP_UNUSABLE_INDEXES 被設為TRUE。

        函式被修改之後,使用者可以使用 ALTER INDEX … ENABLE 語句將索引重新置為 ENABLE 狀態。

 

                                                                                                                                                                                        

 

5.8.6 索引是如何儲存的

        當使用者建立索引時,Oracle 會自動地在表空間(tablespace)中建立索引段(index segment)來儲存索引的資料。使用者可以通過以下方式控制索引段的空間分配和使用:

 

設定索引段的儲存引數(storage parameter)來控制如何為此索引段分配資料擴充套件(extent)

為索引段設定 PCTFREE 引數,來控制組成資料擴充套件的各個資料塊(data block)的可用空間情況。

        索引段(index segment)使用的表空間(tablespace)既可以是索引所有者(owner)的預設表空間,也可以是在 CREATE INDEX 語句中指定的表空間。索引無需和其相關的表位於同一表空間中。相反,如果將索引與其相關表儲存在不同磁碟上能夠提升使用此索引的查詢效能,因為此時 Oracle 能夠並行地(parallel)訪問索引及表資料。

 

5.8.6.1 索引塊的格式

 

        一個資料塊(data block)內可用於儲存索引資料的空間等於資料塊容量減去資料塊管理開銷(overhead),索引條目管理開銷(entry overhead),rowid,及記錄每個索引值長度的 1 位元組(byte)。

 

        當使用者建立索引時,Oracle 取得所有被索引列的資料並進行排序,之後將排序後索引值和與此值相對應的 rowid 按照從下到上的順序載入到索引中。例如,以下語句:

 

        CREATE INDEX employees_last_name ON employees(last_name);

 

        Oracle 先將 employees 表按 last_name 列排序,再將排序後的  列及相應的 rowid 按從下到上的順序載入到索引中。使用此索引時,Oracle 可以快速地搜尋已排序的 last_name 值,並使用相應的 rowid 去定位包含使用者所查詢的 last_name 值的資料行。

 

5.8.6.2 索引的內部結構

 

        Oracle 使用平衡樹(B-tree)儲存索引以便提升資料訪問速度。當不使用索引時,使用者必須對資料進行順序掃描(sequential scan)來查詢指定的值。如果有 n 行資料,那麼平均需要掃描的行為 n/2。因此當資料量增長時,這種方法的開銷將顯著增長。

 

        如果將一個已排序的值列(list of the values)劃分為多個區間(range),每個區間的末尾包含指向下個區間的指標(pointer),而搜尋樹(search tree)中則儲存指向每個區間的指標。此時在 n 行資料中查詢一個值所需的時間為 log(n)。這就是 Oracle 索引的基本原理。

 

        在一個平衡樹索引(B-tree index)中,最底層的索引塊(葉塊(leaf block))儲存了被索引的資料值,以及對應的 rowid。葉塊之間以雙向連結串列的形式相互連線。位於葉塊之上的索引塊被稱為分支塊(branch block),分枝塊中包含了指向下層索引塊的指標。如果被索引的列儲存的是字元資料(character data),那麼索引值為這些字元資料在當前資料庫字符集(database character set)中的二進位制值(binary value)。

 

        對於唯一索引(unique index),每個索引值對應著唯一的一個 rowid。對於非唯一索引(nonunique index),每個索引值對應著多個已排序的 rowid。因此在非唯一索引中,索引資料是按照索引鍵(index key)及 rowid 共同排序的。鍵值(key value)全部為 NULL 的行不會被索引,只有簇索引(cluster index)例外。在資料表中,如果兩個資料行的全部鍵值都為 NULL,也不會與唯一索引相沖突。

 

5.8.6.3 索引的屬性

 

        有兩種型別的索引塊:

 

用於搜尋的分支塊(branch block)

用於儲存索引資料的葉塊(leaf block)

5.8.6.3.1 分支塊

 

        分支塊(branch block)中儲存以下資訊:

 

最小的鍵值字首(minimum key prefix),用於在(本塊的)兩個鍵值之間做出分支選擇

指向包含所查詢鍵值的子塊(child block)的指標()

        包含 n 個鍵值的分支塊(branch block)含有 n+1 個指標。鍵值及指標的數量同時還受索引塊(index block)容量的限制。

 

5.8.6.3.2 葉塊

 

        所有葉塊(leaf block)相對於其根分支塊(root branch block)的深度(depth)是相同的。葉塊用於儲存以下資訊:

 

資料行的鍵值(key value)

鍵值對應資料行的 ROWID

所有的 鍵值-ROWID 對(key and ROWID pair)都與其左右的兄弟節點(sibling)向連結(link),並按照(key,ROWID)的順序排序。

5.8.6.4 平衡樹結構的優勢

 

        平衡樹資料結構(B-tree structure)具有以下優勢:

 

平衡樹(B-tree)內所有葉塊(leaf block)的深度相同,因此獲取索引內任何位置的資料所需的時間大致相同。

平衡樹索引(B-tree index)能夠自動保持平。

平衡樹內的所有塊容量平均在總容量的 3/4 左右。

在大區間(wide range)範圍內進行查詢時,無論匹配個別值(exact match)還是搜尋一個區間(range search),平衡樹都能提供較好的查詢效能。

資料插入(insert),更新(update),及刪除(delete)的效率較高,且易於維護鍵值的順序(key order)

大型表,小型表利用平衡樹進行搜尋的效率都較好,且搜尋效率不會因資料增長而降低。

                                                                                                                                                                                        

5.8.7 索引唯一掃描

        索引唯一掃描(index unique scan)是效率最高的資料訪問方式之一。從平衡樹索引(B-tree index)中獲取資料時將採用此種方式。當一個唯一索引(採用平衡樹結構)的全部列都包含在查詢條件中,且查詢體條件表示式均為等號(equality)時,優化器將選擇使用索引唯一掃描。

 

                                                                                                                                                                                        

 

5.8.8 索引區間掃描

        當訪問選擇性較大的資料(selective data)時 Oracle 常進行索引區間掃描(index range scan)。掃描區間可以是封閉的(bounded)(兩端均封閉),也可以是不封閉的(unbounded)(一端或兩端均不封閉)。掃描所返回的資料按照索引列的升序進行排列,對於索引值相同的行將按 ROWID 的升序排列。

 

                                                                                                                                                                                        

 

5.8.9 鍵壓縮

        使用者利用鍵壓縮(key compression)可以將索引或索引表(index-organized table)中鍵值(column value)的部分內容進行壓縮,以便減少重複值帶來的儲存開銷。

 

        一般來說,索引的一個鍵(key)通常由兩個片段(piece)構成:分組片段(grouping piece)及唯一片段(unique piece)。如果定義索引的鍵中不存在唯一片段,Oracle 會以 ROWID 的形式在此鍵的分組片段後新增一個唯一片段。鍵壓縮(key compression)就是將鍵的分組片段從鍵中拆分出來單獨儲存,供多個唯一片段使用。

 

5.8.9.1 索引鍵的字首和字尾

 

        鍵壓縮(key compression)將一個索引鍵拆分為字首(prefix entry)(即分組片段(grouping piece))和字尾(suffix entry)(即唯一片段(unique piece))。壓縮是通過一個索引塊(index block)中的多個字尾共享一個字首來實現的。在平衡樹索引(B-tree index)中只有位於葉塊(leaf block)的鍵會被壓縮。在分支塊(branch block)內不必儲存鍵的字尾,因此其中的鍵也無需壓縮。

 

        鍵壓縮(key compression)只能在每個索引塊(index block)內分別實現,而不能跨多個索引塊。壓縮後每個索引行(index row)只儲存字尾(suffix entry),而每個字尾將引用一個共享的字首(prefix entry),字尾與其共享的字首必須位於同一索引塊內。

 

        預設情況下,字首(prefix entry)由除去最後一列之外的其他鍵列(key column)構成。例如,一個索引鍵(index key)由(column1,column2,column3)3 列構成,則預設的字首為(column1, column2)。如一組索引值為(1,2,3),(1,2,4),(1,2,7),(1,3,5),(1,3,4),(1,4,4),則其中重複出現的字首 (1,2),(1,3) 將被壓縮。

 

        使用者也可以手工設定字首長度(prefix length),即字首所包含的列數。例如,如果使用者設定字首長度為 1,則在上述例子中,column1 為字首,(column2,column3)為字尾,其中重複出現的字首 1 將被壓縮。

 

        非唯一索引(nonunique index)的最大字首長度(prefix length)為鍵列的個數,而唯一索引(unique index)的最大字首長度為鍵列的個數減 1。

 

        應用鍵壓縮(key compression)後,生成索引時,如果一個鍵值(key value)的字首(prefix entry)在索引塊(index block)中不存在,此字首才會被寫入索引塊中。一個字首被寫入後立即就可以被此索引塊內的字尾(suffix entry)共享,直到所有引用此字首的字尾都被刪除為止。

 

5.8.9.2 效能上及儲存上的考慮

 

        鍵壓縮(key compression)能夠節約大量儲存空間,因此使用者可以在一個索引塊(index block)記憶體儲更多的索引鍵(index key),從而減少 I/O,提高效能。

 

        鍵壓縮(key compression)能夠減少索引所需的儲存空間,但索引掃描時需要重構(reconstruct)鍵值(key value),因此增加了 CPU 的負擔。此外來鍵壓縮也會帶來一些儲存開銷,每個字首(prefix entry)需要 4 位元組(byte)的管理開銷。

 

5.8.9.3 使用鍵壓縮

 

        鍵壓縮(key compression)在多種情況下都能夠發揮作用,例如:
 
 

對於非唯一索引(nonunique index),Oracle 會在每個重複的索引鍵(index key)之後新增 rowid 以便區分。如果使用了鍵壓縮,在一個索引塊(index block)內,Oracle 只需將重複的索引鍵作為字首((prefix entry))儲存一次,並用各行的 rowid 作為字尾(suffix entry)。

唯一索引(nonunique index)中也存在相同的情況。例如唯一索引(stock_ticker,transaction_time)的含義是(專案,時間戳),通常數千條記錄中stock_ticker 的值是相同的,但她們對應的 transaction_time 值各不相同。使用了鍵壓縮後,一個索引塊中每個 stock_ticker 值作為字首只需儲存一次,而各個transaction_time 值則作為字尾儲存,並引用一個共享的 stock_ticker 字首。

在一個包含 VARRAY 或 NESTED TABLE 資料型別(datatype)的索引表(index-organized table)中,這些collection 型別中各個元素(element)的物件識別符號(object identifier)是重複的。使用者可以使用鍵壓縮以避免重複儲存這些物件識別符號。

        有些情況無法使用鍵壓縮(key compression)。例如,一個只有一個索引鍵(index key)的唯一索引(unique index)就無法使用鍵壓縮,因為索引鍵中不存在可供共享的分組片段(grouping piece)。

 

                                                                                                                                                                                        

 

5.8.10 逆序鍵索引

        使用者可以建立逆序鍵索引(reverse key index),此處的逆序指索引列值(index key value)得各個位元組(byte)按倒序排列,而非索引列(index key)逆序排列。在 RAC 環境中,使用這樣的排列方式可以避免由於對索引的修改集中在一小部分葉塊(leaf block)上而造成的效能下降。通過使索引的鍵值逆序排列,可以使插入操作分佈在索引的全部葉塊中。

 

        使用逆序鍵索引(reverse key index)後將無法對此索引進行索引區間掃描(index range scanning),因為在逆序鍵索引 中,詞彙上(lexically)相鄰的索引鍵(index key)在儲存上未必相鄰。因此在逆序鍵索引 上只能進行確定鍵掃描(fetch-by-key scan)或全索引掃描(full-index scan)。

 

        有些情況下,使用逆序鍵索引(reverse key index)可以令 RAC 環境下的 OLTP 應用效率更高。例如,為一個 e-mail 應用中的所有郵件進行索引:由於使用者可能儲存舊的郵件,因此索引必須做到既能快速訪問最新郵件,也能快速訪問舊郵件。

 

        使用者使用 REVERSE 就可以輕易地建立逆序鍵索引(reverse key index)。在 CREATE INDEX語句中使用 REVERSE 關鍵字作為建立索引的選項:

 

        CREATE INDEX i ON t (a,b,c) REVERSE;

 

        使用者也可以在 REBUILD 子句後新增 NOREVERSE 關鍵字將一個逆序鍵索引(reverse key index)轉換為常規的索引:

 

        ALTER INDEX i REBUILD NOREVERSE;

 

        如果 REBUILD 子句後沒有使用 NOREVERSE 關鍵字,那麼逆序鍵索引(reverse key index)被重建後仍將保持逆序。

 

                                                                                                                                                                                         

 

5.8.11 點陣圖索引

        索引的目標是為使用者提供指向包含特定鍵值(key value)的資料行的指標。在常規的索引中,Oracle 將各行的鍵值及與此鍵值對應的一組 ROWID 儲存在一起,從而實現了上述目標。而在點陣圖索引(bitmap index)中,只需儲存每個鍵值的點陣圖(bitmap),而非一組 ROWID。

 

        點陣圖(bitmap)中的每一位(bit)對應一個可能的 ROWID。如果某一位被置位(set),則表明著與此位對應的 ROWID 所指向的行中 包含此位所代表的鍵值(key value)。Oracle 通過一個對映函式(mapping function)將位資訊轉化為實際的 ROWID,因此雖然點陣圖索引(bitmap index)內部的儲存結構與常規索引不同,但她同樣能實現常規索引的功能。當不同值的索引鍵的數量較少時,點陣圖索引的儲存效率相當高。

 

        如果在 WHERE 子句內引用的多個列上都建有點陣圖索引(bitmap index),那麼進行點陣圖索引掃描時(bitmap indexing)可以將各個點陣圖索引融合在一起。不滿足全部條件的行可以被預先過濾掉。因此使用點陣圖索引能夠極大地提高查詢的響應時間。

 

5.8.11.1 資料倉儲應用中點陣圖索引的優勢

 

        資料倉儲應用(data warehousing application)的特點是資料量巨大,執行的多為自定義查詢(ad hoc query),且併發事務較少。這種環境下使用點陣圖索引(bitmap index)具備如下優勢:

 

能夠減少大資料量自定義查詢的響應時間

與其他索引技術相比能夠節省大量儲存空間

即使硬體配置較低也能顯著提高效能

有利於並行 DML 和並行載入

        為一個大表建立傳統的平衡樹索引(B-tree index)可能佔用極大的儲存空間,索引有可能比資料表還要大數倍。而一個點陣圖索引(bitmap index)所佔的空間比被索引資料還要小得多。

 

        點陣圖索引(bitmap index)不適用於 OLTP 系統,因為這樣的系統中存在大量對資料進行修改的併發事務。點陣圖索引主要用於資料倉儲系統中(data warehousing)的決策支援功能,在這種環境下使用者對資料的操作主要是查詢而非修改。

 

        主要進行大於(greater than)或小於(less than)比較的列,不適宜使用點陣圖索引(bitmap index)。例如,WHERE 子句中常會將 salary 列和一個值進行比較,此時更適合使用平衡樹索引(B-tree index)。點陣圖索引適用於等值查詢,尤其是存在 AND,OR,和 NOT 等邏輯操作符的組合時。

 

        點陣圖索引(bitmap index)是整合在 Oracle 的優化器(optimizer)和執行引擎(execution engine)之中的。點陣圖索引也能夠和 Oracle 中的其他執行方法(execution method)無縫地組合。例如,優化器可以在利用一個表的點陣圖索引和另一個表的平衡樹索引(B-tree index)對這兩張表進行雜湊連線(hash join)。優化器能夠在點陣圖索引及其他可用的訪問方法(例如常規的平衡樹索引,或全表掃描(full table scan))中選擇效率最高的方式,同時考慮是否適合使用並行執行。

 

        點陣圖索引(bitmap index)如同常規索引一樣,可以結合並行查詢(parallel query)和並行 DML(parallel DML)一起工作。建立於分割槽表(partitioned table)的點陣圖索引必須為本地索引(local index)。Oracle 還支援並行地建立點陣圖索引,以及建立複合點陣圖索引。

 

5.8.11.2 基數

 

        在基數(cardinality)小的列上建立點陣圖索引(bitmap index)效果最好。所謂某列的基數小(low cardinality)是指此列中所有不相同的值的個數要小於總行數。如果某列中所有不相同的值的個數佔總行數的比例小於 1%,或某列中值的重複數量在 100 個以上,那麼就可以考慮在此列上建立點陣圖索引。即便某列的基數較上述標準稍大,或值的重複數量較上述標準稍小,如果在一個查詢的 WHERE 子句中需要引用此列定義複雜的條件,也可以考慮在此列上建立點陣圖索引。

 

        例如,一個表包含一百萬行資料,其中的一列包含一萬個不相同的值,就可以考慮在此列上建立點陣圖索引(bitmap index)。此列上點陣圖索引的查詢效能將超過平衡樹索引(B-tree index),當此列與其他列作為組合條件時效果尤為明顯。

 

        平衡樹索引(B-tree index)適用於高基數的資料,即資料的可能值很多,例如CUSTOMER_NAME 或 PHONE_NUMBER 列。在有些情況下,平衡樹索引所需的儲存空間可能比被索引資料還要大。如果使用得當,點陣圖索引將遠遠小於同等情況下的平衡樹索引。

 

        對於自定義查詢(ad hoc query)或相似的應用,使用點陣圖索引(bitmap index)能夠顯著地提高查詢效能。查詢的 WHERE 子句中的 AND 和 OR 條件直接對點陣圖(bitmap)進行布林運算(Boolean operation)得到一個點陣圖結果集(resulting bitmap),而無需將所有的點陣圖轉換為 ROWID。如果布林操作後的結果集較小,那麼查詢就能夠迅速得到結果,而無需進行全表掃描(full table scan)。

 

5.8.11.3 點陣圖索引和空值

 

        與其他大多數索引不同,點陣圖索引(bitmap index)可以包含鍵值(key value)為 NULL 的行。將鍵值為空的行進行索引對有些 SQL 語句是有用處的,例如包含 COUNT 聚合函式的查詢。

 

5.8.11.4 分割槽表上的點陣圖索引

 

        使用者可以在分割槽表(partitioned table)上建立點陣圖索引(bitmap index)。唯一的限制是點陣圖索引對分割槽表來說必須是本地的(local),而不能是全域性索引(global index)。只有非分割槽表才能使用全域性點陣圖索引。

 

 

5.8.12 點陣圖連線索引

        除了建立在單個表之上的點陣圖索引(bitmap index),使用者還可以建立點陣圖連線索引(bitmap join index),此種索引是為了連線(join)兩個或多個資料表而建的。點陣圖連線索引(bitmap join index)可以預先將有連線關係的資料進行儲存,且所需的儲存空間較小。對於一個表的某列的每個值,點陣圖連線索引為其儲存其他表中與此值有連線關係的資料行的 rowid。在資料倉儲環境中,連線關係通常是維表(dimension table)中的主鍵(primary key)與事實表(fact table)中的外來鍵(foreign key)進行等值內連線(equi-inner join)。

 

        物化連線檢視(materialized join view)也是一種預先將連線物化的方法,但與之相比點陣圖連線索引(bitmap join index)所需的儲存空間更少。因為物化連線檢視不會壓縮事實表(fact table)中的 rowid。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24996904/viewspace-1175256/,如需轉載,請註明出處,否則將追究法律責任。

相關文章