1. 程式人生 > 其它 >索引原理及SQL優化思路

索引原理及SQL優化思路

索引是一種資料庫結構,能夠就資料庫中的某列或某幾列提供快速查詢,而不用檢索整個表格。建立索引時,oracle會首先對全表進行搜尋,然後把要建立索引的欄位排序,並構建索引條目(包含欄位值和該欄位在原表中的地址值rowid),把索引條目儲存到索引段中。

索引型別

B-Tree索引(ORACLE預設)

  • 根節點(Root node):一個B樹索引只有一個根節點,它實際就是位於樹的最頂端的分支節點。
  • 分支節點(Branch node):最小的鍵值字首(minimum key prefix),用於在(本塊的)兩個鍵值之間做出分支選擇,指向包含所查詢鍵值的子塊(child block)的指標。
  • 葉子節點(Leaf node):資料行的鍵值(key value)、鍵值對應資料行的 ROWID。
注意
  1. 在Oracle中null被定義為無限大,故在索引不會存有與null值對應的條目。如果不加其他限制條件的對錶進行is null掃描,將會是全表掃描;如果是is not null掃描將會是帶索引掃描
  2. 不在低基數列上建立單列索引,例如“性別”
  3. 通過索引查詢資料,行數一般不要超過全表的20%,否則採用全表掃描方式更合適

複合索引

點陣圖索引

點陣圖索引是從oracle 7.3版本開始引入的。點陣圖索引是這樣一種結構,其中用一個索引鍵條目儲存指向多行的指標,這與B*樹結構不同,在b*樹結構中,索引鍵和表中的行存在著對應關係。在點陣圖索引中,可能只有很少的索引條目,每個索引條目指向多行,而在傳統的B*樹中,一個索引條目就指向一行。 如下表,由三列組成,分別是姓名、性別和婚姻狀況,其中性別只有男和女兩項,婚姻狀況由已婚、未婚、離婚這三項,該表共有100w個記錄。現在有這樣的查詢:select * from table where Gender=‘男’ and Marital=“未婚”; 1)不使用索引 不使用索引時,資料庫只能一行行掃描所有記錄,然後判斷該記錄是否滿足查詢條件。 2)B樹索引 對於性別,可取值的範圍只有'男','女',並且男和女可能各站該表的50%的資料,這時新增B樹索引還是需要取出一半的資料, 因此完全沒有必要。相反,如果某個欄位的取值範圍很廣,幾乎沒有重複,比如身份證號,此時使用B樹索引較為合適。事實上,當取出的行資料佔用表中大部分(超過20%)的資料時,即使添加了B樹索引,資料庫如oracle、mysql也不會使用B樹索引,很有可能還是一行行全部掃描。

點陣圖索引原理:

如果在性別列上建立了點陣圖索引,對於性別這個列,針對每行的rowid(rowid可以理解為每行的物理位置),點陣圖索引形成兩個向量,男向量為10100...,向量的每一位表示該行是否是男,如果是則位1,否為0,同理,女向量位01011,(可以理解為給每行資料的性別列中為產生兩個向量分別為男向量和女向量:男向量中 值為男:用1表示,值不是男用0表示,同理女向量中 值為女:用1表示,值不是女:用0表示) 如果在婚姻狀況列上建立了點陣圖索引 對於婚姻狀況這一列,點陣圖索引生成三個向量,已婚為11000...,未婚為00100...,離婚為00010...。

點陣圖索引檢索資料的過程:

當我們使用查詢語句“select * from table where Gender=‘男’ and Marital=“未婚”;”的時候 首先取出男向量10100...,然後取出未婚向量00100...,將兩個向量做and操作,這時生成新向量00100...,可以發現rowid=3的and之後的結果為1,表示該表的rowid=3的這行資料就是我們需要查詢的結果(如下“and的結果”為1的就是需要查詢的結果),然後根據rowid找到需要的資料

HASH索引

