1. 程式人生 > >Oracle B樹索引和點陣圖索引、索引的說明和目的、索引碎片問題

Oracle B樹索引和點陣圖索引、索引的說明和目的、索引碎片問題

B樹索引和點陣圖索引

索引是資料庫為了提高查詢效率提供的一種冗餘結構,保守計算資料庫50%以上的調優可以通過調整索引來進行優化;

引用國內一位資深的ORACLE專家的話:"我其實只懂點(挨踢)知識,IT裡面其實只懂點甲骨文,甲骨文裡面其實只懂點資料庫,資料庫裡面其實只懂點SQL,SQL裡面其實只懂點索引"——"你才是真正的專家!"

根據個人的淺薄的經驗,作為DBA的日常運維會越來越少,從資料庫的每個版本的更新來看,資料庫系統已經趨向越來越智慧話,DBA能幹的活也越來越少了,如果一個DBA只能做做日常的表空間擴容、資料庫的備份恢復、啟停、系統的更新,那麼將是很危險的一件事。而調優自古以來就是一門很高深的學問,如果能把這個做好了,那麼DBA能夠創造的價值和在公司的作用中,將越來越顯著;

說了這麼多,應該引入主題了,如果要做好調優,先從索引入手吧。

後續的章節中將陸續更新索引的一些知識,第一章從索引的類別開始吧;

 

二  索引在結構上的類別可劃分如下:B樹索引、點陣圖索引、雜湊索引、反轉索引等

 

三  索引的介紹:

