1. 程式人生 > >ORACLE 表型別 OLTP和OLAP

ORACLE 表型別 OLTP和OLAP

表型別 

1、表的功能:儲存、管理資料的基本單元(二維表:有行和列組成)
2、表的型別:
   1)堆表:heap table :資料儲存時,行是無序的,對它的訪問採用全表掃描。
   2)分割槽表 表>2G
   3)索引組織表(IOT)
   4)簇表
   5)臨時表
   6)壓縮表
   7)巢狀表


3、如何將普通錶轉換為分割槽表;
   11g以前,1)create 分割槽表, 2)insert into 分割槽表 select * from 普通表; 3)rename 分割槽表名; 4)重建約束、索引、觸發器。
   11g以後,線上重定義分割槽表


12.1 分割槽表及其種類(10g)


1)Range Partitioning (範圍分割槽)


scott:


SQL>create table sale(
product_id varchar2(5), sales_count number(10,2)
)
partition by range(sales_count)
(
  partition p1 values less than(1000),
  partition p2 values less than(2000),
  partition p3 values less than(3000)
);
檢視資訊:


select * from user_tab_partitions where table_name='SALE'; 


insert into sale values('1',600);
insert into sale values('2',1000);
insert into sale values('3',2300);
insert into sale values('4',6000);
commit;


select * from sale partition(p1);
select * from sale partition(p2);


增加一個分割槽
alter table sale add partition p4 values less than(maxvalue);


再看一下, 可以插入6000值了
select * from user_tab_partitions where table_name='SALE';
insert into sale values('4',6000);


看一下段的分配
SQL> select segment_name,segment_type,partition_name from user_segments;


12.1.1 預設情況下,如果對分割槽表的分割槽欄位做超範圍(跨段)update操作,會報錯——ORA-14402: 。如果一定要改,可以通過開啟表的row movement屬性來完成。


SQL> select rowid,t1.* from sale partition(p1) t1;


ROWID              PRODU SALES_COUNT
------------------ ----- -----------
AAASvUAAEAAAAGVAAA 1             600


SQL> update sale set sales_count=1200 where sales_count=600;
update sale set sales_count=1200 where sales_count=600
       *
第 1 行出現錯誤:
ORA-14402: 更新分割槽關鍵字列將導致分割槽的更改


SQL> alter table sale enable row movement;
SQL> update sale set sales_count=1200 where sales_count=600;


已更新 1 行。


SQL> select rowid,t1.* from sale partition(p2) t1;


ROWID              PRODU SALES_COUNT
------------------ ----- -----------
AAASvVAAEAAAAGdAAA 2            1000
AAASvVAAEAAAAGdAAB 1            1200


一般來說範圍分割槽的分割槽欄位使用數字型別或日期型別,使用字元型別的語法是可以的,實際工作中使用較少。這或許跟values less than
子句有關。


12.1.2 關於建立分割槽索引


一般使用分割槽都會建立索引,分割槽索引有local與global之分。


            Local Parfixed Index
                                                             |-----------------------------
 Local Partitioned Index   |
|-----------------------------|
 Partitioned Index                    |                                         |Local Nonparfixed Index
|----------------------------------|                                         |------------------------------
|                                                |
| |Global Partitioned Index
| |------------------------------
|
|Nonpartitioned Index 
|------------------------


1)local:一個索引分割槽對應一個表分割槽,分割槽key就是索引key,分割槽邊界就是索引邊界。更新一個表分割槽時僅僅影響該分割槽的索引。


SQL>create index sale_idx on sale(sales_count) local;
SQL>select * from user_ind_partitions;


Local Parfixed Index,所謂字首索引,是指組合索引中的first column使用的是分割槽key。 


global:全域性索引:
  
2)分割槽全域性索引:索引分割槽不與表分割槽對應,分割槽key是索引key。另外一定要將maxvalue關鍵字做上限。
create index sale_global_idx on sale(sales_count) global
partition by range (sales_count)
(
partition p1 values less than(1500),
partition p2 values less than(maxvalue)
);


SQL>select * from user_ind_partitions; 


12.1.3 刪除一個分割槽,其中的資料全部清除,並且包括相關索引等
SQL> alter table sale drop partition p3;


 
12.1.4 Hash Partitioning (雜湊分割槽,也叫hash分割槽) 


實現均勻的負載值分配,增加HASH分割槽可以重新分佈資料。


create table my_emp(
  empno number, ename varchar2(10)
)
partition by hash(empno) 
(
  partition p1, partition p2
);
  
select * from user_tab_partitions where table_name='MY_EMP';


插入幾個值,看是否均勻插入。


insert into my_emp values(1,'A');
insert into my_emp values(2,'B');
insert into my_emp values(3,'C');


select * from my_emp partition(P1);
select * from my_emp partition(P2);


12.1.5 列表分割槽(list): 將不相關的資料組織在一起


create table personcity(
  id number, name varchar2(10), city varchar2(10)
)
partition by list(city)
(
  partition east values('tianjin','dalian'),
  partition west values('xian'),
  partition south values ('shanghai'),
  partition north values ('herbin'),
  partition other values (default)
);


