天天看點

管理方案對象

對象:表、索引、存儲過程、函數都稱為對象

Schema:某個使用者下面對象的集合

Schema的名稱與使用者名相同,但是schema與使用者不是一回事,如果使用者下面沒有任何對象,那麼這個使用者就不存在schema,使用者下面有對象了,那麼schema就存在了

Oracle資料庫裡面最重要的對象就是表和索引

表用來存儲資料

索引用來加快查詢速度

表名+字段名+字段類型

每個表都會對應一個segment,表實體上存在segment裡面

表的作用在于友善我們更新對應segment裡的資料,以及将segment裡的資料格式化成我們容易了解的形式,并展現出來

Oracle裡面表的分類

1、普通表

一個表對應一個segment

2、分區表

一個表被分成多個分區,每個分區對應一個segment,每個segment可以位于不同的表空間裡,對于資料量非常大的表,我們可以采用這種方式。

3、索引組織表IOT

IOT必須有一個主鍵索引,同時所有的資料與主鍵列一起存放在主鍵索引的葉子節點裡,IOT在存儲上屬于索引,是以通過索引來對應segment

4、簇表cluster table

應用場合比較明顯

主表和明細表,經常兩個表進行關連查詢,例如訂單主表、訂單明細表

通過建立簇表,一個資料塊裡面存放了兩個表的資料,加快了關聯查詢速度

普通表

Oracle為列提供了很多的類型

char(n):字元長度為n,不足部分以空格補齊

varchar2(n):變化長度的字元串,根據實際占用配置設定空間

number(n, m):n表示資料的總長度,m表示小數位數

date:日期類型,包含日期和時分秒

等等,上面是常用的

使用OEM建立表

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937382lA0B.png"></a>

表的具體定義選項

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937382FiGi.png"></a>

存儲相關資訊

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373828f3Q.png"></a>

表空間:這個表對與DML語句是否啟用日志

區數:表的初始區的大小,預設值就是表所在的表空間上所設定的區大小

空間使用情況:資料塊在剩餘空間&amp;gt;10%的時候,可以繼續insert,當小于10%的時候,不能繼續insert,剩餘空間留給update

事務處理數:該表的資料塊頭部ITL槽的個數和最大個數

緩沖池:表屬于哪個緩沖池

因為表空間啟用了ASSM,是以沒有參數pctused

pctused表示當資料塊的剩餘。40%的時候,資料塊可以重新insert

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937383w82A.png"></a>

這個表的建立SQL

資料行在資料塊裡的結構

資料行頭部——列長度——列值

1、資料行的頭部

每一個資料行都有一個行頭部,在這裡存放了該行資料所包含的列的數量、鎖定标記

當某個事務更新某條記錄的時候,會在該資料行的頭部記錄所使用的ITL槽号以及鎖定标記

2、列的長度和列的值,每個列之間沒有空隙,都是緊密排列

3、不同的資料行之間也沒有空隙,緊密排列

資料塊的頭部有一個結構:行目錄,在行目錄中,為每條資料行都記錄了一個條目,每個條目就指向該記錄的行頭部,是以Oracle能夠區分不同的行

每一條記錄都有一個ROWID列,這是一個僞列。該列的值并沒有實際的儲存在資料塊裡面,但是可以顯示和查詢。

Oracle 10g中,rowid列的格式是

OOOOOOFFFBBBBBBRRR

OOOOOO表示該資料行所在的對象名,一般都是表名

FFF表示該資料行所在的相對檔案号

BBBBBB表示該資料行所在的資料塊号

RRR表示該行在資料塊中的行号

ROWID采用的是64進制

A-Z 0-25

a-z 26-51

0-9 52-61

/ 62

+ 63

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937383JUrv.png"></a>

對象号:0+0+0+2*64^2+44*64^1+61*64^0=11069

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937384rWmI.png"></a>

檔案号:0+0+4*64^0=4

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937384OOc2.png"></a>

資料塊号:0+0+0+0+7*64^1+29*64^0=477

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937385jruU.png"></a>

