我得到了一個需要解決的問題,其中在主Db中有一個名爲Scenarios的表,其中包含所有需要查找大小的表空間的詳細信息。 O/P應該包含表大小(實際消耗)和索引大小以及行數。因此,我編寫了一個調整腳本(PL/SQL)來查找特定DB服務器上所有表空間的大小。遇到異常ORA-01555
但是我運行了幾天之後就會遇到這個特殊的異常。
ORA-01555:快照太舊:名稱爲「_SYSSMU9 $」過小
回滾段9號我不知道什麼可能導致這一點,因爲數據量不是很大。
我附上腳本
SET SERVEROUTPUT ON size '10000000'
declare
TYPE cur_typ IS REF CURSOR;
a_Temp number := 0;
x_Total number := 0;
i number := 0;
c_cursor cur_typ;
query_str varchar2(500);
num_long Long;
currentScenarioDB nvarchar2(255);
tableExists number := 0;
scenarioId varchar2(50);
scenarioName varchar2(100);
dbIdentifier nvarchar2(50);
queryToFindScenarioNameAndId varchar2(400) := 'select scenarioId,name from scenarios where dbidentifier = ';
selectQuery varchar2(400) := 'select scenarioId,name from scenarios where dbidentifier = ';
insertStatement varchar2(2000) := 'Insert Into ScenarioTableAndIndexSize values (:1,:2,:3,:4,:5,:6,:7) ';
-- scenarioId,scenarioname,,dbIdentifier,tablename,dataSize,IndexSize,rowNumber
tableIndexSize number := 0;
numOfRows number := 0;
rowNum number := 0;
tableDataSize number := 0;
Cursor getScenarioDb is select dbidentifier from scenarios where dbidentifier IN (select Distinct(TABLESPACE_NAME) from dba_tables);
begin
DBMS_OUTPUT.ENABLE(10000000);
execute immediate 'truncate table ScenarioTableAndIndexSize';
open getScenarioDb;
fetch getScenarioDb into currentScenarioDB;
while getScenarioDb%found
loop
queryToFindScenarioNameAndId := selectQuery || '''' || currentScenarioDB || '''';
execute immediate queryToFindScenarioNameAndId into scenarioId,scenarioName;
declare
queryToFindNoofRows varchar2(1000);
queryConstruct varchar2(32767) := '';
outputTableInScenarioDb nvarchar2(256);
Cursor getTablesInScenario is select DISTINCT TABLE_NAME from dba_tables where owner = currentScenarioDB and TABLE_NAME not like 'BIN%' and table_name != 'SCENARIOTABLEANDINDEXSIZE' order by table_name;
begin
tableExists := 0;
open getTablesInScenario;
fetch getTablesInScenario into outputTableInScenarioDb;
while getTablesInScenario%found
loop
queryConstruct := 'select nvl(sum (';
tableIndexSize := 0;
tableDataSize := 0;
numOfRows := 0;
queryToFindNoofRows := 'select count(*) from '|| currentScenarioDB || '.' ||outputTableInScenarioDb;
execute immediate queryToFindNoofRows into numOfRows;
if numOfRows > 0 then
---------------------------Beginning Of Section to find Table data Size------------------------------------------------------------------------------------------------
declare
Cursor getColumnsInTables is select * from dba_tab_columns where Table_Name = outputTableInScenarioDb and owner = currentScenarioDB;
dbaTabColumnRow dba_tab_columns%rowtype;
dataType varchar2(40);
fields varchar2(1000);
begin
open getColumnsInTables;
fetch getColumnsInTables Into dbaTabColumnRow;
while getColumnsInTables%found
loop
dataType := dbaTabColumnRow.DATA_TYPE;
if dataType = 'CLOB' then
fields := 'nvl(DBMS_LOB.GETLENGTH(' || dbaTabColumnRow.COLUMN_NAME ||'),0)';
elsif dataType = 'BLOB' then
fields := 'nvl(DBMS_LOB.GETLENGTH('|| dbaTabColumnRow.COLUMN_NAME ||'),0)';
elsif dataType = 'LONG' then
fields := 'nvl(VSIZE(''''),0)';
x_Total := 0;
query_str := 'SELECT ' || dbaTabColumnRow.COLUMN_NAME || ' FROM ' || currentScenarioDB || '.' ||outputTableInScenarioDb;
OPEN c_cursor FOR query_str;
LOOP
FETCH c_cursor INTO num_long;
EXIT WHEN c_cursor%NOTFOUND;
a_Temp:=length(num_long);
x_Total:= x_Total + a_Temp;
END LOOP;
CLOSE c_cursor;
else
fields := 'nvl(vsize(' || dbaTabColumnRow.COLUMN_NAME || '),0)';
end if;
fetch getColumnsInTables Into dbaTabColumnRow;
if getColumnsInTables%found then
queryConstruct := queryConstruct || fields||'+';
else
queryConstruct := queryConstruct || fields;
end if;
end loop;
end;
queryConstruct := queryConstruct || '),0) as sizeOfTable from ' || currentScenarioDB || '.' ||outputTableInScenarioDb;
--dbms_output.put_line(queryConstruct);
execute immediate queryConstruct into tableDataSize;
---------------------------End Of Section to find Table data Size-------------------------------------------------------------------------------------------------------------
---------------Section To find index size
declare
Index_Name nvarchar2(4000);
sql_statement varchar2(1000) := 'select nvl(USED_SPACE,0) from index_stats';
stat1 varchar2(1000) := 'analyze index ';
stat2 varchar2(1000) := ' validate structure';
stat3 varchar2(2000) := '';
size1 number := 0;
cursor indexOnTable is select INDEX_NAME from dba_indexes where tablespace_name = currentScenarioDB and table_name = outputTableInScenarioDb and index_type = 'NORMAL';
begin
open indexOnTable;
fetch indexOnTable into Index_Name;
while indexOnTable%found
loop
stat3 := stat1 || currentScenarioDB ||'.' ||Index_Name || stat2;
execute immediate stat3;
execute immediate sql_statement into size1;
tableIndexSize := tableIndexSize + size1;
fetch indexOnTable into Index_Name;
end loop;
close indexOnTable;
end;
-----end of section to find index size
else
rowNum := rowNum + 1;
end if;
tableDataSize := x_Total + tableDataSize;
execute immediate insertStatement using scenarioId,scenarioName,currentScenarioDB,outputTableInScenarioDb,tableDataSize,tableIndexSize,numOfRows;
x_Total := 0;
fetch getTablesInScenario into outputTableInScenarioDb;
end loop;
end;
fetch getScenarioDb into currentScenarioDB;
end loop;
close getScenarioDb;
end;
表的大小是發現了這種方式:
- 列表項 如果該字段類型的LOB然後計算出它的大小我用nvl(DBMS_LOB.GETLENGTH(),0)
- 如果該字段的類型是Long,那麼我將遍歷所有的Long值並使用內置的Length()函數查找它們的大小
- 如果該字段是任何其他類型的我用NVL的(VSIZE(),0)
只需指定用戶有權限的所有的DB
然後我總結他們都往上找表中的總數據大小。
有人可以告訴我我做錯了什麼,或者我應該怎麼做來修復錯誤?
謝謝。
我建議你創建一個新的問題,詢問如何有效地解決手頭的問題。運行一個需要幾天時間才能完成的PL/SQL程序將會導致頭痛無期。一旦你解決了這個問題,你將不得不再次運行好幾天纔會遇到下一個問題。 – Codo 2011-04-25 09:16:54
95%的時間,長時間運行過程中的快照太舊是由於跨提交選擇/提取。我沒有深入上面的每一個細節,但我敢打賭,你有一些驅動光標從它下面正在更新的表中選擇。爲了保持讀取的一致性,Oracle需要引用回滾段來繼續從表中選擇您(或某個進程)不斷修改的數據,因此需要越來越多的回滾 – tbone 2011-04-25 12:09:04
交叉發佈[DBA StackExchange](http:// dba.stackexchange.com/questions/2358/encountering-exception-ora-01555) – Sathya 2011-04-25 16:35:58