insert into personcity values(1,'sohu','tianjin');
insert into personcity values(2,'sina','herbin');
insert into personcity values(3,'yahoo','dalian');
insert into personcity values(4,'360','zhengzhou');
insert into personcity values(5,'baidu','xian');


看結果


select * from personcity partition(east);


12.1.6 Composite Partitioning(複合分割槽)


把範圍分割槽和雜湊分割槽相結合或者 範圍分割槽和列表分割槽相結合。


create table student(
   sno number, sname varchar2(10)
)
partition by range(sno)
subpartition by hash(sname)
subpartitions 4
(
  partition p1 values less than(1000),
  partition p2 values less than(2000),
  partition p3 values less than(maxvalue)
);


有三個range分割槽,對每個分割槽會有4個hash分割槽,共有12個分割槽。


SQL> select * from user_tab_partitions where table_name='STUDENT';
 
SQL> select * from user_tab_subpartitions where table_name='STUDENT';


用EM檢視,看scott的student table子分割槽裡的名字是由oracle取名。


12.2 Oracle11g新增分割槽


Partition(分割槽),一直是Oracle資料庫引以為榮的一項技術,正是分割槽的存在讓Oracle高效的處理海量資料成為可能。在Oracle11g在
10g的分割槽技術基礎上又有了新的發展,使分割槽技術在易用性和可擴充套件性上再次得到了增強。


12.2.1 Interval Partitioning (間隔分割槽)


實際上是由range分割槽引申而來,最終實現了range分割槽的自動化。
scott:
SQL>
create table interval_sales (s_id int,d_1 date)
partition by range(d_1)
interval (numtoyminterval(1,'MONTH'))
(
   partition p1 values less than ( to_date('2010-02-01','yyyy-mm-dd') )
);


SQL> insert into interval_sales values(1, to_date('2010-01-21','yyyy-mm-dd') );
SQL> insert into interval_sales values(2, to_date('2010-02-01','yyyy-mm-dd') );--越過p1分割槽上線,將自動建立一個分割槽
SQL> select partition_name from user_tab_partitions;


PARTITION_NAME
------------------------------
P1
SYS_P61


注意:interval (numtoyminterval(1,'MONTH'))的意思就是每個月有一個分割槽,每當輸入了新的月份的資料,這個分割槽就會自動建立,而
不同年的相同月份是兩個分割槽。


12.2.2 System Partitioning (系統分割槽)


這是一個人性化的分割槽型別,System Partitioning,在這個新的型別中,不需要指定任何分割槽鍵,資料會進入哪個分割槽完全由應用程式決
定,即在Insert語句中決定記錄行插入到哪個分割槽。


先建立三個表空間 tbs1,tbs2,tbs3, 然後建立三個分割槽的system分割槽表,分佈在三個表空間上。


create table test (c1 int,c2 int)
partition by system
(
  partition p1 tablespace tbs1,
  partition p2 tablespace tbs2,
  partition p3 tablespace tbs3
);


現在由SQL語句來指定插入哪個分割槽:


SQL> INSERT INTO test PARTITION (p1) VALUES (1,3);
SQL> INSERT INTO test PARTITION (p3) VALUES (4,5);


SQL> select * from test;


        C1         C2
---------- ----------
         1          3
         4          5


注意:如果要刪除以上表空間,必須先刪除其上的分割槽表,否則會報錯ORA-14404: 分割槽表包含不同表空間中的分割槽。


12.2.3 Reference Partitioning (引用分割槽)


當兩個表是主外來鍵約束關聯時,我們可以利用父子關係對這兩個表進行分割槽。只要對父表做形式上的分割槽,然後子表就可以繼承父表的分
區鍵。
如果沒有11g的引用分割槽,你想在兩個表上都建立對應的分割槽,那麼需要使兩表分別有相同名稱的鍵值列。引用分割槽的好處是避免了在子表
上也建立父表同樣的一個分割槽鍵列,父表上的任何分割槽維護操作都將自動的級聯到子表上。


例:
SQL>
CREATE TABLE purchase_orders 
  (po_id NUMBER(4),
   po_date TIMESTAMP, 
   supplier_id NUMBER(6), 
   po_total NUMBER(8,2),
   CONSTRAINT order_pk PRIMARY KEY(po_id)) 
PARTITION BY RANGE(po_date)
  (PARTITION Q1 VALUES LESS THAN (TO_DATE('2007-04-01','yyyy-mm-dd')), 
   PARTITION Q2 VALUES LESS THAN (TO_DATE('2007-06-01','yyyy-mm-dd')), 
   PARTITION Q3 VALUES LESS THAN (TO_DATE('2007-10-01','yyyy-mm-dd')), 
   PARTITION Q4 VALUES LESS THAN (TO_DATE('2008-01-01','yyyy-mm-dd')));


//父表做了一個Range分割槽(可對引用分割槽使用除間隔分割槽外的所有分割槽策略)


