程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle數據庫基礎 >> Oracle數據庫中段管理方式的詳細介紹

Oracle數據庫中段管理方式的詳細介紹

編輯:Oracle數據庫基礎

用Oracle數據庫10g通過回收浪費的空間、聯機重組表格和評估增長的趨勢,有效地在段中進行存儲管理。近來,有人要求我評估一個與 Oracle 數據庫競爭的RDBMS。在供應商的演示過程中,觀眾認為“最棒”的特性是,對聯機重組的支持——該產品可以聯機重新部署數據塊,以使段的等價物更簡潔,並且不會影響當前的用戶。

那時,Oracle還沒有在Oracle 9i數據庫中提供這種功能。但是現在,有了Oracle數據庫10g,就可以輕松地聯機回收浪費的空間和壓縮對象——正好適合於起步者。

不過,在檢驗該特性之前,讓我們看一看處理這項任務的“傳統的”方法。

當前慣例

考慮讓我們看一個段,如一張表,其中填滿了塊,如圖1 所示。在正常操作過程中,刪除了一些行,如圖2 所示。現有就有了許多浪費的空間:(i)在表的上一個末端和現有的塊之間,以及(ii)在塊內部,其中還有一些沒有刪除的行。

 
圖 1:分配給該表的塊。用灰色正方形表示行

Oracle不會釋放空間以供其他對象使用,有一條簡單的理由:由於空間是為新插入的行保留的,並且要適應現有行的增長。被占用的最高空間稱為最高使用標記(HWM),如圖2所示:

 
圖 2:行後面的塊已經刪除了;HWM 仍保持不變

但是,這種方法有兩個主要的問題:

當用戶發出一個全表掃描時,Oracle始終必須從段一直掃描到HWM,即使它什麼也沒有發現。該任務延長了全表掃描的時間。

當用直接路徑插入行時 — 例如,通過直接加載插入(用APPEND提示插入)或通過SQL*Loader直接路徑 — 數據塊直接置於HWM之上。它下面的空間就浪費掉了。

在Oracle9i及其以前的版本中,可以通過刪除表,然後重建表並重新加載數據來回收空間;或通過使用ALTER TABLE MOVE命令把表移動到一個不同的表空間中來回收空間。這兩種處理方式都必須脫機進行。另外,可以使用聯機表重組特性,但是這需要至少雙倍的現有表空間。

在10g中,該任務已經變得微不足道了;假如您的表空間中支持自動段空間管理(ASSM),您現在可以縮小段、表和索引,以回收空閒塊並把它們提供給數據庫以作他用,讓我們看看其中的緣由。

10g中的段管理方式

設想有一個表BOOKINGS,它保存有經由Web站點的聯機登記。當一個登記確認後,就會把它存儲在一個存檔表BOOKINGS_HIST中,並從BOOKINGS表中刪除該行。登記和確認之間的時間間隔依據客戶有很大的不同,由於無法從刪除的行獲得足夠的空間,因此許多行就插入到了表的 HWM 之上。

現在您需要回收浪費的空間。首先,准確地查明在可回收的段中浪費了多少空間。由於它是在支持ASSM的表空間中,您將不得不使用DBMS_SPACE包的SPACE_USAGE過程,如下所示:

declare

l_fs1_bytes number;
l_fs2_bytes number;
l_fs3_bytes number;
l_fs4_bytes number;
l_fs1_blocks number;
l_fs2_blocks number;
l_fs3_blocks number;
l_fs4_blocks number;
l_full_bytes number;
l_full_blocks number;
l_unformatted_bytes number;
l_unformatted_blocks number;
begin
dbms_space.space_usage(
segment_owner => user,
segment_name  => 'BOOKINGS',
segment_type  => 'TABLE',
fs1_bytes => l_fs1_bytes,
fs1_blocks => l_fs1_blocks,
fs2_bytes => l_fs2_bytes,
fs2_blocks => l_fs2_blocks,
fs3_bytes => l_fs3_bytes,
fs3_blocks => l_fs3_blocks,
fs4_bytes => l_fs4_bytes,
fs4_blocks => l_fs4_blocks,
full_bytes => l_full_bytes,
full_blocks=> l_full_blocks,
unformatted_blocks => l_unformatted_blocks,
unformatted_bytes => l_unformatted_bytes
);
dbms_output.put_line(' FS1 Blocks = '
    ||l_fs1_blocks||' Bytes = '||l_fs1_bytes);
dbms_output.put_line(' FS2 Blocks = '
    ||l_fs2_blocks||' Bytes = '||l_fs1_bytes);
dbms_output.put_line(' FS3 Blocks = '
    ||l_fs3_blocks||' Bytes = '||l_fs1_bytes);
