資料庫收縮資料檔案的嘗試(三)(r11筆記第22天)

jeanron100發表於2016-12-23

  不知道大家在資料庫運維中是否會有這樣的困擾,一個資料檔案裡沒有多少資料,但是資料檔案的大小卻調不下來,嘗試使用resize來調整屢屢失敗。如果一個資料檔案裡有很多的小表,存在大量這樣的碎片表,雖然我們從前端看不到,但是如果檢視儲存結構就會發現還是挺混亂的。

    本質上來說,Oracle也不希望我們去刻意處理這些物理儲存方面的設定,比如設定某個表一定存放在某個資料檔案裡,一個表空間裡存在10個資料檔案,一條insert語句執行下去,到底資料進了哪個資料檔案,應該不需要DBA刻意去關心,而且Oracle也沒提供這樣的資料字典來告訴你,所以我們檢視的最細粒度的儲存資料字典是dba_extents,而沒有db_blocks當然Oracle給了你一把鑰匙,那就是ROWID。透過ROWID我們可以得到很多未曾發現的問題和可能性。

    我們換一個問法,在一個事務中是否會改變ROWID?

如果是普通的增刪改操作,基於主鍵,基於資料變化,肯定是無法改變ROWID,因為ROWID本身就是一個偽列,這個偽列的效果本質上其實比主鍵還要給力,查詢效率還要高。

    如果我要做這樣一個操作,表test的資料量不大在5萬條,分佈在6,7,8三個資料檔案上,如果我們新建一個資料檔案9,希望把這些資料都遷移到9號資料檔案,而且希望保證高可用的情況下,是否可以實現?

   在這個場景中,我們就可以充分利用ROWID來玩一玩了。

我們建立一個臨時中轉的表,比如表名為test,則中轉的臨時表為tmp_test

把表test在8號資料檔案裡的資料篩查出來插入臨時的中轉表tmp_test

insert into  test.tmp_test  select * from test.test where dbms_rowid.rowid_relative_fno(rowid)=8
100 rows created.然後刪除已有的表test在8號資料檔案的資料delete from test.test where dbms_rowid.rowid_relative_fno(rowid)=8;
100 rows deleted.注意此處,這裡是一個事務,對於事務外的應用資料的查詢還是可以滿足一致性的需求。
但是因為表裡的資料量很小,所以這個過程造成的阻塞時間會很短。

然後把資料插入

insert  /*+append*/ into  mbi.test select *from test.tmp_test;
100 rows created.

完成之後就是提交commit

當然如果我們要求資料要放在指定的資料檔案裡,而不是根據資料的增長情況增量的放置,可以使用allocate的方式來處理,比如指定資料放入9號資料檔案中。

alter table  test allocate extent (size 1M datafile  '/U01/app/oracle/oradata/test/test_data09.dbf');

操作之後還是需要驗證一下,原來的資料檔案裡確實是不存在那些資料了。

select count(*)  from test.test where dbms_rowid.rowid_relative_fno(rowid)=8;
  COUNT(*)
----------
         0

這些資料還是在臨時的表裡可以查到,確認無誤之後就可以直接drop了。

select count(*)  from test.tmp_test;
  COUNT(*)
----------
        100當然一個資料庫的資料量非常大,存在上百個這樣的資料檔案有沒有什麼簡潔的方法來統一處理呢。其實是有的。採用的思路就是今天分享的內容,不過後面補充了一些更多的驗證和場景補充。能夠達到的一個基本效果就是可以一鍵式部署,感興趣可以私聊,我近期也會把指令碼開放出來。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-2131306/,如需轉載,請註明出處,否則將追究法律責任。

相關文章