1. 程式人生 > >堆組織表,索引組織表和索引聚簇表

堆組織表,索引組織表和索引聚簇表

卸載 對比 影響 partition 重新登錄 一個數 struct 可變 cal

---

堆組織表就不說了,其索引中記錄了記錄所在位置的rowid,查找的時候先找索引,然後再根據索引rowid找到塊中的行數據

索引組織表,其行數據以索引形式存放,因此找到索引,就等於找到了行數據。

--

堆組織表的數據是散放的,索引和表的數據是分離的

索引組織表的索引和數據是在一起的

--

堆組織表的存儲速度因為不用考慮排序, 所以存儲速度會比較快. 但是要查找符合某個條件的記錄, 就必須得讀取全部的記錄以便篩選.
而這個時候為了加快查詢速度, 索引就出現了, 索引是針對少量特定字段的值拿出來進行排序存儲, 並記錄在表中的位置,
而因為索引是有序的, 所以就會很容易通過索引查詢到具體的記錄位置, 然後再根據記錄位置直接從表中讀取該記錄.
同時因為索引的字段較少, 所以索引通常會比其基表小得多.

從上面通過索引訪問表記錄的方式可以看出, 當要訪問的數據量較大時, 通過每一條記錄的位置去訪問原始記錄,
每一條符合條件的記錄都需要經過索引訪問後再訪問基表這樣一個復雜的過程, 這會花費很多時間,
同樣, 如果不經過索引而直接查詢表, 也可能因為表字段太多, 記錄較大的情況下把全部的數據讀取進來, 這也會花費很多時間.

那怎麽辦呢?
這個時候就會想到, 如果表中數據本身就是有序的, 這樣查詢表的時候就可以快速的找到符合條件的記錄位置,
而很容易判斷符合條件記錄的位置, 這樣只需要讀取一小部分數據出來就可以了, 不需要全表記錄都讀取出來進行判斷.
索引表就這樣產生了.當然索引表中插入,更新資料的時候可能會因為需要排序而將數據重組, 這時候數據插入或更新速度會比堆組織表慢一些.
如果堆組織表上有索引, 那麽對堆組織表的插入也會因為要修改索引而變慢

我們可以看到堆組織表+索引的方式 與 索引表 都能夠實現數據的快速查找, 那為什麽不全部采用索引表呢, 這樣不是很簡單嗎?
我能想到的是前者我們可以針對不同的查找條件建立多個索引, 而後者卻不行, 後者只能對某一組查詢條件有效.

--

堆組織表(heap organized table)

Oracle中有很多類型的表,像堆組織表、索引組織表、索引聚簇表等等。首先,我將從最基本、最常用的堆組織表(heap organized table)介紹。

通常我們默認建的表就是堆組織表。語法(詳細語法請參見Oracle官方文檔)如下:

  1. Create table test(
  2. Id int,
  3. Name varchar2(10)
  4. );

數據會以堆的方式管理,增加數據時,會使用段中找到的第一個能放下此數據的自由空間。當從表中刪除數據時,則允許以後的INSERT和UPDATE重用這部分空間。它是以一種有些隨即的方式使用。

很多初學者會想當然的以為數據的插入會按順序進行,第一條肯定排在第一位,接著是第二條,一直到最後。可當SELECT查詢的時候,返回的結果往往讓人失望。排列的順序讓人大跌眼鏡,下面來看一個例子。

  1. create table t
  2. (
  3. a int,
  4. b varchar2(4000) default rpad(‘*‘, 4000, ‘*‘),
  5. c varchar2(3000) default rpad(‘*‘, 3000,‘*‘)
  6. );
  7. insert into t(a) values (1);
  8. insert into t(a) values (2);
  9. insert into t(a) values (3);
  10. delete from t where a=2;
  11. insert into t(a) values (4);
  12. SQL> select a from t;
  13. A
  14. ----------
  15. 1
  16. 4
  17. 3