1、B樹索引(BTREE

B數索引是我們日常工作最最常用的索引,大家平時在工作中說的"索引"預設都是B數索引;

索引其實很簡單,也很容易理解,用一本書的目錄來形容最為貼切了,B樹索引的結構跟圖書館的目錄也很像

B樹索引的結構:

索引的頂層為根,它包括指向索引中下一層次的條目。下一層次為分支塊,它又指向位於索引中下一層索引中下一層次的塊,最底層的是葉節點,它包含指向錶行的索引條目。葉塊是雙向關聯的,這邊與按鍵值升序或降序掃描索引;

 

索引葉條目的格式

一個索引條目包含以下元件:

條目頭:儲存列數和鎖定資訊

鍵列長度/值對:用於定義鍵中的列大小,後面跟隨列值(此類長度/值對的數目就是索引中的最大列數)。

 

索引葉條目的特性

在非分割槽表的B 樹索引中:

當多個行具有相同的鍵值時,如果不壓縮索引,鍵值會出現重複

當某行包含的所有鍵列為NULL 時,該行沒有對應的索引條目。因此,當WHERE 子句指定了NULL 時,將始終執行全表掃描

 

對索引執行DML 操作的效果

對錶執行DML 操作時,Oracle 伺服器會維護所有索引。下面說明對索引執行DML 命令產生的效果:

執行插入操作導致在相應塊中插入索引條目。

刪除一行只導致對索引條目進行邏輯刪除。已刪除行所佔用的空間不可供後面新的葉條目使用。

更新鍵列導致對索引進行邏輯刪除和插入。PCTFREE 設定對索引沒有影響,但建立時除外。即使索引塊的空間少於PCTFREE 指定的空間,也可以向索引塊新增新條目。

該圖更能體現索引的結構

 

2、點陣圖索引

點陣圖索引(bitmap index)是從Oracle7.3 版本開始引入的。目前Oracle 企業版和個人版都支援點陣圖索引,但標準版不支援。

點陣圖索引在平時的OLTP系統中比較少見,但是在OLAP系統中就會經常見到,號稱資料倉庫調優的三個利器之一;

點陣圖索引(通過在以下特定情況下,點陣圖索引比B 樹索引更有優勢:

表具有數百萬行且鍵列的基數較低時(也就是列的不同值極少時)。例如,對於護照記錄表中的性別和婚姻狀況列,點陣圖索引可能比B 樹索引更可取。

經常使用包含OR 運算子的多個WHERE 條件組合進行查詢時

鍵列上的活動為只讀活動或少量更新活動時(OLAP系統的特點)

 

點陣圖索引的結構

點陣圖索引也可以按B 樹形式進行組織,但是,葉節點會儲存每個鍵值的點陣圖,而不是行ID 列表。點陣圖中每一位與一個可能的行ID 對應,如果設定了該位,則表示具有對應行ID 的行包含鍵值。

如圖所示,點陣圖索引的葉節點包含:

條目頭,其中包含列數和鎖定資訊

由每個鍵列的長度/值對組成的鍵值(在幻燈片的示例中,關鍵字只由一列組成;第一個條目的鍵值為Blue)

開始ROWID,在本示例中它指定塊號10、行號0 和檔案號3

結束ROWID,在本示例中它指定塊號12、行號8 和檔案號3

由位字串組成的點陣圖段(如果對應行包含鍵值,則會設定位;如果對應行不包含鍵值,則不會設定位。Oracle 伺服器使用已獲專利的壓縮技術儲存點陣圖段。)開始ROWID 是點陣圖中的點陣圖段指向的第一行的行ID,也就是說,點陣圖的第一位對應於該行ID,點陣圖的第二位對應於塊中的下一行。結束ROWID 是一個指標,它指向由點陣圖段覆蓋的表中的最後一行。點陣圖索引使用受限的行ID。

 

使用點陣圖索引

B 樹用於定位葉節點,這些節點包含指定鍵值的點陣圖段。開始ROWID 和點陣圖段用於定位包含鍵值的行。

對錶中的鍵列進行更改後,也必須修改點陣圖。這會導致相關的點陣圖段被鎖定。由於鎖是在整個點陣圖段上獲得的,因此,在第一個事務處理結束之前,其它事務處理不能更新點陣圖覆蓋的行。

索引的說明和目的 

1.什麼是索引
    索引是建立在表的一列或多個列上的輔助物件,目的是加快訪問表中的資料;
  Oracle儲存索引的資料結構是B*樹,點陣圖索引也是如此,只不過是葉子節點不同B*數索引;
  索引由根節點、分支節點和葉子節點組成,上級索引塊包含下級索引塊的索引資料,葉節點包含索引資料和確定行實際位置的rowid。
  使用索引的目的
  加快查詢速度
  減少I/O操作
  消除磁碟排序
  何時使用索引
  查詢返回的記錄數
  排序表<40%
  非排序表 <7%
  表的碎片較多(頻繁增加、刪除)

  2.索引的種類
  非唯一索引(最常用)
  唯一索引
  點陣圖索引
  區域性有字首分割槽索引
  區域性無字首分割槽索引
  全域性有字首分割槽索引
  雜湊分割槽索引
  基於函式的索引
  3.管理索引的準則
  
  在表中插入資料後建立索引
  在用SQL*Loader或import工具插入或裝載資料後,建立索引比較有效;
    3.1索引正確的表和列
   經常檢索排序大表中40%或非排序表7%的行,建議建索引;
  。為了改善多表關聯,索引列用於聯結;
  。列中的值相對比較唯一;
  。取值範圍(大:B*樹索引,小:點陣圖索引);
  。Date型列一般適合基於函式的索引;
  。列中有許多空值,不適合建立索引
  
  3.2為效能而安排索引列
  
  。經常一起使用多個欄位檢索記錄,組合索引比單索引更有效;
  。把最常用的列放在最前面,例:dx_groupid_serv_id(groupid,serv_id),在where條件中使用groupid或groupid,serv_id,查詢將使用索引,若僅用到serv_id欄位,則索引無效;
  3.3合併/拆分不必要的索引。
  
  3.4限制每個表索引的數量
  
  。一個表可以有幾百個索引(你會這樣做嗎?),但是對於頻繁插入和更新表,索引越多系統CPU,I/O負擔就越重;
  。建議每張表不超過5個索引。
  
  3.5刪除不再需要的索引
  
  。索引無效,集中表現在該使用基於函式的索引或點陣圖索引,而使用了B*樹索引;
  。應用中的查詢不使用索引;
  。重建索引之前必須先刪除索引,若用alter index … rebuild重建索引,則不必刪除索引。
  
  3.6索引資料塊空間使用
  。建立索引時指定表空間,特別是在建立主鍵時,應明確指定表空間;
  。合理設定pctfress,注意:不能給索引指定pctused;
  。估計索引的大小和合理地設定儲存引數,預設為表空間大小,或initial與next設定成一樣大。
  3.7考慮並行建立索引
  。對大表可以採用並行建立索引,在並行建立索引時,儲存引數被每個查詢伺服器程序分別使用,例如:initial為1M,並行度為8,則建立索引期間至少要消耗8M空間;
  3.8考慮用nologging建立索引
  。對大表建立索引可以使用nologging來減少重做日誌;
  。節省重做日誌檔案的空間;
  。縮短建立索引的時間;
  。改善了並行建立大索引時的效能。

4.怎樣建立最佳索引
  
  明確地建立索引
  create index index_name on table_name(field_name)
  tablespace tablespace_name
  pctfree 5
  initrans 2
  maxtrans 255
  storage
  (
  minextents 1
  maxextents 16382
  pctincrease 0
  );
  
  建立基於函式的索引
  
  。常用與UPPER、LOWER、TO_CHAR(date)等函式分類上,例:
  create index idx_func on emp (UPPER(ename)) tablespace tablespace_name;
  
  建立點陣圖索引
  
  。對基數較小,且基數相對穩定的列建立索引時,首先應該考慮點陣圖索引,例:
  create bitmap index idx_bitm on class (classno) tablespace tablespace_name;
  
  明確地建立唯一索引
  
  。可以用create unique index語句來建立唯一索引,例:
  create unique index dept_unique_idx on dept(dept_no) tablespace idx_1;
  
  建立與約束相關的索引
  
  。可以用using index字句,為與unique和primary key約束相關的索引,例如:
  alter table table_name
  add constraint PK_primary_keyname primary key (field_name)
  using index tablespace tablespace_name;
  
  5.如何建立區域性分割槽索引
  
  。基礎表必須是分割槽表;
  。分割槽數量與基礎表相同;
  。每個索引分割槽的子分割槽數量與相應的基礎表分割槽相同;
  。基礎表的子分割槽中的行的索引項,被儲存在該索引的相應的子分割槽中,例如:
  Create Index TG_CDR04_SERV_ID_IDX On TG_CDR04(SERV_ID)
  Pctfree 5
  Tablespace TBS_AK01_IDX
  Storage (
  MaxExtents 32768
  PctIncrease 0
  FreeLists 1
  FreeList Groups 1
  )
  local
  /
  
  6如何建立範圍分割槽的全域性索引
  
  。基礎表可以是全域性表和分割槽表。
  create index idx_start_date on tg_cdr01(start_date)
  global partition by range(start_date)
  (partition p01_idx vlaues less than (‘0106’)
  partition p01_idx vlaues less than (‘0111’)
  …
  partition p01_idx vlaues less than (‘0401’ ))
  /
  重建現存的索引
  重建現存的索引的當前時刻不會影響查詢;
  
  重建索引可以刪除額外的資料塊;
  提高索引查詢效率;
  alter index idx_name rebuild nologging;
  
  對於分割槽索引:
  alter index idx_name rebuild partition partiton_name nologging;
  
  7.要刪除索引的原因
  
  。不再需要的索引;
  。索引沒有針對其相關的表所釋出的查詢提供所期望的效能改善;
  。應用沒有用該索引來查詢資料;
  。該索引無效,必須在重建之前刪除該索引;
  。該索引已經變的太碎了,必須在重建之前刪除該索引;
  。語句:drop index idx_name;drop index idx_name drop partition partition_name;
  
  8.建立索引的代價
  
  基礎表維護時,系統要同時維護索引,不合理的索引將嚴重影響系統資源,主要表現在CPU和I/O上;
  
  插入、更新、刪除資料產生大量db file sequential read鎖等待;

一個表中有幾百萬條資料,對某個欄位加了索引,但是查詢時效能並沒有什麼提高,這主要可能是oracle的索引限制造成的。

oracle的索引有一些索引限制,在這些索引限制發生的情況下,即使已經加了索引,oracle還是會執行一次全表掃描,查詢的效能不會比不加索引有所提高,反而可能由於資料庫維護索引的系統開銷造成效能更差。

下面是一些常見的索引限制問題。

9、使用不等於操作符(<>, !=)

下面這種情況,即使在列dept_id有一個索引,查詢語句仍然執行一次全表掃描

select * from dept where staff_num <> 1000;

但是開發中的確需要這樣的查詢,難道沒有解決問題的辦法了嗎?

有!

通過把用 or 語法替代不等號進行查詢,就可以使用索引,以避免全表掃描:上面的語句改成下面這樣的,就可以使用索引了。

select * from dept shere staff_num < 1000 or dept_id > 1000;

10、使用 is null 或 is not null

使用 is null 或is nuo null也會限制索引的使用,因為資料庫並沒有定義null值。如果被索引的列中有很多null,就不會使用這個索引(除非索引是一個位圖索引,關於點陣圖索引,會在以後的blog文章裡做詳細解釋)。在sql語句中使用null會造成很多麻煩。

解決這個問題的辦法就是:建表時把需要索引的列定義為非空(not null)

 11、使用函式

如果沒有使用基於函式的索引,那麼where子句中對存在索引的列使用函式時,會使優化器忽略掉這些索引。下面的查詢就不會使用索引:

select * from staff where trunc(birthdate) = '01-MAY-82';

但是把函式應用在條件上,索引是可以生效的,把上面的語句改成下面的語句,就可以通過索引進行查詢。

select * from staff where birthdate < (to_date('01-MAY-82') + 0.9999);

12、比較不匹配的資料型別

比較不匹配的資料型別也是難於發現的效能問題之一。下面的例子中,dept_id是一個varchar2型的欄位,在這個欄位上有索引,但是下面的語句會執行全表掃描。

select * from dept where dept_id = 900198;

這是因為oracle會自動把where子句轉換成to_number(dept_id)=900198,就是3所說的情況,這樣就限制了索引的使用。把SQL語句改為如下形式就可以使用索引

select * from dept where dept_id = '900198';

13、使用like子句

使用like子句查詢時,資料需要把所有的記錄都遍歷來進行判斷,索引不能發揮作用,這種情況也要儘量避免。

Like 的字串中第一個字元如果是‘%’則用不到索引
Column1 like ‘aaa%’ 是可以的
Column1 like ‘%aaa%’用不到

14.使用in

儘管In寫法要比exists簡單一些,exists一般來說效能要比In要高的多
用In還是用Exists的時機
當in的集合比較小的時候,或者用Exists無法用到選擇性高的索引的時候,用In要好,否則就要用Exists
例:select count(*) from person_info where xb in (select xb_id from dic_sex);
Select count(*) from n_acntbasic a where shbxdjm =:a and exists(select 1 from person_info where pid=a.pid and …);

Select * from person_info where zjhm=3101….;將會對person_info全表掃描
Select * from person_info where zjhm =‘3101…’才能用到索引

假定TEST表的dt欄位是date型別的並且對dt建了索引。
如果要查‘20041010’一天的資料.下面的方法用不到索引
Select * from test where to_char(dt,’yyyymmdd’) =‘20041010’;
而select * from test where dt >=to_date(‘20041010’,’yyyymmdd’) and dt < to_date(‘20041010’,’yyyymmdd’) + 1 將會用到索引。

15.如果能不用到排序,則儘量避免排序。
用到排序的情況有
集合操作。Union ,minus ,intersect等,注:union all 是不排序的。
Order by
Group by
Distinct
In 有時候也會用到排序
確實要排序的時候也儘量要排序小資料量
,儘量讓排序在記憶體中執行,有文章說,記憶體排序的速度是硬碟排序的1萬倍。
--------------------------------------------------------------------------
一、索引的幾種常用用法 
1、建立索引

create index <index_name> on <table_name>(<column_name>) [tablespace<tablespace_name>];
1
2、重置索引

alter index <index_name> rebuild;
1
3、刪除索引

drop index <index_name>
1
例項:

create table test as
select rownum as id,
to_char(sysdate + rownum/24/3600,'yyyy-mm-dd hh24:mi:ss') as ttime,
trunc(dbms_random.value(0,100)) as random_id,
dbms_random.string('x',20) txt
from dual
connect by level<=20000000;
select count(id) from test;
select * from test where txt='2W8U82V49FKZYK0JQETF';
drop table  test;
1
2
3
4
5
6
7
8
9
10
二、索引的分類 
1、普通索引

create index index_text_txt on test(txt);
1
2、唯一索引 Oracle 自動在表的主鍵上建立唯一索引

create unique index <index_name> on <index_name>(<coiumn_name>);
1
3、點陣圖索引 
作用範圍及優點: 
1、點陣圖索引適合建立在低階數列(重複的數值多,如性別)上 
2、減少響應時間 
3、節省空間佔用

create bitmap index <index_name> on <table_name>(<column_name>)
1
4、組合索引 
作用範圍及優點: 
1、組合索引是在表的多個列上建立的索引 
2、索引中的順序是任意的 
3、如果SQL語言的WHERE子句中引用了組合索引的所有或大多數列,則可以提高檢索速度

例項:
create index <index_name> on <table_name>(<column_name1><column_name2>)
1
2
5、基於函式索引

create index <index_name> on <table_name>(<function_name>(<column_name>));
1
6、反向鍵索引

create index <index_name> on <table_name>(column_name) reverse;
---------------------------------------------------------------------------------------
1、檢視索引資訊可以在 all_indexs 表中
2、檢視索引資訊及引用的列 all_ind_columns
3、檢視函式索引資訊  all_ind_expressions

4、oracle比較智慧,有時候即使建立了索引也不會使用,比如說在資料量比較少的情況下,可能就不會用索引
5、當進行全表掃描的時候,不用索引效率會更好
6、查詢可能會使用快取,所以說如果發現執行速度變快了,不一定說明你的sql更優了,有可能是使用到了快取而已
7、使用plsql中的“解釋計劃”功能可以比較執行計劃的消耗,進而寫出更優的sql

 

管理索引的原則
使用索引應該遵循以下一些基本的原則。
1.小表不需要建立索引。
2.對於大表而言,如果經常查詢的記錄數目少於表中總記錄數目的15%時,可以建立索引。這個比例並不絕對,它與全表掃描速度成反比。
3.對於大部分列值不重複的列可建立索引。
4.對於基數大的列,適合建立B樹索引,而對於基數小的列適合建立點陣圖索引。
5.對於列中有許多空值,但經常查詢所有的非空值記錄的列,應該建立索引。
6.LONG和LONG RAW列不能建立索引。
7.經常進行連線查詢的列上應該建立索引。
8.在使用CREATE INDEX語句建立查詢時,將最常查詢的列放在其他列前面。
9.維護索引需要開銷,特別時對錶進行插入和刪除操作時,因此要限制表中索引的數量。對於主要用於讀的表,則索引多就有好處,但是,一個表如果經常被更改,則索引應少點。
10.在表中插入資料後建立索引。如果在裝載資料之前建立了索引,那麼當插入每行時,Oracle都必須更改每個索引。


索引
索引是關係資料庫中用於存放每一條記錄的一種物件,主要目的是加快資料的讀取速度和完整性檢查。建立索引是一項技術性要求高的工作。一般在資料庫設計階段的與資料庫結構一道考慮。應用系統的效能直接與索引的合理直接有關。下面給出建立索引的方法和要點。
§3.5.1 建立索引
1. CREATE INDEX命令語法:

 
CREATE INDEX
CREATE [unique] INDEX [user.]index
ON [user.]table (column [ASC | DESC] [,column
[ASC | DESC] ] ... )
[CLUSTER [scheam.]cluster]
[INITRANS n]
[MAXTRANS n]
[PCTFREE n]
[STORAGE storage]
[TABLESPACE tablespace]
[NO SORT]
Advanced

 
其中:
   schema ORACLE模式,預設即為當前帳戶
   index 索引名
   table 建立索引的基表名
   column 基表中的列名,一個索引最多有16列,long列、long raw
              列不能建索引列
   DESC、ASC 預設為ASC即升序排序
   CLUSTER 指定一個聚簇(Hash cluster不能建索引)
   INITRANS、MAXTRANS 指定初始和最大事務入口數
   Tablespace 表空間名
   STORAGE 儲存引數,同create table 中的storage.
   PCTFREE 索引資料塊空閒空間的百分比(不能指定pctused)
   NOSORT 不(能)排序(儲存時就已按升序,所以指出不再排序)

 
 
2.建立索引的目的:

 
建立索引的目的是:
l 提高對錶的查詢速度;
l 對錶有關列的取值進行檢查。

 
但是,對錶進行insert,update,delete處理時,由於要表的存放位置記錄到索引項中而會降低一些速度。
注意:一個基表不能建太多的索引;
      空值不能被索引
      只有唯一索引才真正提高速度,一般的索引只能提高30%左右。

 
   Create index ename_in on emp (ename,sal);

 
例1:商場的商品庫表結構如下,我們為該表的商品程式碼建立一唯一索引,使得在前臺POS收款時提高查詢速度。
Create table good(good_id number(8) not null,/* 商品條碼 */
                   Good_desc varchar2(40), /* 商品描述 */
                   Unit_cost number(10,2) /* 單價 */
                   Good_unit varchar2(6), /* 單位 */
                   Unit_pric number(10,2) /* 零售價 */
                   );

 
注:提高查詢速度的方法還有在表上建立主鍵,主鍵與唯一索引的差別
在於唯一索引可以空,主鍵為非空,比如:

 
Create table good(good_id number(8) primary key,
                    Good_desc Varchar2(40),
                    Unit_cost number(10,2),
                    Good_unit char(6),
                    Unit_pric number(10,2)
                   );

 
§3.5.2 修改索引
對於較早的Oracle版本,修改索引的主要任務是修改已存在索引的儲存引數適應增長的需要或者重新建立索引。而Oracle8I及以後的版本,可以對無用的空間進行合併。這些的工作主要是由管理員來完成。

 
簡要語法結構如下,更詳細的語法圖見電子文件《Oracle8i Reference 》 中的 Alter index.

 
ALTER [UNIQUE] INDEX [user.]index
[INITRANS n]
[MAXTRANS n] 
REBUILD 
[STORAGE n]

 
其中:
REBUILD 是 根據原來的索引結構重新建立索引,實際是刪除原來的索引後再重新建立。

 
提示:DBA經常用 REBUILD 來重建索引可以減少硬碟碎片和提高應用系統的效能。

 
例:
alter index pk_detno rebuild storage(initial 1m next 512k);

 
ALTER INDEX emp_ix REBUILD REVERSE;

 
 
Oracle8i 的新功能可以對索引的無用空間進行合併,它由下面命令完成:

 
ALTER INDEX . . . COALESCE;

 
例如:

 
ALTER INDEX ename_idx COALESCE;

 
§3.5.3 刪除索引
當不需要時可以將索引刪除以釋放出硬碟空間。命令如下:

 
DROP INDEX [schema.]indexname

 
例如:

 
sql> drop index pk_dept;

 
注:當表結構被刪除時,有其相關的所有索引也隨之被刪除。

 
§3.6 新索引型別
Oracle8i為了效能優化而提供新的建立新型別的索引。這些新索引在下面介紹:

 
§3.6.1 基於函式的索引
基於函式的索引就是儲存預先計算好的函式或表示式值的索引。這些表示式可以是算術運算表示式、SQL或PL/SQL函式、C呼叫等。值得注意的是,一般使用者要建立函式索引,必須具有GLOBAL QUERY REWRITE和CREATE ANY INDEX許可權。否則不能建立函式索引,看下面例子:

 
例1:為EMP表的ename 列建立大寫轉換函式的索引idx :

 
CREATE INDEX idx ON emp ( UPPER(ename));

 
這樣就可以在查詢語句來使用:

 
SELECT * FROM EMP WHERE UPPER(ename) LIKE ‘JOH%’;

 
例2:為emp 的工資和獎金之和建立索引:
1) 檢視emp 的表結構:
SQL> desc emp
 Name Null? Type
 ----------------------------------------- -------- ------------------
 EMPNO NOT NULL NUMBER(4)
 ENAME VARCHAR2(10)
 JOB VARCHAR2(9)
 MGR NUMBER(4)
 HIREDATE DATE
 SAL NUMBER(7,2)
 COMM NUMBER(7,2)
 DEPTNO NUMBER(2)

 
2)沒有授權就建立函式索引的提示:

 
SQL> create index sal_comm on emp ( (sal+comm)*12, sal,comm)
 2 tablespace users storage(initial 64k next 64k pctincrease 0);