dbms_output.put_line(' FS4 Blocks = '
    ||l_fs4_blocks||' Bytes = '||l_fs1_bytes);
dbms_output.put_line('Full Blocks = '
    ||l_full_blocks||' Bytes = ||l_full_bytes);
end;
/

輸出結果如下:

FS1 Blocks = 0 Bytes = 0
FS2 Blocks = 0 Bytes = 0
FS3 Blocks = 0 Bytes = 0
FS4 Blocks = 4148 Bytes = 0
Full Blocks = 2 Bytes = 16384

這個輸出結果顯示有4,148個塊,具有75-100%的空閒空間(FS4);沒有其他空閒塊可用。這裡僅有兩個得到完全使用的塊。4,148個塊都可以回收。

接下來,您必須確保該表支持行移動。如果不支持,您可以使用如下命令來支持它:

alter table bookings enable row movement;

或通過Administration頁上的企業管理器10g。您還要確保在該表上禁用所有基於行id的觸發器,這是因為行將會移動,行id可能會發生改變。

最後,您可以通過以下命令重組該表中現有的行:

alter table bookings shrink space compact;

該命令將會在塊內重新分配行,如圖3所示,這就在HWM之下產生了更多的空閒塊,但是HWM自身不會進行分配。

 
圖 3:重組行後的表中的塊

在執行該操作後,讓我們看一看空間利用率所發生的改變。使用在第一步展示的PL/SQL塊,可以看到塊現在是如何組織的:

FS1 Blocks = 0 Bytes = 0
FS2 Blocks = 0 Bytes = 0
FS3 Blocks = 1 Bytes = 0
FS4 Blocks = 0 Bytes = 0
Full Blocks = 2 Bytes = 16384

注意這裡的重要改變:FS4塊(具有75-100%的空閒空間)的數量現在從4,148降為0。我們還看到FS3塊(具有50-75%的空閒空間)的數量從0增加到1。但是,由於HWM沒有被重置,總的空間利用率仍然是相同的。我們可以用如下命令檢查使用的空間:

SQL> select blocks from user_segments 
    where segment_name = 'BOOKINGS';

BLOCKS
---------
4224

由該表占用的塊的數量(4,224)仍然是相同的,這是因為並沒有把 HWM 從其原始位置移開。可以把HWM移動到一個較低的位置,並用如下命令回收空間:

alter table bookings shrink space;

注意子句COMPACT 沒有出現。該操作將把未用的塊返回給數據庫並重置HWM。可以通過檢查分配給表的空間來對其進行測試:

SQL> select blocks from user_segments
    where segment_name = 'BOOKINGS';

BLOCKS
----------
8

塊的數量從4,224降為8;該表內所有未用的空間都返回給表空間,以讓其他段使用,如圖4 所示。

 
圖 4:在收縮後,把空閒塊返回給數據庫

這個收縮操作完全是在聯機狀態下發生的,並且不會對用戶產生影響。

也可以用一條語句來壓縮表的索引:

alter table bookings shrink space cascade;

聯機shrink命令是一個用於回收浪費的空間和重置HWM的強大的特性。我把後者(重置HWM)看作該命令最有用的結果,因為它改進了全表掃描的性能。

找到收縮合適選擇

在執行聯機收縮前,用戶可能想通過確定能夠進行最完全壓縮的段,以找出最大的回報。只需簡單地使用dbms_space包中的內置函數verify_shrink_candidate。如果段可以收縮到1,300,000字節,則可以使用下面的PL/SQL代碼進行測試:

begin
if (dbms_space.verify_shrink_candidate
('ARUP','BOOKINGS','TABLE',1300000)
then
:x := 'T';
else
:x := 'F';
end if;
end;
/

PL/SQL過程成功完成。

SQL> print x

X
--------------------------------
T
如果目標收縮使用了一個較小的數,如 3,000:
begin
if (dbms_space.verify_shrink_candidate
('ARUP','BOOKINGS','TABLE',30000)
then
:x := 'T';
else
:x := 'F';
end if;
end;

變量x 的值被設置成'F',意味著表無法收縮到3,000字節。現在假定您將著手在一個表上,或者也許是一組表上創建一個索引的任務。除了普通的結構元素,如列和單值性外,您將不得不考慮的最重要的事情是索引的預期大小 — 必須確保表空間有足夠的空間來存放新索引。

在Oracle數據庫9i 及其以前的版本中,許多DBA使用了大量的工具(從電子數據表到獨立程序)來估計將來索引的大小。在10g中,通過使用DBMS_SPACE包,使這項任務變得極其微不足道。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved