数据表创建参数介绍
創建數據表create table是我們對數據庫進行的常見操作。我們一般使用create table之后,指定了數據列信息和主鍵等約束信息,其他就交給Oracle使用默認值了。今天我們一起來看看這些默認值。說明:本片只關注一般數據表,臨時表、聚簇、IOT等特殊類型暫時不考慮。
?
提取完整的DDL
?
首先我們需要提取出創建數據表的完整DDL語句,才能將Oracle提供的默認值們正確抽取出來。此處我們使用dbms_metadata.get_ddl方法。
//源數據抽取腳本
set serveroutput on size 10000;
set timing on;
?
declare
?c_ddl clob;
begin
?c_ddl := dbms_metadata.get_ddl('TABLE','DEPT','SCOTT');
?
?dbms_output.put_line(c_ddl);
end;
/
//輸出結果
?CREATE TABLE "SCOTT"."DEPT"
??(???"DEPTNO" NUMBER(2,0),
???"DNAME" VARCHAR2(14),
???"LOC" VARCHAR2(13),
????CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO")
?USING INDEXPCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
?STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
?PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
?TABLESPACE "USERS"?ENABLE
??)
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
?STORAGE
(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
?PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
?TABLESPACE "USERS"
?
?
上面是使用Oracle自帶的源數據導出工具,對Scott用戶下的數據表EMP進行提取的DDL語句。
?
?
注意:其上有兩個片段(標注紅色)是相似。這個要說明一下,我們建立一個數據表,在Oracle中要建立數據段data?segment對象。同時,如果我們指定了主鍵,Oracle會自動為這個主鍵建立索引,索引是一種索引段index segment對象。所以,如果在建立數據表的時候,也指定了主鍵primary key,那么一共會生成兩個段segment對象。
?
下面,我們對相似的代碼參數片段進行分析。
?
1、PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
2、STORAGE
(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
?PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
3、TABLESPACE "USERS"
?
?
代碼段可以分為三個部分,下面分別進行介紹。
?
Part1、數據塊Data Block與表屬性部分
?
標注1部分表示是數據塊結構和使用參數,以及我們的數據表在使用中的一些參數。
?
在Oracle中,數據庫邏輯結構被劃分為“表空間Tablespace、段對象Segment、分區extent和塊block”。其中,block是最小的結構對象。
?
ü???????PCTFREE:為數據更新準備的“留白”
?
數據終究是要寫入到數據塊里面的。對數據表中的塊block來說,都會依次填滿行數據。而Oracle寫數據表的順序是首先找到一個空閑塊,之后向空閑塊中寫入數據。
?
那么Oracle如何判斷這個數據塊是否非空閑呢?就是使用PCTFREE參數了,該參數是一個百分比值,默認為10%。如果一個數據塊空閑的空間低于PCTFREE設定值,就認為這個數據塊已經寫滿。會將這個塊從空閑塊的列表(FREELIST)上取下來。
?
那么,為什么要有這個參數?為什么要保留這10%呢?答案就是為了進行update使用。數據保存在數據行里,隨著不斷的更新,每行所占有的空間是一個不定的范圍。在數據插入之后,如果發生存儲空間增加(比如:varchar2類型字符長度變化),余下的10%就留作數據行空間延展使用。
?
那么,如果超過這個10%,還是不能裝下數據怎么辦?Oracle定位數據使用的物理rowid機制,實際上就是定位特定的數據行在某個數據塊的第幾個slot(槽)上。如果一個數據塊再也裝不下一些數據行,那么這些數據行就需要另找一個新的數據塊進行保存。也就意味著這些行有一個新的new-rowid位置。但是,Oracle還會按照原來的old-rowid定位數據行。原來的數據塊上,記錄著該數據行的新位置new-rowid,再次找到新的數據行位置。這個技術過程就稱為行遷移(row migrate)。
?
注意:我們要讀一個數據行的內容。理論上希望訪問的數據塊越少越好,最好只有一個塊。但是,如果發生行遷移,我們就不得不訪問多個數據塊才能得到數據。所以,行遷移是我們通常不希望看到的。解決的方法,就是保留一個適當的PCTFREE值。
?
?
選擇合適的PCTFREE的值要根據系統的性質而定。如果是一個典型的OLTP系統,數據更新操作多,變化大。這時候就需要設置一個略大些的PCTFREE。相反,如果更新很少,大部分都是讀操作,PCTFREE略小些也無礙。
?
?
PCTFREE意味著一種空間的閑置。如果需要進行某種數據表壓縮,設置PCTFREE為0也是一種思路。
?
?
ü???????PCTUSED:數據塊的判定容量底線
?
剛才我們談論PCTFREE的時候,介紹了Oracle在寫入數據的時候,是將新數據寫入到數據塊中,直到認為已經滿了后,再尋找新塊寫入。這個過程相反的是,如果一個過去寫滿的數據塊,經過若干次刪除后,會逐漸變空,那么什么時間點才能認為這個塊是一個空閑塊,能接受新的數據插入呢?
?
這就是PCTUSED參數的用途。如果一個數據塊的使用容量低于PCTUSED設置的限制,那么就認為這個數據塊已經空閑,可以放置回FREELIST列表中,作為空閑數據塊接受新數據行的插入。
?
?
一般是不需要調節這個參數的,筆者認為,頻繁的數據塊空閑或者寫滿切換,是有損于數據庫性能的。所以,設置默認的40%一般是可以接受的。對一些數據變化巨大,刪除頻繁的系統,這個參數可以配合PCTFREE統一籌劃。
?
?
ü???????INITRANS和MAXTRANS
?
初始事務INITRANS和最大事務MAXTRANS是在數據塊級別的參數。Oracle行級鎖是Oracle最大的特點之一。數據庫事務的本質還是對數據塊的修改,而事務的信息是記錄在數據塊頭。
?
參數INITRANS的作用就是表示數據塊上可以標記的初始事務數目。如果同時進行的事務數據量超過這個數量,事務數目可以增加,直到達到MAXTRANS的限制。
?
?
從性能角度看,我們不希望一個數據塊同時進行過多的事務。因為這樣起碼意味著數據塊過熱。所以,建議設置一個合理的INITRANS。
?
ü???????COMPRESS壓縮參數
?
Compress參數含義很清楚:就是在存儲數據表數據的時候是否啟用壓縮選項。壓縮使用的級別是數據塊block級別。Oracle對數據塊的壓縮采用相鄰相同值合并的壓縮算法。
?
Compress參數有兩個系列參數:
?
1、OMPRESS FOR DIRECT_LOAD OPERATIONS:作用于Compress相同,適合于數據倉庫OLAP系統。只在直接插入過程中在表或者分區上啟用壓縮技術;
2、COMPRESS FOR ALL OPERATIONS:適合于OLTP系統,針對所有的操作均啟用了壓縮選項。要求的版本較高。
?
下面,我們通過一個小實驗,來確定壓縮效果。首先,構建兩個數據表test和test1,數據量和順序相同,只是參數不同。
?
SQL> conn scott/tiger@orcl;
Connected to Oracle Database?10g?Enterprise Edition Release 10.2.0.1.0
Connected as scott
?
SQL> set timing on;
SQL> create table testnocompressas select * from all_objects where 1=0;
Table created
Executed in 0.11 seconds
?
SQL> insert /*+append */ into test select * from all_objects;
40724 rows inserted
(提交和重復執行該語句,篇幅原因省略…)
?
SQL> insert into test?select * from test;
122170 rows inserted
Executed in 8.412 seconds
?
SQL> select count(*) from test;
?COUNT(*)
----------
???244340
Executed in 0.872 seconds
?
SQL> exec dbms_stats.gather_table_stats('SCOTT','TEST',cascade => true);
PL/SQL procedure successfully completed
Executed in 2.354 seconds
?
//壓縮數據表
SQL> create table test1compressas select * from all_objects where 1=0;
Table created
Executed in 0.17 seconds
?
SQL> insert /*+append */ into test1 select * from all_objects;
40724 rows inserted
Executed in 2.724 seconds
(提交和重復執行該語句,篇幅原因省略…)
?
SQL> insert into test1?select * from test1;
122172 rows inserted
Executed in 1.562 seconds
?
SQL> commit;
Commit complete
Executed in 0.03 seconds
SQL> select count(*) from test1;
?
?COUNT(*)
----------
???244344
?
Executed in 0.03 seconds
?
SQL> exec dbms_stats.gather_table_stats('SCOTT','TEST1',cascade => true);
?
PL/SQL procedure successfully completed
?
Executed in 0.501 seconds
?
?
兩個數據表數據量和結構完全相同,內容也相同。經過分析后,我們檢查數據字典反應的情況。
?
SQL> select segment_name, segment_type, bytes/1024/1024 MB, blocks, extents from user_segments where?segment_name in ('TEST','TEST1');
?
SEGMENT_NA SEGMENT_TY????????MB????BLOCKS???EXTENTS
---------- ---------- ---------- ---------- ----------
TEST1?????TABLE?????????????17??????2176????????32
TEST??????TABLE?????????????28??????3584????????43
?
Executed in 0.08 seconds
?
?
結果很清楚了,在沒有使用壓縮技術的TEST數據表,占有空間28MB,共3584個數據塊。而采用過數據庫壓縮技術后,空間使用到了17MB,共2176個數據塊,空間節省39%左右。
?
進一步實驗,根據Oracle壓縮的方法,我們嘗試將近似的行之間相同數據情況增加。all_objects視圖中,owner和object_type相似度較高,選擇性低,這樣我們組織數據形態。
?
//構建實驗數據表三
SQL> create table test2 compress as select * from test1order by owner,object_type;
?
Table created
Executed in 5.719 seconds
?
SQL> exec dbms_stats.gather_table_stats(user,'TEST2',cascade => true);
?
PL/SQL procedure successfully completed
Executed in 1.102 seconds
?
SQL> select segment_name, segment_type, bytes/1024/1024 MB, blocks, extents from user_segments where?segment_name in ('TEST','TEST1','TEST2');
?
SEGMENT_NA SEGMENT_TY????????MB????BLOCKS???EXTENTS
---------- ---------- ---------- ---------- ----------
TEST1?????TABLE?????????????17??????2176????????32
TEST??????TABLE?????????????28??????3584????????43
TEST2?????TABLE?????????????10??????1280????????25
?
Executed in 0.08 seconds
?
?
按照算法特征進行整理之后,數據表大小便為了10M,壓縮率提高到了64%。
?
ü???????LOGGING:日志記錄
LOGGING參數表示對數據表或者其他對象進行變化性操作的時候,是否計入到REDO日志中。默認情況下,Oracle對數據庫對象的任何修改性操作都會計入到redo log中,作為數據庫恢復使用。開啟logging功能,是保證數據庫數據一致性的重要一步。
?
有一些時候,我們可能會不希望記日志操作。因為logging的時候會存在相當的性能損失,為了避免這種損失,加快操作速度,我們可能會選擇暫時性的設置數據表為nologging狀態。比如,我們在進行大規模數據加載的時候,可能就會選擇這種方式。
?
?
先不論nologging的好壞,有幾個問題筆者需要說明。首先,啟用數據表的nologging絕不意味著說一點重做日志都不書寫。在運行過程中,數據表對應的索引對象等內容,都有一個重建的過程,這個過程是需要寫入redo log的。第二,不啟用redo log,的確會帶來一定的性能提升。但是沒有日志的數據庫是極其危險的,一旦發生實例崩潰或者數據庫崩潰這種情況,數據庫數據丟失和不一致的情況是可能發生的。這種方法得不償失。
總結
- 上一篇: oracle11g-asm实例中asml
- 下一篇: oracle 11gR2 新增deins