溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Oracle如何修改壓縮數(shù)據(jù)

發(fā)布時間:2021-11-09 10:58:38 來源:億速云 閱讀:107 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫

這篇文章將為大家詳細(xì)講解有關(guān)Oracle如何修改壓縮數(shù)據(jù),小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

我們將看到只有在直接路徑加載、CTAS(create table as select)和"alter table move"時,基礎(chǔ)表壓縮機制才可以生效。同時當(dāng)表啟用了壓縮時,Oracle會默認(rèn)的將該表中數(shù)據(jù)塊的pctfree設(shè)置為0,這也暗示了我們基礎(chǔ)壓縮應(yīng)該作為一種只讀數(shù)據(jù)的壓縮策略。

當(dāng)我們查看一個對應(yīng)塊的dump文件時,會發(fā)現(xiàn)Oracle并不是“壓縮”數(shù)據(jù),他所做的是在每個塊上創(chuàng)建重復(fù)值列表(即字典表),然后通過一些標(biāo)志來代替那些重復(fù)值從而達(dá)到塊級別的去重。并且,Oracle可以重新排列塊中的字段順序,從而增加用一個標(biāo)志來代替多個字段的機會。這告訴我們,Oracle在讀取塊時并不需要“解壓”數(shù)據(jù),他需要做的僅僅是通過指針來重構(gòu)數(shù)據(jù),當(dāng)然這是一個CPU密集型操作。

在這篇文章中,我們將討論如果不遵從只讀原則將會發(fā)生什么。然后,我們將會在第三篇文章中探討需要另外授權(quán)的OLTP壓縮。如前所述,以下所有示例都來自O(shè)racle 11.2.0.3的實例。

去重與刪除

你可以回憶下上篇文章中,我把一個包含組合標(biāo)志的數(shù)據(jù)塊的一行dump出來,然后Oracle遞歸的向上查找這個標(biāo)志代表的意義,最終確定該組合標(biāo)志由兩個單獨的標(biāo)志和兩個額外的字段值組合而成,下面就是我們測試的那行:

tab 1, row 0, @0x1b28

tl: 5 fb: --H-FL-- lb: 0x0 cc: 4

col 0: [ 4] 41 41 41 41

col 1: [10] 41 41 41 41 41 41 41 41 41 41

col 2: [ 2] c1 02

col 3: [10] 20 20 20 20 20 20 20 20 20 31

bindmp: 2c 00 01 04 31

這是我們在查找引用的單個標(biāo)志的值時所發(fā)現(xiàn)的**49號標(biāo)志**:

Tab 0, row 49, @0x1ed0

tl: 19 fb: --H-FL-- lb: 0x0 cc: 4

col 0: [ 4] 41 41 41 41

col 1: [10] 41 41 41 41 41 41 41 41 41 41

col 2: [ 2] c1 02

col 3: [10] 20 20 20 20 20 20 20 20 20 31

bindmp: 00 08 04 36 40 ca c1 02 d2 20 20 20 20 20 20 20 20 20 31

bindmp中的前5個字節(jié)告訴我們這個標(biāo)志在這個塊中使用了8次(00 08),由4個列組成,然后我們來看看54(0x36)和64(0x40)號標(biāo)志:

tab 0, row 54, @0x1f74

tl: 7 fb: --H-FL-- lb: 0x0 cc: 1

col 0: [ 4] 41 41 41 41

bindmp: 00 0a cc 41 41 41 41


tab 0, row 64, @0x1f7b

tl: 13 fb: --H-FL-- lb: 0x0 cc: 1

col 0: [10] 41 41 41 41 41 41 41 41 41 41

bindmp: 00 05 d2 41 41 41 41 41 41 41 41 41 41

從上面的dump數(shù)據(jù)我們可以猜到,如果想要刪除原始行,就必須進(jìn)行額外的工作。 \

有兩件事必然會發(fā)生:

1. 該行必須標(biāo)志為已刪除(以正常的方式),

2. **49號標(biāo)志**的“使用計數(shù)”也必須減少1。

在刪除一行之后,這里有一個小的片段,首先是行條目本身:

tab 1, row 0, @0x1b28

tl: 2 fb: --HDFL-- lb: 0x2

bindmp: 3c 02

以下是**49號標(biāo)志**的二進(jìn)制轉(zhuǎn)儲,注意,第二個字節(jié):

bindmp: 00 07 04 36 40 ca c1 02 d2 20 20 20 20 20 20 20 20 20 31

所以我們可以意識到,即使是刪除簡單的一行,也會使維護塊數(shù)據(jù)的工作增加。但是這個標(biāo)志同時也在塊的其他7行中使用,所以如果我刪除這些行,會發(fā)生什么?答案取決于刪除的并發(fā)會話數(shù)量。如果我使用一個進(jìn)程來刪除所有8行,在刪除第8行時,Oracle刪除了標(biāo)志,此時63號標(biāo)志和64號標(biāo)志必須更新,以顯示它們?nèi)鄙倭艘粋€依賴項。如果我重復(fù)測試使用多個會話來刪除行,并且在每次刪除后不提交,那么我就可以看到一個場景,標(biāo)志顯示為零,但不會消失。(也有可能我還沒有觀察到的一些后續(xù)的塊清理操作將會清除這個狀態(tài)的標(biāo)志。)

