ORACLE 表型別 OLTP和OLAP
阿新 • • 發佈:2019-01-14
表型別
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是資料倉庫系統的主要應用,支援複雜的分析操作,側重決策支援,並且提供直觀易懂的查詢結果。 ---------------------