create index sal_comm on emp ( (sal+comm)*12, sal,comm)
                                          *
ERROR at line 1:
ORA-01031: insufficient privileges

 
3) 連線到DBA帳戶並授權:

 
SQL> connect sys/
[email protected]
Connected. SQL> grant GLOBAL QUERY REWRITE to scott; Grant succeeded. SQL> grant CREATE ANY INDEX to scott; Grant succeeded. 4)在連線到scott帳戶,建立基於函式的索引: SQL> connect scott/[email protected] Connected. SQL> create index sal_comm on emp ( (sal+comm)*12, sal,comm) 2 tablespace users storage(initial 64k next 64k pctincrease 0); Index created. 1)在查詢中使用函式索引: SQL> select ename,sal,comm from emp where (sal+comm)*12 >5000; ENAME SAL COMM ---------------------- ---------------- ---------------- ALLEN 1600 300 WARD 1250 500 MARTIN 1250 1400 TURNER 1500 0 趙元傑 1234.5 54321 §3.6.2 反向鍵索引 反向鍵索引通過反向鍵保持索引的所有葉子鍵上的插入分佈。有時,可用反向鍵索引來避免不平衡的索引。對於反向鍵索引可以進行下面操作: l 通過在ALTER INDEX命令後加REBUILD NOREVERSE或REBUILD REVERSE子句來使索引邊為反向鍵索引或普通索引; l 採用範圍掃描的查詢不能使用反向鍵索引; l 點陣圖索引不能反向; l 索引編排表不能反向。 例1:建立一個反向鍵索引: CREATE INDEX i ON t (a,b,c) REVERSE; 例2:使一個索引變為反向鍵索引: ALTER INDEX i REBUILD NOREVERSE; §3.6.3 索引組織表 與普通的索引不一樣,索引組織表(Index_Organized Table)是根據表來儲存資料,即將索引和表儲存在一起。這樣的索引結構表(Index_organized table—IOT)的特點是:對錶資料的改變,如插入一新行、刪除某行都引起索引的更新。 索引組織表就象帶一個或多個列所有的普通表一樣,但索引組織表在B-樹索引結構的葉節點上儲存行資料。通過在索引結構中儲存資料,索引組織表減少了總的儲存量,此外,索引組織表也改善訪問效能。 由於表中的行與B_樹索引存放在一起,每個行都沒有ROWID,而是用主鍵來標識。但是Oracle會“猜”這些行的位置併為每個行分配邏輯的ROWID。此外,你可以為這樣的表建立第二個索引。 建立索引結構表也是用CREATE TABLE 命令加ORGANIZATION INDEX關鍵字來實現。但是,這樣的表在建立完後,你還必須為該表建立一個主鍵。 例子: CREATE TABLE IOT_EXPAMPLE ( Pk_col1 number(4), Pk_col2 varchar2(10), Non_pk_col1 varchar2(40), Non_pk_col2 date, CONSTRAINT pk_iot PRIMARY KEY ( pk_col1, pk_col2) ) ORGANIZATION INDEX TABLESPACE INDEX STORAGE( INITIAL 1M NEXT 512K PCTINCREASE 0 ); 索引組織表有些限制: l 不能使用唯一約束; l 必須具有一個主鍵; l 不能建立簇; l 不能包含LONG型別列; l 不支援分佈和複製。 提示:如果建立了索引組織表,則會在DBA_TABLES中的IOT_TYPE和IOT_NAME列上記錄有索引組織表的資訊。 例1.修改索引結構表 docindex 的索引段的INITRANS引數: ALTER TABLE docindex INITRANS 4; 例2.下面語句加一個的溢位資料段到索引組織表 docindex中: ALTER TABLE docindex ADD OVERFLOW; 例3.下面語句為索引組織表 docindex的溢位資料段修改INITRANS引數: ALTER TABLE docindex OVERFLOW INITRANS 4; ============================================================================================================ 適當的使用索引可以提高資料檢索速度,可以給經常需要進行查詢的欄位建立索引 oracle的索引分為5種:唯一索引,組合索引,反向鍵索引,點陣圖索引,基於函式的索引 建立索引的標準語法: CREATE INDEX 索引名 ON 表名 (列名) TABLESPACE 表空間名; 建立唯一索引: CREATE unique INDEX 索引名 ON 表名 (列名) TABLESPACE 表空間名; 建立組合索引: CREATE INDEX 索引名 ON 表名 (列名1,列名2) TABLESPACE 表空間名; 建立反向鍵索引: CREATE INDEX 索引名 ON 表名 (列名) reverse TABLESPACE 表空間名; 檢視文章 oracle 檢視索引類別以及檢視索引欄位被引用的欄位方法2008年01月04日 星期五 13:20檢視索引個數和類別 select * from user_indexes where table='表名' ; 檢視索引被索引的欄位 SQL>select * from user_ind_columns where index_name=upper('&index_name'); PS: 檢視某表的約束條件 SQL>select constraint_name, constraint_type,search_condition, r_constraint_name from user_constraints where table_name = upper('&table_name'); SQL>select c.constraint_name,c.constraint_type,cc.column_name from user_constraints c,user_cons_columns cc where c.owner = upper('&table_owner') and c.table_name = upper('&table_name') and c.owner = cc.owner and c.constraint_name = cc.constraint_name order by cc.position; 檢視檢視的名稱 SQL>select view_name from user_views;

索引碎片問題

索引分為B樹索引和點陣圖索引。我們主要研究B樹索引,B樹索引如下圖(圖片源自網路):

  索引是與表相關的一個可選結構,在邏輯上和物理上都獨立於表資料,索引能優化查詢,不能優化DML,oracle自動維護索引,頻繁的DML操作反而會引起大量的索引維護。

  如果sql語句僅僅訪問被索引的列,那麼資料庫只需從索引中讀取資料,而不會讀取表;如果該語句還要訪問未被索引的列,那麼資料庫會使用rowid來查詢表中的行,通常,為檢索表資料,資料庫以交換方式先讀取索引塊,然後讀取對應的表。

  索引的目的是減少IO,

大表,返回的行數<5%
經常使用where子句查詢的列
離散度高的列
更新鍵值代價低
邏輯AND、OR效率高
檢視索引建在哪表哪列
select * from user_indexes;
select * from user_ind_columns;
索引的使用
唯一索引
create unique index empno_idx on emp(empno);
一般索引
create index empno_idx on emp(empno);
組合索引
create index job_deptno_idx on emp(job,deptno);
函式索引:查詢時必須用到這個函式才會使用到。
create index fun_idx on emp(lower(ename));
。。。
索引問題
檢視執行計劃:set autotrace traceonly explain;

  索引碎片問題:由於基表做DML操作,導致索引表塊的自動更改操作,尤其是基表的delete操作會引起index表的index_entries的邏輯刪除,注意只有當一個索引塊中的全部index_entry都被刪除了,才會把這個索引塊刪除,索引對基表的delete、insert操作都會產生索引碎片問題。

  在oracle文件中並沒有清晰的給出索引碎片的量化標準,oracle建議通過segment advisor(片段顧問)解決表和索引的碎片問題(後面的課程會提及),如果你想自行解決,可以通過檢視 index_stats檢視,當以下三種情形之一發生時,說明積累的碎片應該整理了(經驗之談)