全 表掃描時,會按命中的順序來獲取數據,而不是按插入的順序。這是一個必要要了解的重要的數據庫概念。一般來說,數據庫表本質上是無序的數據組合。還有一種 情況,如果我插入一個小行,其後是一個非常大的行,而且這個大行與小行是無法放在同一個塊上的,然後又插入一個小行,那麽觀察到的結果很可能是“小行,小 行,大行”。

----

索引組織表
An index-organized table has a storage organization that is a variant of a primary B-tree. Unlike an ordinary (heap-organized) table whose data is stored as an unordered collection (heap), data for an index-organized table is stored in a B-tree index structure in a primary key sorted manner. Besides storing the primary key column values of an index-organized table row, each index entry in the B-tree stores the nonkey column values as well

索引組織表有一個可變的主B樹存儲組織。不象普通表(堆組織),數據是無序存儲的集合。
索引組織表是以主鍵排序的方式的B樹組織結構。
***

heap table 就是一般的表,獲取表中的數據是按命中率來得到的。沒有明確的先後之分,在進行全表掃描的時候,並不是先插入的數據就先獲取。數據的存放也是隨機的,當然根據可用空閑的空間來決定。
而iot 就是類似一個全是索引的表,表中的所有字段都放在索引上,所以就等於是約定了數據存放的時候是按照嚴格規定的,在數據插入以前其實就已經確定了其位置,所以不管插入的先後順序,它在那個物理上的那個位置與插入的先後順序無關。這樣在進行查詢的時候就可以少訪問很多blocks,但是插入的時候,速度就比普通的表要慢一些。
適用於信息檢索、空間和OLAP程序。索引組織表的適用情況:
1、 代碼查找表。
2、 經常通過主碼訪問的表。
3、 構建自己的索引結構。
4、 加強數據的共同定位,要數據按特定順序物理存儲。
5、 經常用between…and…對主碼或唯一碼進行查詢。數據物理上分類查詢。如一張訂單表,按日期裝載數據,想查單個客戶不同時期的訂貨和統計情況。
經常更新的表當然不適合iot,因為oracle需要不斷維護索引,而且由於字段多索引成本就大。 **** 八樓的說的很對,因為索引組織的表數據所有字段都是根據索引組織的,因此每次插入都需要排序然後重新組織表結構,所以插入很慢,因此不適宜使用頻繁改動的表(除非你希望每次插入都表根據索引鍵排序),但是由於數據全再索引上,因此索引已經將表排序好,所以訪問的時候比較快(比訪問普通索引快的原因是普通索引找到值後還要指向數據所在的塊),並且,由於索引組織的表相同的索引鍵列中的內容放在一起,對於讀取訪問的塊數也要少不少。
當然索引組織表對全表掃描不排序沒什麽好處。對不按照索引鍵訪問的表也沒什麽好處。 *******************************************************

索引