SQL>
CREATE TABLE purchase_order_items 
  (po_id NUMBER(4) NOT NULL, 
   product_id NUMBER(6) NOT NULL, 
   unit_price NUMBER(8,2), 
   quantity NUMBER(8), 
   CONSTRAINT po_items_fk FOREIGN KEY (po_id) REFERENCES purchase_orders(po_id)) 
   PARTITION BY REFERENCE(po_items_fk);


//主表使用po_date鍵值列做範圍分割槽,子表中沒有po_date列,也想做相應的分割槽,那麼使用引用分割槽吧。
//子表最後一句PARTITION BY REFERENCE()子句給出了引用分割槽約束名,使用的是子表的外來鍵約束名。
//子表的po_id列必須是NOT NULL。這與通常的外來鍵可以是NULL是有區別的。


SQL> select TABLE_NAME,PARTITION_NAME,HIGH_VALUE from user_tab_partitions;
 
TABLE_NAME                     PARTITION_NAME                 HIGH_VALUE
------------------------------ ------------------------------ --------------------------------------------------------------------------------
PURCHASE_ORDERS                     Q1                             TIMESTAMP' 2007-04-01 00:00:00'
PURCHASE_ORDERS                     Q2                             TIMESTAMP' 2007-06-01 00:00:00'
PURCHASE_ORDERS                     Q3                             TIMESTAMP' 2007-10-01 00:00:00'
PURCHASE_ORDERS                     Q4                             TIMESTAMP' 2008-01-01 00:00:00'
PURCHASE_ORDER_ITEMS           Q1                             
PURCHASE_ORDER_ITEMS           Q2                             
PURCHASE_ORDER_ITEMS           Q3                             
PURCHASE_ORDER_ITEMS           Q4                             
 
8 rows selected


//子表purchase_order_items也自動產生了四個分割槽,Q1,Q2,Q3,Q4.高值為空,意味者此處邊界由父表派生。


SQL> select TABLE_NAME,PARTITIONING_TYPE,REF_PTN_CONSTRAINT_NAME from user_part_tables;
 
TABLE_NAME                     PARTITIONING_TYPEREF_PTN_CONSTRAINT_NAME
------------------------------ -----------------------------------------------
PURCHASE_ORDERS                     RANGE             
PURCHASE_ORDER_ITEMS           REFERENCE         PO_ITEMS_FK
 
// PO_ITEMS_FK列是外來鍵約束名稱


12.2.4 Virtual Column-Based Partitioning(虛擬列分割槽)


先了解一下什麼叫虛擬列。


虛擬列是11g的新特性:


1> 只能在堆組織表(普通表)上建立虛擬列
2> 虛擬列的值並不是真實存在的,只有用到時,才根據表示式計算出虛擬列的值,磁碟上並不存放。
3> 可在虛擬列上建立索引。
4> 如果在已經建立的表中增加虛擬列時,若沒有指定虛擬列的欄位型別,ORACLE會根據 generated always as 後面的表示式計算的結
     果自動設定該欄位的型別。
5> 虛擬列的值由ORACLE根據表示式自動計算得出,不可以做UPDATE和INSERT操作,可以對虛擬列做DELETE 操作。
6> 表示式中的所有列必須在同一張表。
7> 表示式不能使用其他虛擬列。


8> 可把虛擬列當做分割槽關鍵字建立虛擬列分割槽表,這正是我們要講的虛擬列分割槽。


create table emp1
  (empno number(4) primary key,
   ename char(10) not null,
   salary number(5) not null,
   bonus number(5)  not null,
   total_sal AS (salary+bonus))
partition by range (total_sal)
  (partition p1 values less than (5000),
   partition p2 values less than (maxvalue))
   enable row movement;


insert into emp1(empno,ename,salary,bonus) values(7788,'SCOTT',3000,1000);
insert into emp1(empno,ename,salary,bonus) values(7902,'FORD',4000,1500);
insert into emp1(empno,ename,salary,bonus) values(7839,'KING',5000,3500);
commit;


SQL> select * from user_tab_partitions;
SQL> select * from user_part_key_columns;


SQL> select * from emp1 partition (p1);


     EMPNO  ENAME          SALARY      BONUS  TOTAL_SAL
----------    ----------         ----------      ----------    ----------
      7788      SCOTT            3000         1000       4000


SQL> select * from emp1 partition (p2);


     EMPNO   ENAME          SALARY      BONUS  TOTAL_SAL
----------     ----------      ----------        ----------   ----------
      7902      FORD             4000          1500       5500
      7839      KING              5000          3500       8500


SQL> update emp1 set bonus=500 where empno=7902;


在建表時就使能了行移動(enable row movement),當更新分割槽鍵值時就不會報錯(ORA-14402: 更新分割槽關鍵字列將導致分割槽
的更改)


12.2.5 More Composite Partitioning
在10g中,我們知道複合分割槽只支援Range-List和Range-Hash,而在在11g中複合分割槽的型別大大增加,現在Range,List,Interval都可
以作為Top level分割槽,而Second level則可以是Range,List,Hash,也就是在11g中可以有3*3=9種複合分割槽,滿足更多的業務需求。


12.3 Oracle11g 的聯機重定義功能


聯機條件下把普通的堆錶轉換成分割槽表(11g新特性)