行号:0+0+0

管理表的主要工作

擴充表

1、主動地擴充一個表所占用的空間(就是給表配置設定一個extent)

2、将一個表配置設定到多個資料檔案上,實作IO均衡

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937385xxQ1.png"></a>

主動的給表配置設定一個extent,在目前的資料檔案裡配置設定。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937385QRla.png"></a>

将表配置設定到指定的檔案上,實作負載均衡。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937386yIEe.png"></a>

重整表

将一個表從目前的表空間轉移到另外一個表空間中去,或者消除表的資料塊級别的碎片

資料塊級别的碎片指的是每個資料塊裡含有的資料行太少了,例如100條記錄分布在100個資料塊中,這種表稱為稀疏表

稀疏表産生的原因

該表上存在很多的insert、delete

表的segment header裡記錄了一個值,叫高水位标記(HWM high water mark)

HWM表示目前segment裡使用的最後一個資料塊的位置,當發生insert時,extent不斷的配置設定,HWM不斷的增長

HWM最典型的好處就是select count(*)的時候,引起表掃描,伺服器程序在掃描資料塊的時候,隻掃描到HWM為止,因為HWM後面不會有segment的資料塊

當delete發生的時候,HWM不會下降的,即使表裡面的資料全部删除,HWM也不會下降,這勢必會影響select count(*)的性能

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373865o8t.png"></a>

這個表裡面的資料排列不夠緊密,我們需要重新整理一下資料行在資料塊裡的分布,使其分布的緊密一些。即節省了空間,又提高了select的速度

10g以前,我們隻能使用move或者導入導出的方式對表進行重整,達到降低HWM的目的,10g以後可以使用shrink對表進行收縮

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937387y3uN.png"></a>

這個表占用了52個資料塊。删除最後的五千行資料以後,還是占用了52個資料塊。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373878YCw.png"></a>

資料表遷移到另外一個表空間以後,重新進行了整理。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937387KjCo.png"></a>

表占用的資料塊明顯減少。

注意:表進行move以後,表上的所有索引失效,需要重建。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937388HQ5x.png"></a>

可以為了碎片整理,減低HWM,在表空間内部進行move。

對于消除資料塊級别的碎片來說,Oracle10g之前采用了move、exp/imp的方式進行解決。當時都會停止應用。

Oracle 10g開始采用了shrink技術

Shrink是通過事務的方式将資料行從一個資料塊轉移到另一個資料塊。收縮過程中,表仍然可以進行DML操作

當然,事務要能夠進行DML操作,還是需要等待收縮引起的事務鎖釋放。

收縮雖然是事務,但是資料并沒有發生變化,是以不會引起觸發器的觸發。

使用shrink的前提條件

1、表所在的表空間必須使用ASSM(自動段空間管理)

2、在收縮表上必須啟用row movement選項

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937388rcGX.png"></a>

兩個條件都具備了。可以對表進行收縮。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373892E7u.png"></a>

為test3表添加一些資料并删除,以示範收縮

收縮操作分為兩個階段

1、壓縮

2、降低HWM

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937389ytc7.png"></a>

可以分開兩個階段進行執行,業務運作期間執行第一個階段,業務不繁忙或者停止的時候,進行第二個階段。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937390WUvz.png"></a>

如果表上有相關的對象,例如索引,該如何收縮?

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937390EsEq.png"></a>

我們不太清楚哪些表需要進行收縮,該如何?使用segment advisor

可以對整個的表空間,也可以對具體的對象進行分析。

截斷表

删除記錄可以采用delete,delete是DML事務,對表的記錄加鎖,産生重做日志,消耗undo空間,消耗資源較多,執行時間較長

對于大表資料,我們建議采用truncate

Truncate是一個DDL語句,隻更新資料字典

将資料字典裡面該表所占用空間記錄全部删除

将表所占用的資料塊全部釋放

将HWM下降到最低

因為是DDL,執行完畢就不能復原

問題