索引是與表關聯的可選結構.可以明確地創建索引,以加快對表執行SQL語句的速度.合理使用索引是減少磁盤I/O的主要方法.索引包括以下幾種類型:
1.標準索引.
語法:
create index 索引名 on 表名(字段名)
實例如下:
create index ind_ename on emp(ename)
2.唯一索引.主鍵上會自動創建唯一索引.唯一索引確保在定義索引的列中,表的任意兩行的值都不相同.
語法:
create unique index 索引名 on 表名(字段名)
實例:
create unique index ind_name on emp(ename)
3.組合索引,組合索引是在表中的多個列上創建的索引.
基於:select .... from table where ...and ... 此種多條件語句考慮建立組合索引
實例:
create index ind_name on emp(ename,sal)
4.反向鍵索引.此索引適合由序列組成的字段或者某數據分布密集的字段.
如:
原字段 反向鍵字段
1001 1001
1002 2001
1003 3001
1004 4001
是不是觀察到哪邊檢索得快些?對,就是左邊的反向鍵字段.
實例:
create index ind_empno on emp(empno) reverse
5.位圖索引.使用位圖索引的優點在於,它最適用於低基數列,也就是不同值的數目比表的行數少的列.如果某個列的值重復超過一百次,則可以考慮在該列上創建位圖索引.
實例:
create bitmap index in_deptno on emp(deptno)
6.基於函數的索引.
為了方便操作,oracle提供了一個選項,可以基於一個或多個列上的函數或表達式創建索引.
如下所示:
create index ind_sal on emp(lower(ename)) 必須註意的是,要創建基於函數或表達式的索引,必須具有query rewaite 系統權限.
7.索引組織表.
索引組織表與普通表不同之處在於,該表的數據存儲在與其關聯的索引中.對表數據進行的修改,如添加新行,更新新行或刪除行,只會導致索引的更新.索引組織表最大的優點,提高讀取速度,降低I/O讀寫.建立索引組織表必須有一列為主鍵.
實例如下:
create table ind_table
(
id number primary key,
name varchar2(20)
)
organization index;
OK,下面再來講講索引中的分區.
與對表進行分區類似,Oracle也允許對索引分區.與表分區一樣,索引分區可以存儲在不同的表空間中.索引分區有如下三種類型:
(1)局部分區
局部分區索引是在分區表上創建的一種索引,在局部分區索引中,Oracle為表的每個分區建立一個獨立的索引.
實例如下:
先創建一個分區表:
create table order_mast
(
order_id number(4),
order_name varchar2(20)
)
partition by range(order_id)
(
partition p1 values less than(1000),
partition p2 values less than(2000),
partition p3 values less than(maxvalue)
);
然後緊接著創建局部分區索引:
create index myindex on order_mast(order_id) local
(2)全局分區
全局分區是指在分區表或非分區表上創建的索引.全局索引的鍵可以引用存儲在多個分區中的行.合璧索引是自己分區.
實例如下:
create index glb_ind on order_mast(order_id) global
partition by range(order_id)
(
partition p1 values less than(1500),
partition p2 values less than(maxvalue)
);
(3)全局非分區,索引中不分區,與普通索引相同.在此不在舉例說明.

-------

1. 堆組織表:
通常我們默認建的表就是堆組織表。
語法:Create table test(
Id int,
Name varchar2(10)
);
此類型的表中,數據會以堆的方式進行管理,增加數據時候,會使用段中找到的第一個能放下
此數據的自由空間。當從表中刪除數據時候,則允許以後的UPDATE和INSERT重用這部分空間,
它是以一種有些隨機的方式使用。

很多初學者會想當然的以為數據的插入會按順序進行,第一條肯定排在第一位,接著是第二條,一直到最後。
可當SELECT查詢的時候,返回的結果往往讓人失望。排列的順序讓人大跌眼鏡,下面來看一個例子。

create table t(
a int,
b varchar2(4000) default rpad(‘*‘, 4000, ‘*‘),
c varchar2(3000) default rpad(‘*‘, 3000,‘*‘)
);

insert into t(a) values (1);
insert into t(a) values (2);
insert into t(a) values (3);
delete from t where a=2;
insert into t(a) values (4);

SQL> select a from t;

A
----------
1
4
3

全表掃描時,會按命中的順序來獲取數據,而不是按插入的順序。
這是一個必要要了解的重要的數據庫概念。一般來說,數據庫表本質上是無序的數據組合。