例:聯機建立分割槽表:將emp1表聯機重定義,要求完成兩個任務,使其按照 sal分割槽(以2500為界),並去掉comm列。這個過程需要建
立一個臨時分割槽表emp1_temp完成複製轉換。


sys下執行


create table scott.emp1 as select * from scott.emp;


alter table scott.emp1 add constraint pk_emp1 primary key(empno);


1) 檢查原始表是否具有線上重定義資格,(要求表自包含及之前沒有建立實體化檢視及日誌)
SQL>
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE('scott','emp1');   該包要求表要有primary key
END;
/


2) 建立一個臨時分割槽表:emp1_temp, 含有7列(刪去comm列),然後range分割槽,兩個區以sal=2500為界。
SQL>
CREATE TABLE scott.emp1_temp
  (empno        number(4) not null,
   ename        varchar2(10),
   job          varchar2(9),
   mgr          number(4),
   hiredate     date,
   sal          number(7,2),
   deptno       number(2))
PARTITION BY RANGE(sal)
   (PARTITION sal_low VALUES LESS THAN(2500),
   PARTITION sal_high VALUES LESS THAN (maxvalue));


3)啟動聯機重定義處理過程
SQL>
BEGIN
  dbms_redefinition.start_redef_table('scott','emp1','emp1_temp',
   'empno empno,
   ename ename,
   job job,
   mgr mgr,
   hiredate hiredate,
   sal sal,
   deptno deptno');
END;
/




SQL> select count(*) from scott.emp1_temp;


  COUNT(*)
----------
        14


SQL> select * from scott.emp1_temp partition(sal_low);


     EMPNO ENAME      JOB              MGR  HIREDATE                        SAL     DEPTNO
---------- ---------- --------- ---------- ------ -------------                      ----------      ----------
      7369 SMITH      CLERK                7902 1980-12-17 00:00:00        800         20
      7499 ALLEN      SALESMAN        7698 1981-02-20 00:00:00       1600        30
      7521 WARD      SALESMAN        7698 1981-02-22 00:00:00       1250        30
      7654 MARTIN   SALESMAN        7698 1981-09-28 00:00:00       1250        30
      7782 CLARK      MANAGER         7839 1981-06-09 00:00:00       2450        10
      7844 TURNER   SALESMAN        7698 1981-09-08 00:00:00       1500        30
      7876 ADAMS    CLERK                7788 1987-05-23 00:00:00       1100        20
      7900 JAMES      CLERK                7698 1981-12-03 00:00:00        950         30
      7934 MILLER     CLERK                7782 1982-01-23 00:00:00       1300        10


已選擇9行。


SQL> select * from scott.emp1_temp partition(sal_high);


     EMPNO ENAME      JOB              MGR HIREDATE                   SAL     DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ----------
      7566 JONES      MANAGER         7839 1981-04-02 00:00:00       2975         20
      7698 BLAKE      MANAGER         7839 1981-05-01 00:00:00       2850         30
      7788 SCOTT      ANALYST           7566 1987-04-19 00:00:00       3000         20
      7839 KING        PRESIDENT                 1981-11-17 00:00:00       5000         10
      7902 FORD       ANALYST           7566 1981-12-03 00:00:00       3000         20


已選擇5行。


這個時候emp1_temp的主鍵,索引,觸發器,授權等還沒有從原始表繼承過來,


SQL> select constraint_name,constraint_type,table_name from user_constraints where table_name like 'EMP1%';
 
CONSTRAINT_NAME                CONSTRAINT_TYPE TABLE_NAME
------------------------------ --------------- ------------------------------
PK_EMP1                          P                EMP1
SYS_C009652                    C               EMP1_TEMP


4) 複製依賴物件


這一步的作用是:臨時分割槽表emp1_temp繼承原始表emp1的全部屬性:包括索引、約束和授權以及觸發器。


SQL>
DECLARE
  num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('scott','emp1','emp1_temp',
  DBMS_REDEFINITION.CONS_ORIG_PARAMS,TRUE,TRUE,TRUE,TRUE,num_errors);
END;
/


SQL> select constraint_name,constraint_type,table_name from user_constraints where table_name like 'EMP1%';
 
CONSTRAINT_NAME                CONSTRAINT_TYPE TABLE_NAME
------------------------------ --------------- ------------------------------
PK_EMP1                                    P               EMP1
SYS_C009652                       C              EMP1_TEMP
TMP$$_PK_EMP10                     P               EMP1_TEMP






這時候原始表emp1還沒有分割槽,


SQL> select table_name,partition_name,high_value from user_tab_partitions;
 
TABLE_NAME                     PARTITION_NAME                 HIGH_VALUE
------------------------------ ------------------------------ --------------------------------------------------------------
EMP1_TEMP                      SAL_HIGH                                MAXVALUE
EMP1_TEMP                      SAL_LOW                                 2500


5) 完成重定義過程。


SQL> EXECUTE dbms_redefinition.finish_redef_table('scott','emp1','emp1_temp');


SQL> select table_name,partition_name,high_value from user_tab_partitions;
 
TABLE_NAME                     PARTITION_NAME                 HIGH_VALUE
------------------------------ ------------------------------ --------------------------------------------------------------
EMP1                           SAL_HIGH                       MAXVALUE
EMP1                           SAL_LOW                        2500


最後一步發生了什麼事情:原始表emp1與臨時分割槽表emp1_temp互換名稱。


12.4 索引組織表(IOT表:如果表經常以主鍵查詢,可以考慮建立索引組織表,加快表的訪問速度


heap table 資料的存放是隨機的,獲取表中的資料時沒有明確的先後之分,在進行全表掃描的時候,並不是先插入的資料就先獲取。而IOT
表是一個完全B_tree索引結構的表,表結構按照索引(主鍵)有序組織,因此資料存放在插入以前就已經確定了其位置。


由於IOT表是把普通表和索引合二而一了,這樣在進行查詢的時候就可以少訪問很多基表的blocks,但是插入和刪除的時,速度比普通的表要
慢一些。


IOT表的葉子節點儲存了所有表列,因為已按主鍵排序,所以葉子節點上不需要再儲存rowid。


表列較多時,設定溢位段將主鍵和其他欄位資料分開來儲存以提高效率。


溢位段是個可選項,如果選擇了溢位段,Oracle將為一個IOT表分配兩個段,一個是索引段,另一個是溢位段。


溢位段有兩個子句pctthreshold和including


說明:
pctthreshold給出行大小和塊大小的百分比,當行資料在葉子節點佔用大小超出這個閾值時,就以這個閾值將索引entry一分為二,包含
主鍵的一部分列值保留在索引段,而其他列值放入溢位段,即overflow到指定的儲存空間去。


including 後面指定一個或多個列名(不含主鍵列),將這些列都放入索引段。即讓主鍵和一些常用的列在索引段,其餘的列在溢位段。


例:
create table iot_timran(id int, name char(50), sal int, 
constraint pk_timran primary key (id))
organization index pctthreshold 30 overflow tablespace users;


使用select * from user_indexes 檢視是否單獨有索引。


SQL> select index_name,index_type,table_name from user_indexes;
 
INDEX_NAME                     INDEX_TYPE                  TABLE_NAME
------------------------------ --------------------------- ------------------------------
PK_TIMRAN                      IOT - TOP                     IOT_TIMRAN
PK_EMP                            NORMAL                      EMP
PK_DEPT                           NORMAL                      DEPT


通過user_segments檢視檢視產生了兩個段。
SQL> select segment_name,segment_type,partition_name from user_segments;


12.5 簇表(cluster table):


兩個相互關聯的表的資料,物理上同時組織到一個簇塊中,當以後進行關聯讀取時,只要掃描一個數據塊就可以了,可以提高了IO效率。


建立簇表的三個步驟:


1)建立簇段cluster segment
2)基於簇,建立兩個相關表,這兩個表不建立單獨的段,每個表都關聯到cluster segment上。
3)為簇建立索引,生成索引段。


create cluster cluster1(code_key number);
create table student(sno1 number, sname varchar2(10)) cluster cluster1(sno1);
create table address(sno2 number,zz varchar2(10)) cluster cluster1(sno2);
create index index1 on cluster cluster1; 


生成了cluster1段和index1段。


檢視簇的資訊:
select * from user_clusters;
select * from user_clu_columns;


刪除簇:
drop table student;
drop table address;
drop cluster cluster1;


12.6 臨時表 (Temporary Table)


臨時表存放在當前登入的臨時表空間下,它被每個session單獨使用,即隔離session間的資料,不同session看到的臨時表中的資料不一樣。


每個session獨立支援rollback,基於事務的臨時段在事務結束後收回臨時段,基於會話的臨時段在會話結束後收回臨時段,總之沒有
DML鎖,沒有約束,可以建索引,檢視和觸發器,由於會產生少量UNDO資訊所以會產生少量redo,節省資源,訪問資料快。


兩種模式:
1)基於事務的臨時段:在事務提交時,就會自動刪除記錄,on commit delete rows。
2)基於會話的臨時段:當用戶退出session 時,才會自動刪除記錄, on commit preserve rows。


例:scott:
create global temporary table tmp_student(sno int,sname varchar2(10), sage int) on commit preserve rows;


再用Scott開一個session 
兩邊插入記錄看看, 你可以在兩個session裡插入同樣的記錄,井水不犯河水!


要刪除臨時表,要所有session斷開連線,再做刪除。


drop table tmp_table;


12.7 只讀表 (11g新特性)


在以前版本中,有隻讀表空間但沒有隻讀表。11g中增加了新特性----只讀表。


SQL> alter table t read only;
SQL> update t set id=2;
update t set id=2
       *
第 1 行出現錯誤:
ORA-12081: 不允許對錶 "SCOTT"."T" 進行更新操作


SQL> alter table t read write;


注意點:只讀表可以drop,因為只需要在資料字典做標記,但是不能做DML,另外,truncate也不行,因為它們都在對只讀表做寫操作。


12.8 壓縮表 (11g新特性)


目的:去掉表列中資料儲存的重複值,提高空間利用率。對資料倉庫類的OLAP有意義(頻繁的DML操作的表可能不適用做壓縮表)


可以壓縮:堆表(若指定表空間則壓縮該表空間下所有表),索引表,分割槽表,物化檢視。


主要壓縮形式有兩種:


Advanced 11gR2較之前版本在語法上有了變化


1)Basic table compression 使用direct path loads(預設),典型的是建立大批量的資料,如:create table as select...結構 


Basic對應的語法是:
CREATE TABLE ... COMPRESS BASIC;
替換
COMPRESS FOR DIRECT_LOAD OPERATIONS(舊)


2)Advanced row compression 針對OLTP的任何SQL操作。


CREATE TABLE ... COMPRESS FOR OLTP...
代替
CREATE TABLE ... COMPRESS FOR ALL OPERATIONS(舊)


兩種壓縮的原理類似(PPT-II-481-482):當insert達到pctfree=閥值(basic對應的pctfree=0, Advanced對應的是pctfree=10),觸發
compress,之後可以繼續insert,再達到pctfree,再觸發compress....直至compress資料填滿block的pctfree以下部分。


壓縮的是block中的冗餘資料,這對節省db buffer有益。例如一個表有7個columns,5 rows,其中的一些column有重複的行值


2190,13770,25-NOV-00,S,9999,23,161
2225,15720,28-NOV-00,S,9999,25,1450
34005,120760,29-NOV-00,P,9999,44,2376
9425,4750,29-NOV-00,I,9999,11,979
1675,46750,29-NOV-00,S,9999,19,1121


壓縮這個表後,儲存形式成為如下,重複值用符號替代。


2190,13770,25-NOV-00,S,%,23,161
2225,15720,28-NOV-00,S,%,25,1450
34005,120760,*,P,%,44,2376
9425,4750,*,I,%,11,979
1675,46750,*,S,%,19,1121


那麼自然要對這些符號做些說明,相當於有個符號表


Symbol Value ColumnRows 
* 29-NOV-00 3 958-960
% 9999 5 956-960
--------------------- 

OLTP和OLAP

 資料處理大致可以分成兩大類:聯機事務處理OLTP(on-line transaction processing)、聯機分析處理OLAP(On-Line Analytical Processing)。OLTP是傳統的關係型資料庫的主要應用,主要是基本的、日常的事務處理,例如銀行交易。OLAP是資料倉庫系統的主要應用,支援複雜的分析操作,側重決策支援,並且提供直觀易懂的查詢結果。


OLTP 系統強調資料庫記憶體效率,強調記憶體各種指標的命令率,強調繫結變數,強調併發操作;

OLAP 系統則強調資料分析,強調SQL執行市場,強調磁碟I/O,強調分割槽等。




OLTP與OLAP之間的比較:

                          

 

 

 

 



什麼是OLTP


OLTP,也叫聯機事務處理(Online Transaction Processing),表示事務性非常高的系統,一般都是高可用的線上系統,以小的事務以及小的查詢為主,評估其系統的時候,一般看其每秒執行的Transaction以及Execute SQL的數量。在這樣的系統中,單個數據庫每秒處理的Transaction往往超過幾百個,或者是幾千個,Select 語句的執行量每秒幾千甚至幾萬個。典型的OLTP系統有電子商務系統、銀行、證券等,如美國eBay的業務資料庫,就是很典型的OLTP資料庫。

 



OLTP系統最容易出現瓶頸的地方就是CPU與磁碟子系統。

(1)CPU出現瓶頸常表現在邏輯讀總量與計算性函式或者是過程上,邏輯讀總量等於單個語句的邏輯讀乘以執行次數,如果單個語句執行速度雖然很快,但是執行次數非常多,那麼,也可能會導致很大的邏輯讀總量。設計的方法與優化的方法就是減少單個語句的邏輯讀,或者是減少它們的執行次數。另外,一些計算型的函式,如自定義函式、decode等的頻繁使用,也會消耗大量的CPU時間,造成系統的負載升高,正確的設計方法或者是優化方法,需要儘量避免計算過程,如儲存計算結果到統計表就是一個好的方法。

(2)磁碟子系統在OLTP環境中,它的承載能力一般取決於它的IOPS處理能力. 因為在OLTP環境中,磁碟物理讀一般都是db file sequential read,也就是單塊讀,但是這個讀的次數非常頻繁。如果頻繁到磁碟子系統都不能承載其IOPS的時候,就會出現大的效能問題。

 



OLTP比較常用的設計與優化方式為Cache技術與B-tree索引技術,Cache決定了很多語句不需要從磁碟子系統獲得資料,所以,Web cache與Oracle data buffer對OLTP系統是很重要的。另外,在索引使用方面,語句越簡單越好,這樣執行計劃也穩定,而且一定要使用繫結變數,減少語句解析,儘量減少表關聯,儘量減少分散式事務,基本不使用分割槽技術、MV技術、並行技術及點陣圖索引。因為併發量很高,批量更新時要分批快速提交,以避免阻塞的發生。


