ORACLE 11g 用exp命令導出庫文件備份時,發現只能導出來一部分表而且不提示錯誤,之前找不到解決方案只能把沒導出來的表重新建建立。后來發現是所有的空表都沒有導出來。於是想好好查查,因為在以前的10g版本中沒有這樣的問題。
查資料發現Oracle 11g中有個新特性:新增了一個參數“deferred_segment_creation”含義是段延遲創建,默認是true。
具體是什么意思呢?
如果這個參數設置為true,你新建了一個表Table1,並且沒有向其中插入數據,那么這個表不會立即分配extent,也就是不占數據空間,即表也不分配 segment 以節省空間,所以這些表也沒能導出來。在系統表user_tables中也可以看到segment_treated的字段里是“NO”或者“YES”說明了某張表是否分配了segment。說白了是為了可以節省少量的空間。
用下面的SQL語句查詢,可以發現沒有導出的表其 segment_created 字段值都是 'NO'。
Select segment_created,table_name from user_tables where segment_created = 'NO';
解決方法:
1、最原始最笨的辦法(不推薦):insert一行,再rollback或者刪除就產生segment了。
該方法是在在空表中插入數據,再刪除,則產生segment。導出時則可導出空表。
2、設置deferred_segment_creation 參數:
設置deferred_segment_creation 參數為FALSE來禁用"段推遲創建"(也就是直接創建segment),無論是空表還是非空表,都分配segment。
在sqlplus中,執行如下命令:
SQL>alter system set deferred_segment_creation=false;
查看:
SQL>show parameter deferred_segment_creation;
注意:該值設置后只對后面新增的表產生作用,對之前建立的空表(已經存在的)不起作用,仍不能導出。
並且要重新啟動數據庫,讓參數生效。
3、使用ALLOCATE EXTENT,可以導出之前已經存在的空表。
使用ALLOCATE EXTENT可以為數據庫對象的每一張表分配Extent(注意針對每一張表,就是說一張表需要一條SQL代碼):
其語法如下:
-----------
ALLOCATE EXTENT { SIZE integer [K | M] | DATAFILE 'filename' | INSTANCE integer }
-----------
可以針對數據表、索引、物化視圖等手工分配Extent。
ALLOCATE EXTENT使用樣例:
ALLOCATE EXTENT
ALLOCATE EXTENT(SIZE integer [K | M])
ALLOCATE EXTENT(DATAFILE 'filename')
ALLOCATE EXTENT(INSTANCE integer) www.2cto.com
ALLOCATE EXTENT(SIZE integer [K | M] DATAFILE 'filename')
ALLOCATE EXTENT(SIZE integer [K | M] INSTANCE integer)
針對數據表操作的完整語法如下:
-----------
ALTER TABLE [schema.] table_name ALLOCATE EXTENT [({ SIZE integer [K | M] | DATAFILE 'filename' | INSTANCE integer})]
-----------
故,需要構建如下樣子簡單的SQL命令:
-----------
alter table TableName allocate extent
-----------
但要是每一張表寫一條語句的話太過麻煩,為了方便我們使用SQL命令拼寫出每一張表的alter語句。
構建對空表分配空間的SQL命令。
查詢當前用戶下的所有空表(一個用戶最好對應一個默認表空間)。命令如下:
SQL>select table_name from user_tables where NUM_ROWS=0;
根據上述查詢,可以構建針對空表分配空間的命令語句,如下:
SQL>Select 'alter table '||table_name||' allocate extent;' from user_tables where num_rows=0 or num_rows is null(注意:很多教程沒有這里,這里是有可能位空的)
上述代碼可產生批量的修改表extent的SQL語句(有多少張空表就產生多少條),我們只需要將其生成的所有sql代碼全部執行,就可以給每一張已經存在的表來分配segment,就OK了。
最后:這時再用exp導出就沒有問題了。但是:數據庫本身的deferred_segment_creation屬性還是TRUE,也是就是說如果再創建新表的話,默認還是不分配segment的。所以還是需要更改deferred_segment_creation的參數,以便以后創建的新表自動分配segment。
總結:
如果你的數據庫還沒有創建任何數據表,那么直接修改deferred_segment_creation屬性,以后創建的表無論是不是為空都會自動分配segment,就不會出現導不出空表的情況。然而如果你的數據庫中已經有很多空表,並且需要導出來,那么光修改deferred_segment_creation屬性則沒有用的,因為它只對之后創建的表有作用。你需要給已存在的空表分配segment以便可以導出存在的空表,就用到上面講的allocate extent方法,但此方法只針對已經存在的表的segment屬性,所以最好就是:先給已存在的空表分配segment,方便其可以直接導出,然后設定deferred_segment_creation參數以便以后每張表無論是否為空都自動分配segment。
附錄:有關第三種方法給已經存在的空表分配segment,下面介紹一種生成腳本來執行sql的方法。
SQL>Select 'alter table '||table_name||' allocate extent;' from user_tables where num_rows=0 or num_rows is null;
批量輸出上述生成的SQL語句並寫入到一個.sql的腳本文件中。
如:
1. 創建執行腳本文件:我創建一個E:\sql_script.sql文件。內容如下:
set heading off;
set echo off;
set feedback off;
set termout on;
spool E:\sql_allocate.sql;
Select 'alter table '||table_name||' allocate extent;' from user_tables where num_rows=0 or num_rows is null;
spool off;
這個腳本的作用就是創建一個E:\sql_allocate.sql腳本文件,將Select 'alter table '||table_name||' allocate extent;' from user_tables where num_rows=0 or num_rows is null的執行結果(就是給每張表生成segment的SQL代碼)批量輸出,存儲到一個E:\sql_allocate.sql的腳本文件中。
2. 執行E:\sql_script.sql文件來生成“分配表空間的SQL代碼”的腳本文件sql_allocate.sql。
命令如下:
SQL>@ E:\sql_script.sql; (也可寫一個批處理文件,命令如下:sqlplus 用戶名/密碼@數據庫 @E:\sql_script.sql)
執行完畢后,得到E:\sql_allocate.sql腳本文件(里面是給所有空表分配segment的SQL代碼)。
打開該文件會看到,已經得到對所有空表分配空間的SQL語句。
3. 執行E:\sql_allocate.sql文件來對表分配空間。
命令如下:SQL>@ E:\sql_allocate.sql
執行完畢,表已更改。之前存在的空表已分配segment空間!
大功告成,此時執行exp命令,即可把包括空表在內的所有表,正常導出。
轉自:http://blog.sina.com.cn/s/blog_5f0e9ca50101it7n.html