如果需要截斷的表達到幾十個GB,那麼釋放資料塊的工作可能會花費很長的時間(可能超過10個小時),在這個過程中,被截斷的表是不能被使用的。

截斷并不意味着drop,是以我們還是需要使用這些表

如何解決,10g中給出了解決方案

1、更新完成資料字典以後,不立即釋放全部資料塊(這個操作花費時間多)

2、資料塊沒有釋放,仍然被表所擁有,但是表上的HWM已經下降到最低了

3、系統空閑的時候,分多次釋放資料塊,每次釋放部分空間

這樣truncate就能将對系統的影響降到最低

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937390rqyM.png"></a>

隻是更新了資料字典,降低了HWM,資料塊并沒有實際的釋放。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373916dq4.png"></a>

檢視所占用的塊

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937391i5P4.png"></a>

資料庫可以正常的使用。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373922rzo.png"></a>

将表的空間釋放到1m,可以看到收縮了一些塊

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373929DtT.png"></a>

雖然将表的空間釋放到0m,但是表中已經添加了資料,是以沒有完全釋放。通過上面的方式,我們可以階段性的釋放資料塊。

删除表的操作

1、删除表的操作屬于DDL指令,也就是隻是更新資料字典資訊,資料字典資訊存在system表空間中,是以即使表屬于隻讀表空間中,也能删除表

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937392FyFD.png"></a>

2、如果這個表是其他表的父表,或者說其他表上有外鍵引用了這個表,删除這個表的時候,需要加上參數cascade constraint,删除主表以後,引用這個表的外鍵也被删除。(外表并沒有被删除,删除的隻是外鍵)

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937393fmfY.png"></a>

建立一個表testdrop

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937393Y5X8.png"></a>

對一個列名進行修改

資料一緻性問題

為了更好的提供資料的一緻性,Oracle提供了限制

Oracle提供了5種限制

1、非空not null,在列上定義,該列必須有值

2、唯一unique,在列上定義,不同的資料行上,該列的值不能重複,唯一限制是借助索引建立的,建立唯一限制的時候,如果該列上沒有索引,那麼就建立一個唯一索引

3、主鍵primary key,在列上定義,和唯一鍵唯一的不同之處就是不能為空,unique列上可以有多個null,主鍵也是借助索引建立的

4、外鍵foreign key,發生在兩個表之間,外鍵在子表上定義,但是引用(參考)了父表的列,被引用的父表上的列必須有主鍵或者唯一鍵

5、檢查check,在表上定義,類似于where條件,表裡所有的記錄必須滿足指定的條件

建議:對于資料一緻性問題,限制能夠實作的,盡量在資料庫裡面實作,不要放在應用裡面實作,主要是為了集中實作。

限制的狀态

enable和disable狀态:建立限制以後,對表的資料進行插入或者修改時,是否進行校驗

validate和novalidate狀态:建立限制時,是否對表裡現存的資料進行校驗

我們看一下組合情況

1、enable+validate:既要校驗已經存在的資料,也要校驗新進入的資料

2、enable+novalidate:不校驗已經存在的資料,隻校驗新進入的資料

3、disable+validate:一種沖突的狀态,有這種限制的表不能進行DML

4、disable+novalidate:相當于沒有建立限制

1和 2使用的最多,建立限制以後,對新進入的資料就要使用限制,對于已經存在的資料,有的情況下進行校驗,有的情況下,不進行校驗

在對表進行建立或者編輯的時候,可以建立限制。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937394qW7W.png"></a>

1、禁用:是否對新加入的資料啟用限制

2、驗證:是否對已有資料進行校驗

3、可延遲:後面會詳細的講,這個涉及到一個限制啟用時機的問題

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937394LM3I.png"></a>

建立了一個表,這個表上建立了一個主鍵限制。

我們可以對這個主鍵限制進行enable、validate、disable、novalidate的選擇

我們還可以修改這個限制的名字,這個特性是從9i R2開始

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373945ZfV.png"></a>

限制校驗資料的時機

預設情況下,一旦發生DML操作,Oracle會立即判斷變化後的資料是否違反了限制,如果違反,立即復原該DML所進行的修改