OLTP 系統是一個數據塊變化非常頻繁,SQL 語句提交非常頻繁的系統。 對於資料塊來說,應儘可能讓資料塊儲存在記憶體當中,對於SQL來說,儘可能使用變數繫結技術來達到SQL 重用,減少物理I/O 和重複的SQL 解析,從而極大的改善資料庫的效能。 


這裡影響效能除了繫結變數,還有可能是熱快(hot block)。 當一個塊被多個使用者同時讀取時,Oracle 為了維護資料的一致性,需要使用Latch來序列化使用者的操作。當一個使用者獲得了latch後,其他使用者就只能等待,獲取這個資料塊的使用者越多,等待就越明顯。 這就是熱快的問題。 這種熱快可能是資料塊,也可能是回滾端塊。 對於資料塊來講,通常是資料庫的資料分佈不均勻導致,如果是索引的資料塊,可以考慮建立反向所以來達到重新分佈資料的目的,對於回滾段資料塊,可以適當多增加幾個回滾段來避免這種爭用。

 

 

 




什麼是OLAP

OLAP,也叫聯機分析處理(Online Analytical Processing)系統,有的時候也叫DSS決策支援系統,就是我們說的資料倉庫。在這樣的系統中,語句的執行量不是考核標準,因為一條語句的執行時間可能會非常長,讀取的資料也非常多。所以,在這樣的系統中,考核的標準往往是磁碟子系統的吞吐量(頻寬),如能達到多少MB/s的流量。

磁碟子系統的吞吐量則往往取決於磁碟的個數,這個時候,Cache基本是沒有效果的,資料庫的讀寫型別基本上是db file scattered read與direct path read/write。應儘量採用個數比較多的磁碟以及比較大的頻寬,如4Gb的光纖介面。

 



在OLAP系統中,常使用分割槽技術、並行技術。

分割槽技術在OLAP系統中的重要性主要體現在資料庫管理上,比如資料庫載入,可以通過分割槽交換的方式實現,備份可以通過備份分割槽表空間實現,刪除資料可以通過分割槽進行刪除,至於分割槽在效能上的影響,它可以使得一些大表的掃描變得很快(只掃描單個分割槽)。另外,如果分割槽結合並行的話,也可以使得整個表的掃描會變得很快。總之,分割槽主要的功能是管理上的方便性,它並不能絕對保證查詢效能的提高,有時候分割槽會帶來效能上的提高,有時候會降低。

並行技術除了與分割槽技術結合外,在Oracle 10g中,與RAC結合實現多節點的同時掃描,效果也非常不錯,可把一個任務,如select的全表掃描,平均地分派到多個RAC的節點上去。

 



在OLAP系統中,不需要使用繫結(BIND)變數,因為整個系統的執行量很小,分析時間對於執行時間來說,可以忽略,而且可避免出現錯誤的執行計劃。但是OLAP中可以大量使用點陣圖索引,物化檢視,對於大的事務,儘量尋求速度上的優化,沒有必要像OLTP要求快速提交,甚至要刻意減慢執行的速度。


繫結變數真正的用途是在OLTP系統中,這個系統通常有這樣的特點,使用者併發數很大,使用者的請求十分密集,並且這些請求的SQL 大多數是可以重複使用的。

 



對於OLAP系統來說,絕大多數時候資料庫上執行著的是報表作業,執行基本上是聚合類的SQL 操作,比如group by,這時候,把優化器模式設定為all_rows是恰當的。 而對於一些分頁操作比較多的網站類資料庫,設定為first_rows會更好一些。 但有時候對於OLAP 系統,我們又有分頁的情況下,我們可以考慮在每條SQL 中用hint。 如:

Select /*+first_rows(10) */ a.* from table a;

 

 






分開設計與優化

在設計上要特別注意,如在高可用的OLTP環境中,不要盲目地把OLAP的技術拿過來用。

如分割槽技術,假設不是大範圍地使用分割槽關鍵字,而採用其它的欄位作為where條件,那麼,如果是本地索引,將不得不掃描多個索引,而效能變得更為低下。如果是全域性索引,又失去分割槽的意義。

並行技術也是如此,一般在完成大型任務時才使用,如在實際生活中,翻譯一本書,可以先安排多個人,每個人翻譯不同的章節,這樣可以提高翻譯速度。如果只是翻譯一頁書,也去分配不同的人翻譯不同的行,再組合起來,就沒必要了,因為在分配工作的時間裡,一個人或許早就翻譯完了。

點陣圖索引也是一樣,如果用在OLTP環境中,很容易造成阻塞與死鎖。但是,在OLAP環境中,可能會因為其特有的特性,提高OLAP的查詢速度。MV也是基本一樣,包括觸發器等,在DML頻繁的OLTP系統上,很容易成為瓶頸,甚至是Library Cache等待,而在OLAP環境上,則可能會因為使用恰當而提高查詢速度。


對於OLAP系統,在記憶體上可優化的餘地很小,增加CPU 處理速度和磁碟I/O 速度是最直接的提高資料庫效能的方法,當然這也意味著系統成本的增加。

比如我們要對幾億條或者幾十億條資料進行聚合處理,這種海量的資料,全部放在記憶體中操作是很難的,同時也沒有必要,因為這些資料快很少重用,快取起來也沒有實際意義,而且還會造成物理I/O相當大。 所以這種系統的瓶頸往往是磁碟I/O上面的。


對於OLAP系統,SQL 的優化非常重要,因為它的資料量很大,做全表掃描和索引對效能上來說差異是非常大的。
--------------------- 
概述
Oracle-OLAP和OLTP解讀

Oracle-index索引解讀

Oracle-分割槽表解讀

Oracle-鎖解讀

Oracle-等待事件解讀

Oracle-procedure/cursor解讀

通常來說,我們把業務分為來兩類,線上事務處理系統(OLTP)和線上分析系統(OLAP)或者DSS(決策支援系統),這兩類系統在資料庫的設計上是如此的不同,甚至有些地方的設計是像相悖的。

比如: 
OLTP 系統強調資料庫的記憶體效率,強調記憶體各種指標的命中率,強調繫結變數,強調併發操作

OLAP 系統則強調資料分析,強調SQL 執行時長,強調磁碟I/O,強調分割槽等。

OLTP(on-line transaction processing)資料庫
通常來講,OLTP(線上事務處理系統)的使用者併發數都很多,但他們只對資料庫做很小的操作,資料庫側重於對使用者操作的快速響應,這是對資料庫最重要的效能要求。

對於一個OLTP 系統來說,資料庫記憶體設計顯得很重要,如果資料都可以在記憶體中處理,那麼資料庫的效能無疑會提高很多。

記憶體的設計通常是通過調整Oracle 和記憶體相關的初始化引數來實現的,比較重要的幾個是記憶體相關的引數,包括SGA 的大小(Data Buffer,Shared Pool),PGA 大小(排序區,Hash 區等)等,這些引數在一個OLTP 系統裡顯得至關重要,OLTP 系統是一個數據塊變化非常頻繁,SQL 語句提交非常頻繁的一個系統。

對於資料塊來說,應儘可能讓資料塊儲存在記憶體當中,對於SQL 來說,儘可能使用變數繫結技術來達到SQL 的重用,減少物理I/O 和重複的SQL 解析,能極大的改善資料庫的效能。

除了記憶體,沒有繫結變數的SQL 會對OLTP 資料庫造成極大的效能影響之外,還有一些因素也會導致資料庫的效能下降,比如熱塊(hot block)的問題,當一個塊被多個使用者同時讀取的時候,Oracle 為了維護資料的一致性,需要使用Latch 來序列化使用者的操作,當一個使用者獲得了這個Latch,其他的使用者就只能被迫的等待,獲取這個資料塊的使用者越多,等待就越明顯,就造成了這種熱塊問題。這種熱塊可能是資料塊,也可能是回滾段塊。

對於資料塊來講,通常是資料塊上的資料分佈不均勻導致,如果是索引的資料塊,可以考慮建立反向索引來達到重新分佈資料的目的,對於回滾段資料塊,可以適當多增加幾個回滾段來避免這種爭用。

OLAP(On-Line Analytical Processing)資料庫
OLAP 資料庫在記憶體上可優化的餘地很小,甚至覺得增加CPU 處理速度和磁碟I/O 速度是最直接的提高資料庫效能的方式,但這將意味著著系統成本的增加。實際上,使用者對OLAP 系統性能的期望遠遠沒有對OLTP 效能的期望那麼高。

對於OLAP 系統,SQL 的優化顯得非常重要

試想,如果一張表中只有幾千資料,無論執行全表掃描或是使用索引,對我們來說差異都很小,幾乎感覺不出來,但是當資料量提升到幾億或者幾十億或者更多的時候,全表掃描,索引可能導致極大的效能差異,因此SQL得優化顯得重要起來。

分割槽技術在OLAP 資料庫中很重要

這種重要主要是體現在資料管理上,比如資料載入,可以通過分割槽交換的方式實現,備份可以通過備份分割槽表空間,刪除資料可以通過分割槽進行刪除。

聯機事務處理(OLTP)和聯機分析處理(OLAP)的不同
聯機事務處理(OLTP)和聯機分析處理(OLAP)的不同,主要通過以下五點區分開來。

1.使用者和系統的面向性:
OLTP是面向顧客的,用於事務和查詢處理 
OLAP是面向市場的,用於資料分析

2.資料內容:
OLTP系統管理當前資料. 
OLAP系統管理大量歷史資料,提供彙總和聚集機制.

3.資料庫設計:
OLTP採用實體-聯絡ER模型和麵嚮應用的資料庫設計. 
OLAP採用星型或雪花模型和麵向主題的資料庫設計.

4.檢視:
OLTP主要關注一個企業或部門內部的當前資料,不涉及歷史資料或不同組織的資料 
OLAP則相反.

5.訪問模式:
OLTP系統的訪問主要由短的原子事務組成.這種系統需要並行和恢復機制. 
OLAP系統的訪問大部分是隻讀操作

OLTP是傳統的關係型資料庫的主要應用,主要是基本的、日常的事務處理,例如銀行交易。

OLAP是資料倉庫系統的主要應用,支援複雜的分析操作,側重決策支援,並且提供直觀易懂的查詢結果。
---------------------