在我提到并發(fā)測試之前,我沒有提到任何關(guān)于提交或回滾的內(nèi)容。標(biāo)志的改變發(fā)生在delete這個動作上,并且之后并沒有提交。如果我提交或回滾會發(fā)生什么?

在提交時,可能會發(fā)生通常的提交清除操作,用提交時的SCN更新事務(wù)的ITL插槽(換句話說,沒有新的或特別的事情發(fā)生)。在回滾時,數(shù)據(jù)根據(jù)undo信息恢復(fù),任何已經(jīng)被刪除的標(biāo)志也將被重新創(chuàng)建,任何相關(guān)標(biāo)志的使用數(shù)都會增加。

但重點是,回滾之后,壓縮依然會保留。雖然這些行會在回滾后寫入塊的空閑空間,但在原始塊和回滾后的塊之間還是有一些區(qū)別。因為這樣的操作需要塊經(jīng)過空閑空間碎片的整合操作。所以如果你再次將塊dump出來,你可以看到塊的內(nèi)容已經(jīng)被移動了。在我的例子里(刪除了引用49號標(biāo)志的8行記錄,然后回滾),我看到了如下的區(qū)別:

tab 0, row 49, @0x1ed0 -- original position of token 0

tab 0, row 49, @0x134a -- position of token 0 after rollback


tab 1, row 0, @0x1b28 -- original position of row 0

tab 1, row 0, @0x1322 -- position of row 0 after rollback

壓縮與空閑空間

當(dāng)你刪除然后回滾數(shù)據(jù)后,行就會移動,這個現(xiàn)象引出了關(guān)于空閑空間非常有趣的一點——當(dāng)你的表是基礎(chǔ)壓縮的時候,默認(rèn)的pctfree就是0了。沒有空閑空間,但有空間給我在回滾后移動數(shù)據(jù)用?

我發(fā)現(xiàn)Oracle確實會保留一點點空間(大約幾十byte,但對于我測試用例里的兩整行也是絕對足夠了)。這一小部分空間允許Oracle恢復(fù)那些已被刪除的行。有些情況,這部分剩余空間甚至能讓你做update操作。

我來微調(diào)下我的初始數(shù)據(jù)集,每一行看起來如下:

 (1000001, 'AAAA', 'AAAAAAAAAA','         1')

第一列是一個序列,第二列從AAAA到EEEE循環(huán),第三列從AAAAAAAAAA到JJJJJJJJJJ循環(huán),最后一列是10個字符,從1-50循環(huán)(占位符用"\ "表示)。然后我生成800行數(shù)據(jù)。由于我創(chuàng)建數(shù)據(jù)的方法問題,第一個數(shù)據(jù)塊中有11行數(shù)據(jù),第二第三列都是A,所以我需要運行如下sql然后dump表中的第一個塊來觀察發(fā)生了什么。

update t1

set

        vc_rep = 'BBBB'

where

        vc_rep = 'AAAA'

and     vc_cycle = 'AAAAAAAAAA'

and     rownum <= 4

;

這證明了這個塊里有足夠的空間來更新這兩行記錄,而且始終在同一個塊里,但是我的行還是發(fā)生了遷移。這里有這個數(shù)據(jù)塊中某行在操作前后的dump數(shù)據(jù)對比:

tab 1, row 0, @0x1bb8 -- before

tl: 11 fb: --H-FL-- lb: 0x0 cc: 4

col 0: [ 4] 41 41 41 41

col 1: [10] 41 41 41 41 41 41 41 41 41 41

col 2: [10] 20 20 20 20 20 20 20 20 20 31

col 3: [ 5] c4 02 01 01 02

bindmp: 2c 00 02 03 1b cd c4 02 01 01 02


tab 1, row 0, @0x4f3 -- after

tl: 37 fb: --H-FL-- lb: 0x2 cc: 4

col 0: [ 4] 42 42 42 42

col 1: [10] 41 41 41 41 41 41 41 41 41 41

col 2: [10] 20 20 20 20 20 20 20 20 20 31

col 3: [ 5] c4 02 01 01 02

bindmp: 2c 02 04 00 cc 42 42 42 42 d2 41 41 41 41 41 41 41 41 41 41 d2 20 20 20 20 20 20 20 20 20 31 cd c4 02 01 01 02