我們還可以選擇:限制在事務送出的時候進行校驗,這叫做延遲限制(deferred constraint)

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937395O4IT.png"></a>

建立表sales,檢視一個限制的觸發。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937395hcZW.png"></a>

注意:復原隻是復原引起限制沖突的這條語句的修改。對于已經實行的操作,不會進行復原。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937396DTAu.png"></a>

表示可延遲,但是預設是initially immediate,發生DML操作立即校驗資料。

事務送出時進行校驗

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937396GO9B.png"></a>

插入一條資料,隻有在送出的時候才會觸發延時限制

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937396Cb5s.png"></a>

如果隻是定義了這個限制的deferrable屬性,表示可延遲,預設是immediate,馬上進行校驗。有什麼意義呢?

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937397OYva.png"></a>

這個會話涉及的所有的表,隻要是定義了deferrable屬性的限制,全部都延遲校驗。

分區表

上千萬條記錄的表,稱之為大表,在管理和性能上會有問題,如何解決?

1、一個非常大的表分布在不同的磁盤上,如果其中一塊磁盤壞了,就會導緻整個表的資料丢失

2、對大表進行資料遷移,即使隻是對部分資料進行遷移,也必須以整個表為機關進行操作

3、從上千萬條的表中檢索資料,花費的時間會很多

Oracle引入了分區表的概念

1、分區表是多個小表的組合,每一個小表叫做一個分區

2、資料存放在分區裡面,每個分區對應一個實體的segment

3、不同的分區可以具有不同的存儲屬性,可以存放在不同的表空間中

4、分區表的總表是一種虛表,沒有對應的segment,分區表具有多個segment

5、邏輯上是一個表、相同的列、相同的限制

改進

1、不同的分區放在不同的磁盤上,既是一個磁盤損壞,隻有這個損壞磁盤上的資料不能通路,其他資料還是能夠通路

2、可以以分區作為機關進行備份、遷移時直接将分區裡面的資料與其他表進行遷移

3、性能上,如果以列c1建立的分區,那麼當where條件中使用c1的時候,資料庫自動判斷,直接到該分區裡面檢索資料,不需要對整個表進行掃描

1、範圍分區

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937397GK7h.png"></a>

maxvalue這個有必要定義,否則當插入的資料大于2012-12-21的時候,就會報錯(世界末日^_^)。

2、Hash分區

對列的值進行hash函數的運算以後,分布到分區裡面,這樣做的最大的好處就是能夠實作分區資料的平均分布,我們在定義分區的時候,分區的個數應該是2的幂,例如2,4,8,16,否則出現資料分布不平衡,失去了hash分區的意義

當列中的數值不容易劃分範圍的時候,我們可以使用hash分區

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373987hZh.png"></a>

3、清單分區

分區列的取值是一些指定的離散值的時候,該資料行就進入某個指定的分區

4、範圍hash組合分區

1、首先根據範圍進行劃分,然後将每個範圍劃分的資料進行hash分區,分布到不同的hash子分區上,範圍分區以後,并沒有産生segment,對範圍進行hash的時候,才會産生實實在在的segment

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373988GZc.png"></a>

1、根據範圍對表進行了範圍劃分,分成4個區。

2、對每個區的hash劃分預設是根據id,分成4個分區

3、pmax分區沒有使用預設值,而是分成了2個分區

是以一共産生了14個分區。

5、範圍清單組合分區

首先對列進行範圍劃分,然後對每個分區進行清單分區

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359373989Twb.png"></a>

一共是6個分區

p1_1、 p1_2在ts01上

p1_3在ts02上

p2_1、 p2_2在ts03上

p2_3在ts04上

索引組織表

一般的表都是以堆來組織的,這是一種無序的組織方式。Oracle還提供了另外一種有序的表,索引組織表,簡稱IOT

IOT表上必須有主鍵,表裡所有的資料都存放在主鍵所在的索引的葉子節點裡

在索引葉子節點裡的索引條目裡,不僅存放了被索引的列的值,還存放了其他列的值

對于總是通過主鍵通路資料的表來說,比較适合使用IOT表

普通表通過主鍵索引通路資料表,至少讀取兩個資料塊

1、索引塊

2、表的資料塊

IOT表

隻要讀取索引塊就可以

IOT是一個虛表,實際存放在索引segment裡

在IOT的基礎上建立索引,叫做二級索引,使用二級索引查找資料,存在兩個階段

1、在二級索引裡面存儲的是邏輯ROWID,就是主鍵值

2、二級索引進行查找的時候,首先是根據二級索引查找到邏輯ROWID,因為邏輯ROWID就是主鍵值,是以還需要進行一次二次查找,根據主鍵值再進行一次索引查找。

也就是二級索引最終還是要轉化成對主鍵列的查找

二級索引裡面存儲的是邏輯ROWID、不是實體ROWID

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937399LyDJ.png"></a>

1、必須建立一個主鍵限制

2、指定索引組織表的方式

如果pctthreshold限制的列是c1開始後面的列,但是including限制的列是c2開始後面的列,那麼以pctthreashold為準

如果我們在通路IOT表的時候,經常通路id和c1兩個列,如果把c2、c3、c4也放在索引的葉子節點裡面,那麼會造成索引葉子節點的增多,單個葉子節點裡面的行數減少,這樣通路索引的速度就會降低。是以我們希望後面的三個列不要放在索引的葉子節點裡面,而是放在溢出segment裡面

通過兩個參數來指定

1、留在索引塊裡面的資料空間占總資料塊大小的百分比,0-50%,id列+c1列總共占的位元組數/索引塊的大小,超出這個範圍的列不放在索引塊裡面

2、表示從c2開始,後面所有的列都放在overflow segment裡面,不放在索引塊裡面

簇表(cluster table)

兩種類型的簇表:索引簇表、hash簇表

索引簇表的經典用法

1、主名細表關連查詢,主表和明細表經常進行關連查詢,适合使用這種表結構

2、建立一個 cluster segment,segment裡面有extent,extent裡面有block

3、簇表的資料就是存放在cluster segment裡面

4、因為表并沒有segment,是以是一個虛表

5、在cluster segment上面建立索引(主表和明細表的關聯鍵)

6、将表關聯到cluser segment上,根據關聯鍵,将主表和明細表的記錄放在同一個資料塊裡面。

7、因為總是關連查詢,是以隻要掃描一個資料塊就可以取到兩個表的資料

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937399qcEi.png"></a>

建立一個聚集段

在關聯鍵上建立索引

将表建立到聚集索引上

Hash 簇表

1、一個hash簇隻能關聯一個表

表有一個簇列,表在插入segment的時候,對簇列進行hash運算,得到一個該記錄所在的資料塊的位置

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359374002s3T.png"></a>

表示phone_no的值最多不超過10000個

對于每一個hashkeys值所對應的所有記錄行來說,在segment頭部都會有一塊空間,來存放這些資料行的位址,size表示每個hashkeys 所能使用的空間大小,上面是50個位元組。

臨時表

1、臨時表所存放的資料都是臨時使用的,這些資料用完以後就可以删除

2、臨時表的資料被session所專用

同一個臨時表,多個用戶端使用,用戶端将資料暫存在臨時表裡面

用戶端隻對自己的資料進行處理,互相之間并不影響

因為臨時表内的資料不共享,被session所占用,是以沒有DML鎖

Oracle能夠自動清除臨時表裡的資料

1、退出session的時候,也就是使用者中斷資料庫連接配接的時候,自動清除與該session相關的,位于臨時表裡的資料,通過on commit preserve rows指定

2、使用者送出或者rollback時,自動清除與該session相關的,位于臨時表裡的資料,通過on commit delete rows指定

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359374009J1d.png"></a>

建立兩個臨時表,分别使用兩種不同的模式

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937400qoWZ.png"></a>

上面是在session A裡面

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937401HBgq.png"></a>