2. 索引組織表(index organized table, IOT):就是存儲在一個索引結構中的表,數據按主鍵進行存儲和排序。
適用的場景:
a.完全由主鍵組成的表。這樣的表如果采用堆組織表,則表本身完全是多余的開銷,
因為所有的數據全部同樣也保存在索引裏,此時,堆表是沒用的。
b.代碼查找表。如果你只會通過一個主鍵來訪問一個表,這個表就非常適合實現為IOT.
c.如果你想保證數據存儲在某個位置上,或者希望數據以某種特定的順序物理存儲,IOT就是一種合適的結構。 IOT提供如下的好處:
·提高緩沖區緩存效率,因為給定查詢在緩存中需要的塊更少。
·減少緩沖區緩存訪問,這會改善可擴縮性。
·獲取數據的工作總量更少,因為獲取數據更快。
·每個查詢完成的物理I/O更少。
如果經常在一個主鍵或唯一鍵上使用between查詢,也是如此。如果數據有序地物理存儲,就能提升這些查詢的性能。
語法:create table indexTable(
ID varchar2 (10),
NAME varchar2 (20),
constraint pk_id primary key (ID)
) organization index;
3. 索引聚簇表:
聚簇是指:如果一組表有一些共同的列,則將這樣一組表存儲在相同的數據庫塊中;聚簇還表示把相關的數據存儲在同一個塊上。
利用聚簇,一個塊可能包含多個表 的數據。概念上就是如果兩個或多個表經常做鏈接操作,那麽可以把需要的數據預先存儲在一起。
聚簇還可以用於單個表,可以按某個列將數據分組存儲。
語法:
索引聚簇表是基於一個索引聚簇(index cluster)創建的。
裏面記錄的是各個聚簇鍵。聚簇鍵和我們用得做多的索引鍵不一樣,索引鍵指向的是一行數據,
聚簇鍵指向的是一個ORACLE BLOCK。我們可以先通過以下命令創建一個索引簇。
create cluster emp_dept_cluster
  ( deptno number(2) )
  size 1024
  /

size參數:
向聚簇中放數據之前,需要先對聚簇建立索引。可以現在就在聚簇中創建表,
但是由於我們想同時創建和填充表,而有數據之前必須有一個聚簇索引,所以我們先來 建立聚簇索引。
create index emp_dept_cluster_idx
  on cluster emp_dept_cluster
  /

建表:
create table dept
  ( deptno number(2) primary key,
dname varchar2(14),
   loc varchar2(13)
  )
  cluster emp_dept_cluster(deptno)
  /

create table emp
  ( empno number primary key,
ename varchar2(10),
job varchar2(9),
mgr number,
hiredate date,
sal number,
comm number,
   deptno number(2) constraint emp_fk references dept(deptno)
  ) cluster emp_dept_cluster(deptno)
/

什麽時候不應該使用聚簇?
1) 如果預料到聚簇中的表會大量修改:
必須知道,索引聚簇會對DML的性能產生某種負面影響(特別是INSERT語句)。管理聚簇中的數據需要做更多的工作。
  2) 如果需要對聚簇中的表執行全表掃描:不只是必須對你的表中的數據執行全面掃描,
還必須對(可能的)多個表中的數據進行全面掃描。由於需要掃描更多的數據, 所以全表掃描耗時更久。
  3) 如果你認為需要頻繁地TRUNCATE和加載表:聚簇中的表不能截除。
這是顯然的,因為聚簇在一個塊上存儲了多個表,必須刪除聚簇表中的行。

  因此,如果數據主要用於讀(這並不表示“從來不寫”;聚簇表完全可以修改),
而且要通過索引來讀(可以是聚簇鍵索引,也可以是聚簇表上的其他索引),
另外 會頻繁地把這些信息聯結在一起,此時聚簇就很適合。

-----------

表類型的定義
heap table 就是一般的表,獲取表中的數據是按命中率來得到的。沒有明確的先後之分,在進行全表掃描的時候,並不是先插入的數據就先獲取。數據的存放也是隨機的,當然根據可用空閑的空間來決定

