簡單瞭解一下壓縮表
資料被壓縮的原理在於,對於資料塊裡的重複值來說,只保留一份。儲存在資料塊裡的壓縮資料是自我包含的。也就是說,對於將壓縮的資料進行解壓來說,所有需要的資訊都在資料塊裡了,而不需要參考資料塊以外的其他資料。
資料塊裡的所有重複資料行和資料列都只存放一次,並放在資料塊的開始部分,這塊區域叫做資料塊的symbol table。也就是說,同一個資料塊裡放了兩個表的資料。這一點有點像class table。資料行裡如果存在重複的值,則該重複值去掉,並在原來的位置上放了一個很短的引用,指向symbol table。除了資料塊開始部分的symbol table以外,壓縮資料塊與普通的資料塊沒什麼兩樣。注意,在9i裡,壓縮表在建立以後就不能修改結構的,而10g則沒有這個限制了,但是不能對新增的列提供預設值。
對於壓縮資料塊的訪問來說,並沒有很消耗資源的解壓縮操作。這也就是說,在考慮是否要啟用壓縮時,並不需要考慮對於查詢效能的影響。只能在進行批量資料載入的時候,完成壓縮操作。在載入資料並壓縮過程中,CPU資源的消耗會有50%的增長。
只有當資料批量插入或載入的時候完成壓縮,這些操作包括:
·SQL*Loader的直接路徑載入。
·CREATE TABLE … COMPRESS AS SELECT。
·並行insert或帶有append提示的序列insert。你也可以發出ALTER TABLE…MOVE COMPRESS,從而將表裡已有的資料進行壓縮。
對於壓縮表的update操作的效率極其低下,如果一個表要經常被update,則不應該對該表啟用壓縮。因為update時,需要先將資料解壓,然後對解壓後的資料進行更新,更新結束以後再次壓縮。
除了LOB以外的資料型別都可以被壓縮。另外,如果表裡的列超過255個,則壓縮被禁用。也提供對索引的壓縮,包括B樹索引和bitmap索引,以及IOT表。
來了解一下壓縮表的內部結構。
SQL> create table t_seed as
2 select chr(trunc(dbms_random.value(65,67))) c1,chr(trunc(dbms_random.value(65,67))) c2,
3 trunc(dbms_random.value(0,2)) c1flag,trunc(dbms_random.value(0,2)) c2flag
4 from dba_objects where rownum<=1000;
表已建立。
SQL> create table t_comp_1 compress as
2 select decode(c1flag,1,lpad(c1,10,c1),null) as c1,
3 decode(c2flag,1,lpad(c2,10,c2),null) as c2 from t_seed;
表已建立。
SQL> select distinct dbms_rowid.rowid_relative_fno(rowid) as file#,
2 dbms_rowid.rowid_block_number(rowid) as block# from t_comp_1 order by file#,block#;
FILE# BLOCK#
---------- ----------
4 7604
4 7605
SQL> alter system dump datafile 4 block 7604;
系統已更改。
data_block_dump,data header at 0xcc19a7c
===============
tsiz: 0x1f80
hsiz: 0x5ce
pbl: 0x0cc19a7c
bdba: 0x01001db4
76543210
flag=-0------
ntab=2 這裡的2說明該資料塊裡有2個表,一個symbol table,一個實際的表。
nrow=725
frre=-1
fsbo=0x5ce
fseo=0x1147
avsp=0x3d
tosp=0x3d
r0_9ir2=0x0
mec_kdbh9ir2=0x9 這裡的9說明該資料塊裡重複值有9種情況。
76543210
shcf_kdbh9ir2=----------
76543210
flag_9ir2=--R----C
fcls_9ir2[3]={ 0 32768 32768 }
0x1c:pti[0] nrow=11 offs=0 這部分說明symbol table裡有6條記錄。
0x20:pti[1] nrow=717 offs=11 這部分說明該資料塊裡存放的實際表裡的記錄行數為717行。
0x24:pri[0] offs=0x1f61
0x26:pri[1] offs=0x1f5c
......................
tab 0, row 0, @0x1f61
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: *NULL*
col 1: *NULL*
bindmp: 00 a7 02 ff ff
tab 0, row 1, @0x1f5c
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: *NULL*
col 1: [10] 42 42 42 42 42 42 42 42 42 42
bindmp: 00 50 02 ff 0a
tab 0, row 2, @0x1f57
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: *NULL*
col 1: [10] 41 41 41 41 41 41 41 41 41 41
bindmp: 00 6c 02 ff 09
tab 0, row 3, @0x1f52
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [10] 42 42 42 42 42 42 42 42 42 42
col 1: *NULL*
bindmp: 00 55 02 0a ff
tab 0, row 4, @0x1f4d
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [10] 42 42 42 42 42 42 42 42 42 42
col 1: [10] 42 42 42 42 42 42 42 42 42 42
bindmp: 00 34 02 0a 0a
tab 0, row 5, @0x1f48
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [10] 42 42 42 42 42 42 42 42 42 42
col 1: [10] 41 41 41 41 41 41 41 41 41 41
bindmp: 00 22 02 0a 09
tab 0, row 6, @0x1f43
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [10] 41 41 41 41 41 41 41 41 41 41
col 1: *NULL*
bindmp: 00 5b 02 09 ff
tab 0, row 7, @0x1f3e
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [10] 41 41 41 41 41 41 41 41 41 41
col 1: [10] 42 42 42 42 42 42 42 42 42 42
bindmp: 00 2c 02 09 0a
tab 0, row 8, @0x1f39
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [10] 41 41 41 41 41 41 41 41 41 41
col 1: [10] 41 41 41 41 41 41 41 41 41 41
bindmp: 00 38 02 09 09
tab 0, row 9, @0x1f66
tl: 13 fb: --H-FL-- lb: 0x0 cc: 1
col 0: [10] 41 41 41 41 41 41 41 41 41 41
bindmp: 00 06 d2 41 41 41 41 41 41 41 41 41 41
tab 0, row 10, @0x1f73
tl: 13 fb: --H-FL-- lb: 0x0 cc: 1
col 0: [10] 42 42 42 42 42 42 42 42 42 42
bindmp: 00 06 d2 42 42 42 42 42 42 42 42 42 42
以上tab 0的部分就是所謂的symbol table裡所存放的記錄了。可以看到一共有11條記錄。實際就是對c1和c2這兩列所存在的值的窮舉,如下所示:
可能的情況 |
C1列 |
C2列 |
1 |
AAAAAAAAAA |
Null |
2 |
BBBBBBBBBB |
Null |
3 |
Null |
AAAAAAAAAA |
4 |
Null |
BBBBBBBBBB |
5 |
AAAAAAAAAA |
AAAAAAAAAA |
6 |
AAAAAAAAAA |
BBBBBBBBBB |
7 |
BBBBBBBBBB |
AAAAAAAAAA |
8 |
BBBBBBBBBB |
BBBBBBBBBB |
9 |
Null |
Null |
而在該資料塊裡的每條記錄就是對上面這9種情況的描述,不過它窮舉出來的情況要更多點。
多出來的也就是最後兩條cc為1的記錄。也就是說有可能只壓縮一列。在我們這個例子裡,因為只有兩個列,所以沒有這種情況。如果表裡的列很多,則有可能只壓縮一列。
在tab 0裡的每條記錄裡,記錄了c1列和c2列的可能的取值,同時還記錄了bindmp,這表示該種組合的一些後設資料。比如對於symbol table裡的row 4來說:
tab 0, row 4, @0x1f4d
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [10] 42 42 42 42 42 42 42 42 42 42
col 1: [10] 42 42 42 42 42 42 42 42 42 42
bindmp: 00 34 02 0a 0a
前兩個位元組表示該資料塊裡有多少條記錄屬於該組合。這裡為十六進位制的00 34,換算成十進位制,也就是52。說明在該資料塊裡的717條記錄當中,有52條記錄的(c1,c2)=(‘BBBBBBBBBB’,’ BBBBBBBBBB’)。02表示壓縮的列的個數為2個列。
我們來驗證一下:
SQL> select count(*) from(
2 select c1,c2 from t_comp_1 where rownum<=717)
3 where c1='BBBBBBBBBB' and c2='BBBBBBBBBB';
COUNT(*)
----------
52
tab 0以後的部分就是tab 1,這部分就是資料塊裡實際存放的記錄了。
tab 1, row 0, @0x1f34
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [10] 42 42 42 42 42 42 42 42 42 42
col 1: *NULL*
bindmp: 2c 00 01 02 03
tab 1, row 1, @0x1f2f
tl: 5 fb: --H-FL-- lb: 0x0 cc: 2
col 0: *NULL*
col 1: *NULL*
bindmp: 2c 00 01 02 00
..................
轉儲的時候,進行了解壓。把c1和c2的值都顯示出來。實際物理存放的值是:
bindmp: 2c 00 01 02 03
..................
也就是對每條記錄來說,只佔用了5個位元組。其中,2c 00應該表示symbol table的實體地址。02表示壓縮了2個欄位。03表示在symbol table裡的記錄行號。這裡的03也就是symbol table裡的row 3所記錄的c1和c2的值。換句話說,該表裡的第一條記錄的(c1,c2)也就等於('BBBBBBBBBB', Null)。
這時再建立一個壓縮表,該表裡多加兩個列:
SQL> create table t_comp_2 compress as
2 select decode(c1flag,1,lpad(c1,10,c1),null) as c1,rownum id1,
3 decode(c2flag,1,lpad(c2,10,c2),null) as c2,
4 chr(trunc(dbms_random.value(65,80))) c3 from t_seed;
表已建立。
SQL> select distinct dbms_rowid.rowid_relative_fno(rowid) as file#,
2 dbms_rowid.rowid_block_number(rowid) as block# from t_comp_2 order by file#,block#;
FILE# BLOCK#
---------- ----------
4 6900
4 6901
SQL> alter system dump datafile 4 block 6900;
系統已更改。
開啟轉儲檔案,可以看到下面的部分:
r0_9ir2=0x0
mec_kdbh9ir2=0x18
76543210
shcf_kdbh9ir2=----------
76543210
flag_9ir2=--R---OC
fcls_9ir2[4]={ 0 32768 32768 32768 }
perm_9ir2[4]={ 0 3 1 2 } 多出了這一行。
這一行非常重要,因為在壓縮表中,oracle會修改列的排列順序。非壓縮表裡,列在物理存放的時候,按照資料字典裡記錄的順序,也就是col1、col2、col3....。比如:
SQL> desc t_comp_2
名稱 是否為空? 型別
----------------------------------------- -------- ----------------------------
C1 VARCHAR2(2)
ID1 NUMBER
C2 VARCHAR2(2)
C3 VARCHAR2(2)
也就是說,正常表來說,在資料塊裡存放列時,會這樣放:
col 0 XXXXXXX ->表示放的是C1列的值
col 1 XXXXXXX ->表示放的是ID1列的值
col 2 XXXXXXX ->表示放的是C2列的值
col 3 XXXXXXX ->表示放的是C3列的值
但是,在壓縮表裡,col 0已經不表示c1列的值了,col 1也不是ID1列的值。怎麼對應呢,就是從這裡的perm_9ir2[4]={ 0 3 1 2 }來對應。這裡的0、3、1、2表示物理儲存時的列的下標。也就是說col 0對應資料字典裡的col 1,在這裡也就是C1列;col 3對應ID1;col 1對應C2;col 2對應C3。
找到tab 1部分,比如:
tab 1, row 0, @0x1ea9
tl: 9 fb: --H-FL-- lb: 0x0 cc: 4
col 0: [10] 42 42 42 42 42 42 42 42 42 42 ->表示放的是C1列的值
col 1: *NULL* ->表示放的是C2列的值
col 2: [ 1] 49 ->表示放的是C3列的值
col 3: [ 2] c1 02 ->表示放的是ID1列的值
bindmp: 2c 00 03 03 12 28 ca c1 02 ->這裡2c 00表示symbol table的地址。而03 來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9842/viewspace-344546/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 簡單瞭解一下GaussDB
- 選不好針式印表機? 瞭解一下壓縮列印吧!
- 簡單的瞭解一下AQS吧AQS
- 簡單瞭解一下pinia的結構
- 如此簡單的 SpringBoot,不瞭解一下Spring Boot
- Mysql鎖機制簡單瞭解一下MySql
- 簡單的小程式小結, 瞭解一下
- 簡單好用的js 壓縮工具JS
- Word檔案太大怎麼壓縮,分享壓縮Word的簡單方法
- 怎麼把影片壓縮?實用又簡單的壓縮影片方法
- 簡單實用的mac壓縮解壓軟體:iFastZip for Mac中文版MacAST
- Keka Mac:高效簡潔的壓縮解壓工具Mac
- 簡單瞭解一下php的迭代生成器yieldPHP
- 簡單解壓縮工具:OmniZip - Universal Extractor Pro 中文啟用版
- WebSocket 簡單瞭解Web
- JWT簡單瞭解JWT
- 批次壓縮影片大小的簡單操作分享
- 【leetcode 簡單】 第一百零六題 壓縮字串LeetCode字串
- linux下壓縮解壓縮命令Linux
- CentOS 壓縮解壓CentOS
- Linux壓縮解壓Linux
- oracle 的表壓縮Oracle
- oracle壓縮表(二)Oracle
- oracle壓縮表(一)Oracle
- Linux tar分卷壓縮與解壓縮Linux
- Hive的壓縮儲存和簡單優化Hive優化
- 【Node】簡單快捷的圖片壓縮指令碼指令碼
- 簡單瞭解組策略
- 防火牆-簡單瞭解防火牆
- Golang介面簡單瞭解Golang
- linux分卷壓縮解壓Linux
- linuxtar解壓和壓縮Linux
- Linux 常用的壓縮與解壓縮命令詳解Linux
- Linux下的tar壓縮解壓縮命令詳解Linux
- 跟我一起學Redis之Redis事務簡單瞭解一下Redis
- 提的最多的資料庫“索引”,先來簡單瞭解一下資料庫索引
- 簡單瞭解一下大資料的一些基本概念大資料
- 分卷壓縮怎麼解壓 快速解壓電腦分卷壓縮檔案方法