另起一個session,看不見另一個session的資料。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937402GKNU.png"></a>

臨時表裡的資料都是存放在臨時表空間裡面

目前正在使用臨時表空間的session資訊

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359374029K4G.png"></a>

Session A裡面

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937403LpvK.png"></a>

Session B裡面

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937403HzCl.png"></a>

臨時表所占的區與塊的情況

索引

索引的主要目的就是提高查詢速度,分為B樹索引和位圖索引

B樹索引(平衡樹索引)

1、索引也屬于一種segment,裡面存放了使用者資料,與表一樣需要占用空間

2、索引裡面的資料存放形式和表不一樣,是有序排列的

3、索引占用的空間比表小得多,主要作用是為了加快對資料的搜尋速度,也用來保證資料的唯一性

4、索引對DML操作會産生額外的負擔

索引分為很多種

分區索引、非分區索引、正常B樹索引、位圖索引、反轉索引

B樹索引是最常見的索引

B樹索引是一種典型的樹結構,而且是一顆平衡樹

1、葉子節點(leaf node):包含的條目中具有指針,指向表裡的資料行,葉子節點之間互相指向,隻要表裡的記錄行中,被索引的列的值不為空,就會在索引葉子節點裡存在一個索引條目,如果被索引的列的值為空,則不會在葉子節點中存放對應的條目

(屬于表的資料塊裡的資料叫做資料行,屬于索引的資料塊裡的資料叫做索引條目)

2、分支節點(branch node):包含的條目指向索引裡其他的分支節點或者葉子節點

3、根節點(root node):一個B樹索引值有一個根節點,位于樹的頂端的分支節點

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937404ef5b.png"></a>

一個索引條目由兩個字段組成

第一個字段表示目前該分支節點塊下所連結的索引塊中所包含的最小值

第二個字段4個位元組,表示所連接配接的索引塊的位址,該位址指向下面所連結的索引塊

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937404lr3m.png"></a>

根索引塊中包含三個索引條目,分别指向三個下級索引塊

注(分支索引塊中的一個索引條目指向一個下級索引塊,葉子索引塊中的一個索引條目指向一條表記錄)

1、0表示這個索引條目指向的下級索引塊的最小值是0

2、B1指向這個索引條目所指向的下級索引塊的位址

3、L1中的0就是一個鍵值,R1是0這個鍵值指向的資料行的實體ROWID

如何估算每個索引能夠包含多少條目,以及對于表來說,能産生索引的大小

我們最好在收集表的統計資訊的時候,同時收集索引的統計資訊。看一下索引一共占用了多少資料塊。

B數索引的管理機制

管理分為兩種情況

1、在一個充滿了資料的表上建立索引時,索引是怎麼管理的?

Oracle會掃描表裡的資料,并對其進行排序,然後生成葉子節點,生成所有的葉子節點以後,根據葉子節點的數量生成若幹層級的分支節點,最後生成根節點

2、建立索引以後,一行接着一行向表裡插入或者更新或者删除資料,索引是怎麼管理的?       

1、當一開始在一個空的表上建立索引的時候,該索引沒有根節點,隻有一個葉子節點

2、随着資料不斷的插入表裡,該葉子節點的索引條目也在不斷的增加

3、當該葉子節點充滿索引條目而不能再放下新的索引條目時,該索引就必須擴張,也就是在擷取一個可用的葉子節點,這個過程叫做索引的拆分(split)

4、索引包含了兩個葉子節點,兩個葉子節點需要一個上級的分支節點,于是索引就有了三個索引塊(一個根和兩個葉子)

葉拆分的兩種情況

葉子節點的拆分分為兩種情況

1、一種是插入的鍵值不是要插入的索引塊裡包含的最大值

2、另一種是插入的鍵值是要插入的索引塊裡包含的最大值

第一種情況:當一個非最大值要進入索引,但是發現所應進入的索引塊不足以容納目前鍵值,Oracle會按照以下步驟進行葉子節點的拆分

1、獲得一個新的可用的索引資料塊

2、将目前充滿了的索引塊中的索引條目分成兩部分,一部分是具有較小的鍵值、另外一部分是具有較大的鍵值,Oracle将具有較大鍵值的部分移入新的索引資料塊,而較小鍵值的部分保持不動

3、将目前鍵值插入合适的索引塊中,可能是原來空間不足的索引塊,也可能是新的索引塊

4、更新原來空間不足的索引塊的指針資訊,使其指向新的索引塊(分支索引塊之間是雙向連結清單)

5、更新位于原來空間不足的索引塊右邊的索引塊裡的指針資訊,使其指向新的索引塊

6、向原來空間不足的索引塊的上一級分支索引中添加一個索引條目,該索引條目中儲存新的索引塊裡的最小值,以及新索引塊的位址

對于第二種情況,也就是插入鍵值是要插入索引塊裡包含的最大值時

分裂過程相對簡化,不再進行上面第二步中索引塊的分裂,直接将新的索引條目插入新的索引塊中

當葉子節點越來越多,導緻原來的根節點不足以存放新的索引條目的時候,則該節點就必須進行分裂,根節點的分裂流程如下

1、從索引段的可用清單上獲得兩個新的索引資料塊

2、将根節點的索引條目分成兩個部分,這兩部分分别存放在兩個新的索引塊中,進而形成了兩個新的分支節點

3、更新原來的根節點的索引條目,使其分别指向這兩個新的索引塊中

這時索引層次變成了兩層,根節點索引塊在實體上始終都是同一個索引塊,而随着資料量的不斷增長,導緻分支節點又要進行分裂,分支節點的分裂過程與根節點類似步驟如下

分支節點的分裂

1、從索引可用清單上多的一個新的索引資料塊

2、将目前用滿了的分支節點裡的索引條目分成兩個部分,較小鍵值的部分不動,而較大鍵值的部分移入新的索引塊

3、将新的索引條目插入合适的分支索引塊中

4、再上一層分支索引中添加一個新的條目,使其指向新加的分支索引

分支索引和根節點會随着資料量的增加繼續拆分,步驟同上

根節點分裂以後,索引的層次增加,根據索引的分裂機制來看,一個B樹索引始終都是平衡的,平衡指的是每個葉子節點與根節點的距離是相等的

當插入的鍵值始終都是增大的時候,索引總是向右擴充

當插入的鍵值始終都是減小的時候,索引總是向左擴充

删除表的操作,對索引的影響如下

1、當删除表裡的一條記錄時,其對應于索引塊裡的條目并不會被實體的删除,隻是做了一個删除标記

2、當一個新的索引條目進入一個索引葉子節點的時候,Oracle會檢查該葉子節點裡是否存在被标記為删除的索引條目,如果存在,則會将所有具有删除标記的索引條目從該葉子節點裡實體的删除,避免葉拆分

3、當一個新的索引條目進入索引時,Oracle會将目前所有被清空的葉子節點收回(該葉子節點中所有的索引條目都被标記為删除),進而再次成為可用索引塊

盡管被删除的索引條目所占用的空間大部分情況下都能夠重新使用,但是仍然存在一些情況可能導緻索引空間被浪費,并造成索引資料塊很多,但是索引條目很少的情況,這時該索引可以被認為出現碎片

導緻索引出現碎片的情況主要包括以下幾種

1、不合理的較高的PCTFREE

2、索引鍵值持續增加(例如使用sequence生成序列号的鍵值),同時對索引鍵值按照順序連續删除,這時可能導緻索引碎片的發生

原因:某個索引塊中删除了部分的索引條目,隻有目前鍵值進入該索引塊的時候才能将空間收回,而持續增加的索引值永遠隻會插入排在前面的(右面)的索引塊中,索引空間幾乎不能回收

3、經常被删除或者更新的鍵值,以後幾乎不再會被插入,情況同上

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_133593740559DP.png"></a>

如果這個值小于50%,那麼就認為存在明顯的碎片。

更新對索引條目的影響,可以認為是delete和insert的組合。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_13359374058jGK.png"></a>