將索引和表數據一起存儲在一個稱為“索引組織的表”(Index-Organized Table, IOT)的表中。使用IOT可以顯著地減少磁盤空間的使用,因為不需要存儲索引的列兩次(一次存在表中,一次存在索引中)。相反,只需將它們和其他任何非索引的列存儲在IOT中一次。IOT適用於基本的訪問方法是通過主鍵進行訪問的那些表,但允許在IOT的其他列上創建索引以改善通過這些列的訪問性能。 由於IOT中的整個行存儲為索引本身,因此沒有用於每個行的ROWID。主鍵用來標識一個IOT中的行。與此不同,Oracle根據主鍵的值來創建邏輯ROWID,邏輯ROWID用於支持IOT上的二級索引。此外,還可以對IOT進行分區。對於頻繁的插入操作的表。iot性能不好,在插入數據時,要尋找插入到那個塊,若塊的大小不足,需要放在溢出塊中,這些操作都需要消耗資源。索引組織表適合於應用中更改不頻繁,且訪問時大多數時候按某一主鍵訪問的字典。

而iot 就是類似一個全是索引的表,表中的所有字段都放在索引上,所以就等於是約定了數據存放的時候是按照嚴格規定的,在數據插入以前其實就已經確定了其位置,所以不管插入的先後順序,它在那個物理上的那個位置與插入的先後順序無關。這樣在進行查詢的時候就可以少訪問很多blocks,但是插入的時候,速度就比普通的表要慢一些。
適用於信息檢索、空間和OLAP程序。
因為索引組織的表數據所有字段都是根據索引組織的,因此每次插入都需要排序然後重新組織表結構,所以插入很慢,因此不適宜使用頻繁改動的表(除非你希望每次插入都表根據索引鍵排序),但是由於數據全再索引上,因此索引已經將表排序好,所以訪問的時候比較快(比訪問普通索引快的原因是普通索引找到值後還要指向數據所在的塊),並且,由於索引組織的表相同的索引鍵列中的內容放在一起,對於讀取訪問的塊數也要少不少。
當然索引組織表對全表掃描不排序沒什麽好處。對不按照索引鍵訪問的表也沒什麽好處。
索引組織表的適用情況:
1、代碼查找表。
2、經常通過主碼訪問的表。
3、構建自己的索引結構。
4、加強數據的共同定位,要數據按特定順序物理存儲。
5、經常用between…and…對主碼或唯一碼進行查詢。數據物理上分類查詢。如一張訂單表,按日期裝載數據,想查單個客戶不同時期的訂貨和統計情況。
經常更新的表當然不適合iot,因為oracle需要不斷維護索引,而且由於字段多索引成本就大。

An index-organized table has a storage organization that is a variant of a primary B-tree. Unlike an ordinary (heap-organized) table whose data is stored as an unordered collection (heap), data for an index-organized table is stored in a B-tree index structure in a primary key sorted manner. Besides storing the primary key column values of an index-organized table row, each index entry in the B-tree stores the nonkey column values as well


索引組織表有一個可變的主B樹存儲組織。不象普通表(堆組織),數據是無序存儲的集合。
索引組織表是以主鍵排序的方式的B樹組織結構。



IOT有什麽意義呢?使用堆組織表時,我們必須為表和表主鍵上的索引分別留出空間。而IOT不存在主鍵的空間開銷,因為索引就是數據,數據就是索引,二者已經合二為一。但是,IOT帶來的好處並不止於節約了磁盤空間的占用,更重要的是大幅度降低了I/O,減少了訪問緩沖區緩存(盡管從緩沖區緩存獲取數據比從硬盤讀要快得多,但緩沖區緩存並不免費,而且也絕對不是廉價的。每個緩沖區緩存獲取都需要緩沖區緩存的多個閂,而閂是串行化設備,會限制應用的擴展能力)

索引組織表屬性

1、OVERFLOW子句(行溢出)

因為所有數據都放入索引,所以當表的數據量很大時,會降低索引組織表的查詢性能。此時設置溢出段將主鍵和溢出數據分開來存儲以提高效率。溢出段的設置有兩種格式:

PCTTHRESHOLD n:制定一個數據塊的百分比,當行數據占用大小超出時,該行的其他列數據放入溢出段

INCLUDING column_name:指定列之前的列都放入索引塊,之後的列都放到溢出段

● 當行中某字段的數據量無法確定時使用PCTTHRESHOLD。

● 若所有行均超出PCTTHRESHOLD規定大小,則考慮使用INCLUDING。

Create table t88(

ID varchar2(10),

NAME varchar2(20),

Constraint pk_id primary key(ID)

)

Organization index

PCTTHRESHOLD 20

Overflow tablespace users

INCLUDING name;

● 如上例所示,name及之後的列必然被放入溢出列,而其他列根據PCTTHRESHOLD規則。

2、COMPRESS子句(鍵壓縮)

與普通的索引一樣,索引組織表也可以使用COMPRESS子句進行鍵壓縮以消除重復值。

具體的操作是,在organization index之後加上COMPRESS n子句

用於壓縮索引列,在塊級提取公因子,避免重復值。

如:create table iot(

owner, object_type, object_name,

constraint iot_pk primary key(owner, object_type,object_name)

Orgnazation index

NOCOMPRESS

);

表示對於每個主鍵組合都會物理地存儲。倘若使用COMPRESS N 則對於重復的列不再物理存儲,

● n的意義在於:指定壓縮的列數。默認為無窮大。

例如對於數據(1,2,3)、(1,2,4)、(1,2,5)、(1,3,4)、(1,3,5)時

若使用COMPRESS則會將重復出現的(1,2)、(1,3)進行壓縮

若使用COMPRESS 1時,只對數據(1)進行壓縮

如NOCOMPRESS:

owner , object_type, object_name

Scott table emp

Scott table dept

COMPRESS 1

owner , object_type, object_name

Scott table emp

table dept

COMPRESS 2

owner , object_type, object_name

Scott table emp

Dept

索引組織表的維護

索引組織表可以和普通堆表一樣進行INSERT、UPDATE、DELETE、SELECT操作。

可使用ALTER TABLE ... OVERFLOW語句來更改溢出段的屬性。

Alter table t88 add overflow;--新增一個overflow

● 要ALTER任何OVERVIEW的屬性,都必須先定義overflow,若建表時沒有可以新增

Alter table t88 pctthreshold 15 including name;--調整overflow的參數

Alter table t88 initrans 2 overflow initrans 4;--修改數據塊和溢出段的 initrans特性



下面分別就索引組織表和普通表的一些性能對比做一些試驗,創建兩張表,一個為普通的表,另外一個為索引組織表:
C:\>sqlplus

SQL*Plus: Release 9.2.0.1.0 - Production on 星期四 5月 19 11:09:06 2005

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

請輸入用戶名: wwf/wwf

連接到:
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production

create table heap_stocks
( symbol varchar2(4),
ticker_dt date,
price number,
constraint heap_stocks_pk primary key (symbol,ticker_dt)
);

create table iot_stocks
( symbol varchar2(4),
ticker_dt date,
price number,
constraint iot_stocks_pk primary key (symbol,ticker_dt)
)
organization index compress 1;

上面模仿股票,分別存放股票代碼,日期,收盤價格三個字段。下面,我們插入分別對這兩個表插入1000種股票200天的數據,看看其插入數據時的性能:

1 插入數據
SQL> set timing on
SQL> begin
2 for i in 1..200 loop
3 insert into heap_stocks
4 select to_char(rownum, ‘fm0009‘), trunc(sysdate)+i, rownum
5 from all_objects where rownum <= 1000;
6 end loop;
7 commit;
8 end;
9 /

PL/SQL 過程已成功完成。

已用時間: 00: 00: 18.06
SQL> set timing on
SQL> begin
2 for i in 1..200 loop
3 insert into iot_stocks
4 select to_char(rownum, ‘fm0009‘), trunc(sysdate)+i, rownum
5 from all_objects where rownum <= 1000;
6 end loop;
7 commit;
8 end
9 ;
10 /