height >= 4 (概述中圖示索引樹的高度是3)
pct_used < 50%
del_lf_rows/lf_row > 0.2
-------------------------------------------------------------------------------
Oracle解決索引碎片功能
我們開始時向一個空的帶索引的表中插入大量資料後,是不會產生碎片問題的,但是,資料庫經過很長一段時間的增刪改查後,難免會出現碎片問題,影響資料庫的效能,Oracle對於這一問題有自己的解決方案。

下面介紹解決這一問題的方案:

首先要對索引進行分析:analyze index ind_1 validate structure;  ind_1為你自己建立的索引

分析後查詢幾個主要的引數判斷是否需要整理碎片:select name,HEIGHT,PCT_USED,DEL_LF_ROWS/LF_ROWS from index_stats;



這裡主要通過幾個標準來判斷是否需要整理碎片:

1.HEIGHT>=4

2.PCT_USED<50%

3.DEL_ROWS/LF_ROWS>0.2

如果查詢到的值符合以上三種情況的任意一種,就說明我們需要進行碎片整理工作了

碎片整理語句:alter index ind_1 rebuild [online] [tablespace name];

一般情況下都是要加上online引數的,不必加tablespace name。

以上就是對Oracle解決索引碎片功能的理解。

不是因為有了機遇才去爭取,而是因為爭取了才會遇到機遇
-------------------------------------------------------------------------------------
背景說明:

       今天查閱書籍時,偶然間發現“在對某個索引行執行刪除操作時,只是為該行增加了一個刪除標記,這個索引行並不會釋放它的儲存空間,Insert產生的新的索引行也不能被插入到該位置。索引列的修改過程其實是將對應的列值刪除,然後再插入新的列值(與資料行本身的修改是不一致的,這也正是我們儘量不使用修改頻繁的列來建立索引的原因)。所以,無論是插入、修改、刪除,都需要消耗儲存空間,增大B-Tree索引結構的深度,影響資料的查詢速度。尤其是刪除和修改,不僅造成了儲存空間的浪費,而且增加了掃描索引塊的數量”,這就是所謂的索引碎片問題,建議定期對經常使用的表執行檢查和重建索引操作。

問題重現:

      經測試,收集統計資訊等操作,無法釋放索引刪除塊所佔用的儲存空間。

analyze table tkk29 compute statistics;

select t.index_name, t.distinct_keys, t.num_rows, t.sample_size, t.last_analyzed 
      , t.blevel, t.leaf_blocks, t.* 
from user_indexes t 
where t.table_name = upper('tkk29');

tkk2901

 

delete from tkk29 
where mod(trunc((sysdate-createddate) * 24 * 60), 2) = 0;

analyze table tkk29 compute statistics;

analyze index IDX_tkk29_PARTICIPANT validate structure;

select t.name, t.blocks, t.lf_rows, t.del_lf_rows, t.lf_rows - t.del_lf_rows as lf_rows_used 
       , to_char((t.del_lf_rows/t.lf_rows) * 100, '999.999') as ratio, t.* 
from index_stats t
----------------------------------------------------------------------------------