補充一點:

雙向連結清單的作用

如果一個以範圍作為查詢條件的查詢,例如20&amp;lt;c1&amp;lt;30,那麼首先找到鍵值20,然後沿着20一直向上找,一直找到30為止,整個的路線是沿着雙向清單,而不需要重複的回到根節點。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937406VsCg.png"></a>

位圖索引:組織形式和B樹索引相同,也是一顆平衡樹

B樹索引在葉子節點裡為每一個鍵值維護一個索引條目

位圖索引的特點

應用場合:作為索引的列的值隻有少數的幾個

如上圖

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937406KOXx.png"></a>

1、表T裡所有的記錄在列c1上隻具有三個值:01、02、03

2、在c1上建立了位圖索引

3、葉子節點中,隻有三個索引條目,每個c1列的值對應一個索引條目

4、位圖索引條目中還包含表裡第一條記錄所對應的ROWID以及最後一條記錄所對應的ROWID

5、索引條目的最後一部分則是由多個bit位組成的bitmap,每個bitmap對應一條記錄,這個表一共19條記錄

6、因為列的值就三種,是以三個位圖加起來就是19個1

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937407kdjl.png"></a>

當發出where c1=’01’這樣的sql 語句的時候,Oracle會搜尋01所在的索引條目

然後搜尋該索引條目中的bitmap裡所有bit位,第一個bit位為1,則傳回第一條記錄所在的ROWID(根據索引條目所對應的 start ROWID加上行号得到該記錄所在的ROWID),第二個bit為0,則說明第二條記錄上的c1值不為0,如果索引為空,也會在位圖索引裡記錄,相應值為0

如果索引列上不同值的個數比較少的時候,例如性别,使用位圖索引效果很好

如果在主鍵上建立位圖索引,效果不如B樹

如果位圖索引經常被更新的話,不适合位圖索引,因為更新一個條目以後,需要在兩個位圖索引條目上同時更新,會鎖定兩個索引條目,降低了并發性

位圖索引比較适合資料倉庫,不适合OLTP

管理索引

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937407DWrW.png"></a>

建立索引

重建索引

重建索引有兩種方式

1、drop + create

2、alter index ….rebuild

第二種方式的好處

1、使用原索引的葉子節點作為新索引的資料來源

索引資料塊相對表資料塊來說要少很多,是以減少了IO

原索引葉子節點已經排好序,是以節省了排序的工作

2、8.1.6開始,rebuild的時候,可以加上online,索引重建過程中,使用者可以繼續對原來的索引進行修改,也就是說可以繼續對表進行DML操作

兩種方式的相同之處

1、他們都可以通過添加PARALLEL提示進行并行處理

2、都以通過添加NOLOGGING,使的索引的重建生成最少的日志條目

3、8.1.5開始,就可以通過添加compute statistics選項,在重建索引的過程中就生成Oracle優化器所需要的統計資訊

重建索引的好處:減少了索引所占用的空間,索引塊減少以後的好處如下

1、索引掃描的實體塊數減少

2、記憶體占用減少

索引會加重DML的負擔

1、每添加一個索引,DML語句的響應時間增加三倍

2、Oracle建議每個表上的索引不要超過7個

3、查詢如果不怎麼使用索引,那應該删除這個索引

Oracle提供了一種方法,用來監控某個索引是否被使用過

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937408bqAi.png"></a>

在監控的這段時間内,索引沒有被使用過。

視圖

可以把視圖了解為給一條SQL語句起了個名字,這個名字就是視圖名字,使用視圖的好處如下:

1、可以屏蔽SQL語句的複雜性,使用一個視圖的名字就可以代表一個複雜的SQL

2、可以管理權限,不同的使用者建立不同的視圖,通路的列不同,達到控制通路的目的

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/2/1293914_1335937408M3QC.png"></a>

本文轉自bear_cat51CTO部落格,原文連結:http://blog.51cto.com/bearlovecat/850056 ,如需轉載請自行聯系原作者