PL/SQL 過程已成功完成。

已用時間: 00: 00: 31.07

可以看到,插入20萬條數據,普通表用了18秒,而IOT表用了31秒,相差明顯。這說明插入數據時,IOT表的速度是相當慢的。

2. 查詢

我們重新啟動一下數據庫:
SQL> conn
請輸入用戶名: sys / nolog as sysdba
已連接。
SQL> shutdown immediate
數據庫已經關閉。
已經卸載數據庫。
ORACLE 例程已經關閉。
SQL> startup
ORACLE 例程已經啟動。

Total System Global Area 135338868 bytes
Fixed Size 453492 bytes
Variable Size 109051904 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes
數據庫裝載完畢。
數據庫已經打開。
SQL> exit
從Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production中斷開

然後重新登錄:
SQL> conn
請輸入用戶名: wwf/wwf
已連接。
a. 使用autotrace測試
SQL> set autotrace traceonly
SQL> set timing on
SQL> set autotrace traceonly
SQL> select * from heap_stocks where symbol = ‘0001‘;

已選擇200行。

已用時間: 00: 00: 00.08

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (BY INDEX ROWID) OF ‘HEAP_STOCKS‘
2 1 INDEX (RANGE SCAN) OF ‘HEAP_STOCKS_PK‘ (UNIQUE)

Statistics
----------------------------------------------------------
239 recursive calls
0 db block gets
259 consistent gets
207 physical reads
0 redo size
5706 bytes sent via SQL*Net to client
646 bytes received via SQL*Net from client
15 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
200 rows processed

SQL> select * from iot_stocks where symbol = ‘0001‘;

已選擇200行。

已用時間: 00: 00: 00.02

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=82 Bytes=2132)
1 0 INDEX (RANGE SCAN) OF ‘IOT_STOCK_PK‘ (UNIQUE) (Cost=2 Card=82 Bytes=2132)

Statistics
----------------------------------------------------------
299 recursive calls
0 db block gets
63 consistent gets
4 physical reads
0 redo size
5706 bytes sent via SQL*Net to client
646 bytes received via SQL*Net from client
15 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
200 rows processed

邏輯讀分別為259和63,差別顯著!說明,查詢時,IOT表性能要遠遠優越於普通的表!


b 使用sql_trace測試:
SQL> conn
請輸入用戶名: wwf/wwf
已連接。
SQL> alter session set sql_trace = true;

會話已更改。

SQL> select avg(price) from heap_stocks where symbol = ‘0001‘;

AVG(PRICE)
----------
1

SQL> select avg(price) from iot_stocks where symbol = ‘0001‘;

AVG(PRICE)
----------
1

SQL> alter session set sql_trace = false;

會話已更改。

使用tkprof格式化輸出文件,得到如下結果:

select avg(price) from heap_stocks where symbol = ‘0001‘


call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.31 0.33 1 1 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.39 203 208 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.31 0.73 204 209 0 1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 61

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
200 TABLE ACCESS BY INDEX ROWID HEAP_STOCKS
200 INDEX RANGE SCAN HEAP_STOCKS_PK (object id 30391)



select avg(price) from iot_stocks where symbol = ‘0001‘


call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.02 0.03 0 0 0 0
Execute 1 0.00 0.01 0 0 0 0
Fetch 2 0.00 0.07 3 4 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.02 0.11 3 4 0 1

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 61

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
200 INDEX RANGE SCAN IOT_STOCK_PK (object id 30393)

看看Tom怎麽說:
So, we did 203 physical IO‘s to process the HEAP table. What that tells me is
that our data for stock symbol 0001 is spread out on 200 blocks (200 days, 200
blocks). In order to cache the results for this query, we need 200 block
buffers. We needed to do that IO to get the answer initially.

Now, looking at the IOT we did 3 physical IO‘s -- we cached 3 blocks -- and got
the same answer! Not only that but by using index key compression I was able to
remove he redudant 0001‘s from the data -- we can cache this much more
efficiently and getting it the first time takes seriously less IO. Very nice.


3 刪除數據
SQL> set autotrace off
SQL> delete from heap_stocks;

已刪除200000行。

已用時間: 00: 00: 26.02
SQL> delete from iot_stocks;

已刪除200000行。

已用時間: 00: 00: 08.08

可以看到,刪除數據時,普通表用了26秒,而IOT表用了8秒。差別顯著!也許是普通表占的空間大的緣故吧!

索引聚簇表clusterindex

Oracle中聚簇是存儲一組表的方法,而不是如同SQL Server、Sybase中那樣(那是Oracle中的IOT)。概念上是通過聚簇碼列將幾張表“預連接”,盡可能將聚簇碼列相同的幾張表的行放入同一個塊中。
不使用聚簇的情況:

1.聚簇可能消極影響DML性能;

2.全掃描表的性能會受到影響——不僅僅掃描一個表,而是對多個表全掃描;

3.聚簇中的表不能TRUNCATE。


Although a normal index does not storenull key values, cluster indexes store null keys. There is only one entry foreach key value in the cluster index. Therefore, a cluster index is likely to besmaller than a normal index on the same set of key values.


Although a normal index does not store null key values, cluster indexes storenull keys.
雖然普通的索引不保存空的鍵值,但cluster index保存空的keys?
為什麽cluster index保存空的keys?什麽情況呢,搞不明白
請指教

cluster 在存儲中,是多個表集合在一起存儲的,也就是說多個表的數據存儲在同一個 block 中。如果多個表中同時存在null key,是不是也需要把這些集中起來放在一起?你去觀察一下?

想到底是放 null key 呢還是不放 null key 好呢? 根據 cluster 的特點,結合起來考慮考慮看看。


其實,普通 b-tree index 也不是說就不能放 null keys ,只不過可能oracle認為大多數查詢是等值或者範圍查詢,很少用 is null 查詢,並且如果表中存在大量的 null 的時候不存儲 null 有利於減小索引大小提高性能。在各種因素權衡下選擇了不存儲 null 。

如果你實在覺得沒有很明顯的理由,大不了就先記下好了。

Each cluster key value is stored onlyonce for all the rows of the same key value; it therefore uses less storagespace.

散列聚簇表hash cluster

概念類似索引聚簇表,但用散列函數代替了聚簇碼索引。Oracle采用行的碼值,使用內部函數或者自定義的函數進行散列運算,從而指定數據的存放位置。這樣沒有在表中增加傳統的索引,因此不能Range Scan散列聚簇中的表,而只能全表掃描(除非單獨建立索引)。

CREATE CLUSTER hash_cluster

(hash_key NUMBER)

HASHKEYS 1000

SIZE 8192;

索引聚簇需要空間時是動態分配,而散列聚簇表在創建時確定了散列碼數(HASHKEY)。Oracle采用第一個不小於HASHKEY的質數作為散列碼數,將散列碼數*SIZE就得到分配的空間(字節),可容納HASHKEYS/TRUNC(BLOCKSIZE/SIZE)字節的數據。

性能上,散列聚簇表消耗較少I/O,較多CPU,所需執行時間較少,大體取決於CPU時間(當然可能要等待I/O,取決於配置)。

下列情況下使用散列聚簇表較為合適:

1. 在一定程度上精確知道整個過程中表中記錄行數或者合理的上限,以確定散列碼數;

2.不大量執行DML,尤其是插入。更新不會產生顯著的額外開銷,除非更新HASHKEY,這樣會導致行遷移;

3.總是通過HASHKEY值訪問數據。

堆組織表,索引組織表和索引聚簇表