我得到了一个需要解决的问题,其中在主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