使用HASH索引必須要使用HASH叢集。建立一個叢集或HASH叢集的同時,也就定義了一個叢集鍵。這個鍵告訴Oracle如何在叢集上儲存表。在儲存資料時,所有與這個叢集鍵相關的行都被儲存在一個數據庫塊上。如果資料都儲存在同一個資料庫塊上,並且將HASH索引作為WHERE子句中的確切匹配,Oracle就可以通過執行一個HASH函式和I/O來訪問資料。Oracle可以快速使用該值,基於HASH函式確定行的物理儲存位置。

Oracle 執行計劃

什麼是Oracle執行計劃

執行計劃是一條查詢語句在Oracle中執行過程或者訪問路徑的描述.

檢視Oracle執行計劃

1.執行計劃常用的列欄位解釋 基數:返回的結果集行數 位元組:執行該步驟後返回的位元組數 耗費(cust),CPU耗費:Oracle估計的該步驟的執行成本,用於說明SQL執行的代價,理論上越小越好.

看懂Oracle執行計劃

1) plSql : Fn+F5 通過tree檢視

2)plSql : Fn+F5通過text檢視

3)navicat檢視 注:根據縮排來判斷,縮排最多的最先執行(縮排相同時,最上面的最先執行)

表的訪問方式

  • TABLE ACCESS FULL(全表掃描)
  • TABLE ACCESS BY ROWID(通過rowid的表存取)
  • TABLE ACCESS BY INDEX SCAN(索引掃描)

ABLE ACCESS FULL(全表掃描)

Oracle會讀取表中的所有行,並檢查是否滿足where語句中條件; 使用建議:資料量太大的表不建議全表掃描 一般5000行以下可以使用全表掃描。

TABLE ACCESS FULL(全表掃描)

Oracle會讀取表中的所有行,並檢查是否滿足where語句中條件; 使用建議:資料量太大的表不建議全表掃描

TABLE ACCESS BY ROWID(通過ROWID的表存取)

ROWID的解釋:oracle會自動加在表的每一行的最後一列偽列,表中並不會物理儲存ROWID的值,一旦一行資料插入後,則其對應的ROWID在該行的生命週期內是唯一的,即使發生行遷移,該行的ROWID值也不變。

TABLE ACCESS BY INDEX SCAN(索引掃描)

在索引塊中即儲存每個索引的鍵值,也儲存具有該鍵值所對的ROWID. 索引的掃描分兩步:首先是找到索引所對的ROWID,其次通過ROWID讀取改行資料 索引掃描又分五種:
  • INDEX UNIQUE SCAN(索引唯一掃描)
  • INDEX RANGE SCAN(索引範圍掃描)
  • INDEX FULL SCAN(索引全掃描)
  • INDEX FAST FULL SCAN(索引快速掃描)
  • INDEX SKIP SCAN(索引跳躍掃描)

(a).INDEX UNIQUE SCAN(索引唯一掃描)

針對唯一性索引(UNIQUE INDEX)的掃描,每次至多隻返回一條記錄,主要針對該欄位為主鍵或者唯一;

(b). INDEX RANGE SCAN(索引範圍掃描)

使用一個索引存取多行資料; 發生索引範圍掃描的三種情況:
  • 在唯一索引列上使用了範圍操作符(如:> < <> >= <= between)
  • 在組合索引上,只使用部分列進行查詢(查詢時必須包含前導列,否則會走全表掃描)
  • 對非唯一索引列上進行的任何查詢

(c). INDEX FULL SCAN(索引全掃描)

  • 進行全索引掃描時,查詢出的資料都必須從索引中可以直接得到

(d). INDEX FAST FULL SCAN(索引快速掃描)

  • 掃描索引中的所有的資料塊,與 INDEX FULL SCAN 類似,但是一個顯著的區別是它不對查詢出的資料進行排序(即資料不是以排序順序被返回)

(e). INDEX SKIP SCAN(索引跳躍掃描):

Oracle 9i後提供,有時候複合索引的前導列(索引包含的第一列)沒有在查詢語句中出現,oralce也會使用該複合索引,這時候就使用的INDEX SKIP SCAN; 當Oracle發現前導列的唯一值個數很少時,會將每個唯一值都作為常規掃描的入口,在此基礎上做一次查詢,最後合併這些查詢;