在update操作后,Oracle將該行擴展成了完整的四列數(shù)據(jù)。有兩個標(biāo)志在字典表中,可以被用來替換更新的這行記錄的前兩個字段。但是Oracle并沒有去試圖尋找并使用這些標(biāo)志。所以,這么看來,好像update壓縮的數(shù)據(jù)就會造成整體的混亂,一行壓縮的記錄可能會擴展的及其巨大,微不足道的那點空閑空間無法裝下這些數(shù)據(jù),最終引發(fā)了行的遷移。

雖然我們現(xiàn)在看來,當(dāng)出現(xiàn)擴展的行以及遷移的行之后,數(shù)據(jù)會有點混亂。但當(dāng)我們執(zhí)行回滾操作時,Oracle會把這些混亂清理干凈,而且剩余的行也都會在原始壓縮的、未遷移的位置。

所以update操作到底能造成多么糟糕的影響?回答這個問題之前,我們可以先看下我所做的update操作。我修改了一個標(biāo)志可以代替的值,而且該值在很多行中都存在。但如果我修改了一個標(biāo)志無法代替的值呢?Oracle還會因為這個update來擴展這行記錄嗎?答案是否定的。如果我們修改了ID(序列類型,不重復(fù),無法標(biāo)志化)的值。下面是修改前會的dump數(shù)據(jù)對比:

tab 1, row 0, @0x1bb8 -- before

tl: 11 fb: --H-FL-- lb: 0x0 cc: 4

col 0: [ 4] 41 41 41 41

col 1: [10] 41 41 41 41 41 41 41 41 41 41

col 2: [10] 20 20 20 20 20 20 20 20 20 31

col 3: [ 5] c4 02 01 01 02

bindmp: 2c 00 02 03 1b cd c4 02 01 01 02


tab 1, row 0, @0x1bb8 -- after

tl: 10 fb: --H-FL-- lb: 0x2 cc: 4

col 0: [ 4] 41 41 41 41

col 1: [10] 41 41 41 41 41 41 41 41 41 41

col 2: [10] 20 20 20 20 20 20 20 20 20 31

col 3: [ 4] c3 64 64 64

bindmp: 2c 02 02 03 1b cc c3 64 64 64

update操作后的數(shù)據(jù)依然在原來的位置,并未發(fā)生遷移。但是請注意該行由一個可代表前三行的標(biāo)志和一個實際的值組成。行擴展并未發(fā)生。

我初始測試的那行數(shù)據(jù)實際上整行都可以被一個標(biāo)志所代替。如果我更新一個被多個標(biāo)志組合起來的行中的某個標(biāo)志化的字段會怎樣?Oracle并不會擴展整行——它只會擴展update操作影響的那列的數(shù)據(jù)。這里是操作前后的dump數(shù)據(jù):

tab 1, row 18, @0x1ac2

tl: 13 fb: --H-FL-- lb: 0x0 cc: 4

col 0: [ 4] 44 44 44 44

col 1: [10] 58 58 58 58 58 58 58 58 58 58

col 2: [10] 20 20 20 20 20 20 20 20 33 34

col 3: [ 5] c4 02 01 01 14

bindmp: 2c 00 04 03 32 37 45 cd c4 02 01 01 14


tab 1, row 18, @0x1ab8

tl: 23 fb: --H-FL-- lb: 0x2 cc: 4

col 0: [ 4] 44 44 44 44

col 1: [10] 59 59 59 59 59 59 59 59 59 59

col 2: [10] 20 20 20 20 20 20 20 20 33 34

col 3: [ 5] c4 02 01 01 14

bindmp: 2c 02 04 00 32 d2 59 59 59 59 59 59 59 59 59 59 45 cd c4 02 01 01 14

在這個測試的最開始,dump數(shù)據(jù)就表明了這行由三個獨立的標(biāo)志(0x32, 0x37和0x45)和一個實際數(shù)值組成。我將第一列的值‘XXXXXXXXXX’更新為‘YYYYYYYYYY’,正如你所見,最后一塊dump數(shù)據(jù)依然包含標(biāo)志0x32和0x45,但是標(biāo)志0x37已經(jīng)被實際值所替換掉。你也可以看到行的長度增加了10字節(jié)(從13b增加到23b),這意味著Oracle不得不把它移動到那很小的一部分空閑空間中,所以最終行的地址發(fā)生了變化。

所以當(dāng)你試圖更新基礎(chǔ)表壓縮中的數(shù)據(jù)時,Oracle可能將標(biāo)志擴展為實際值,但它會盡可能的做最小化的擴展。即使數(shù)據(jù)在壓縮后pctfree為0的情況下數(shù)據(jù)塊中依然有一小部分空間。所以雖然你可以在不造成大量擴展以及行遷移的情況下做一些極小量的update操作,但這些副作用幾乎不可能被預(yù)知。

如果你確實需要對已壓縮的數(shù)據(jù)做一些小量的維護操作,就需要對實際數(shù)據(jù)做足夠多的測試來尋找最合適的pctfree的值,以將行遷移率控制在可接受的范圍。

關(guān)于“Oracle如何修改壓縮數(shù)據(jù)”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI