为什么我基于游标的 table 复制即使在完成该过程后也会完全占用撤消 table 空间?
Why does my cursor based copying of a table leave the undo tablespace completely occupied even after finishing the procedure?
我在一个过程中将大量数据从一个 Table 复制到另一个,同时使用游标迭代一个 table 的数据,将它们保存在一个数组中,然后填充另一个批量有限。
我确实意识到有更好的方法可以做到这一点,但由于语言限制,我采用了这种方式。我的代码:
PROCEDURE copy_tableA_into_tableB IS
TYPE tableA_array IS TABLE OF tableA%ROWTYPE;
tableA_initialized_array TableIwantToCopyFrom_array;
CURSOR table_a_cursor IS
SELECT *
FROM TABLE_A; --get all data from Table_A
BEGIN
OPEN table_a_cursor;
LOOP
FETCH table_a_cursor BULK COLLECT
INTO test_copy LIMIT 10000;
FORALL i IN 1 .. table_a_cursor.COUNT
INSERT INTO TABLE_B
VALUES tableA_initialized_array (i);
COMMIT;
EXIT WHEN table_a_cursor%NOTFOUND;
END LOOP;
CLOSE table_a_cursor;
END copy_tableA_into_tableB;
只要发生一件奇怪的事情,这段代码就可以正常工作,
当我用像 150 万 table 行这样的大量数据执行它几次时,UNDO tablespace 变得越来越大,即使程序完成了它仍然由分配我的程序。最终我的 UNDO tablespace 已满,我得到一个异常。事实上,我只能放弃我的 UNDO tablespace 并重建它以使其空置并再次清空。
你可以清楚地看到我每次通过数组时都在提交,所以为什么在事务完成后 UNDO table space 仍然被分配?
我不是理解底层概念的 Oracle 专家,但我认为我的游标已关闭并在他关闭时重新分配,所以我不认为他是罪魁祸首,如果这是任何问题。
我预计当我完成该过程时,我的 UNDO table space 会再次被释放,我正在检查仍然存在的 undo table space保持不变
编辑未回答的问题:
我正在检查有多少 UNDO tablespace 我留下了数据的数量加起来,我是唯一的 运行 程序,
异常:ORA-01555:快照太旧:名称为“”的回滚段号太小
我正在 PL/SQL 开发人员中测试存储过程测试中的过程
我不会重置任何东西,只是清空我想用截断复制到的 tables。
Oracle 不会重用 space 那里有一个活动事务。
这就解释了为什么你的 tablespace 完全被占用了
更多信息在此 Undo tablespace keeps growing
如果你想知道space占用了多少
select tablespace_name,sum(bytes) from dba_segments group by tablespace_name;
这样你就可以找到实际尺寸
select tablespace_name,sum(bytes) from dba_data_files group by tablespace_name;
首先,我不明白"language restrictions"是什么意思。为什么这会阻止您进行直插入?
其次,您正在循环提交 - 说真的,这是一个非常非常糟糕的主意。您可能会发现自己收到快照太旧的错误。
第三,对于你的回答,Oracle 不会立即在 UNDO 中释放 space,一旦你完成它 - 它被标记为不再需要(你对该提交所做的事情,因此为什么跨循环获取是个坏主意!)如果另一个会话需要它 space 那么它会被覆盖。
Tom Kyte,一如既往,says it best
不就是因为开场白是:
光标 table_a_cursor 是
SELECT *
来自 TABLE_A; --从Table_A
获取所有数据
因此生成undo,以便本次查询能够成功。这些行上的锁直到完成后才会释放(此时 UNDO 表空间已满)。
这样的事情应该可行:(可能需要对循环进行一些修改 - 我个人会检查提交前处理的 'x' 而不是此方法。
PROCEDURE Copy_tableA_into_tableB AS
l_count integer
BEGIN
-- Count rows in tableA
l_count_total := 'select count(*) from table A';
EXECUTE IMMEDIATE l_sql_regexp_count
INTO l_pancount;
WHILE l_count > 0
LOOP
FETCH table_a_cursor BULK COLLECT
INTO cdplzstb_copy_batch LIMIT 10000;
FORALL i IN 1 .. table_a_cursor.COUNT
INSERT INTO TABLE_B
VALUES tableA_initialized_array (i);
COMMIT;
l_count:=l_count-1;
END LOOP;
END Copy_tableA_into_tableB;
我在一个过程中将大量数据从一个 Table 复制到另一个,同时使用游标迭代一个 table 的数据,将它们保存在一个数组中,然后填充另一个批量有限。
我确实意识到有更好的方法可以做到这一点,但由于语言限制,我采用了这种方式。我的代码:
PROCEDURE copy_tableA_into_tableB IS
TYPE tableA_array IS TABLE OF tableA%ROWTYPE;
tableA_initialized_array TableIwantToCopyFrom_array;
CURSOR table_a_cursor IS
SELECT *
FROM TABLE_A; --get all data from Table_A
BEGIN
OPEN table_a_cursor;
LOOP
FETCH table_a_cursor BULK COLLECT
INTO test_copy LIMIT 10000;
FORALL i IN 1 .. table_a_cursor.COUNT
INSERT INTO TABLE_B
VALUES tableA_initialized_array (i);
COMMIT;
EXIT WHEN table_a_cursor%NOTFOUND;
END LOOP;
CLOSE table_a_cursor;
END copy_tableA_into_tableB;
只要发生一件奇怪的事情,这段代码就可以正常工作, 当我用像 150 万 table 行这样的大量数据执行它几次时,UNDO tablespace 变得越来越大,即使程序完成了它仍然由分配我的程序。最终我的 UNDO tablespace 已满,我得到一个异常。事实上,我只能放弃我的 UNDO tablespace 并重建它以使其空置并再次清空。
你可以清楚地看到我每次通过数组时都在提交,所以为什么在事务完成后 UNDO table space 仍然被分配?
我不是理解底层概念的 Oracle 专家,但我认为我的游标已关闭并在他关闭时重新分配,所以我不认为他是罪魁祸首,如果这是任何问题。
我预计当我完成该过程时,我的 UNDO table space 会再次被释放,我正在检查仍然存在的 undo table space保持不变
编辑未回答的问题:
我正在检查有多少 UNDO tablespace 我留下了数据的数量加起来,我是唯一的 运行 程序,
异常:ORA-01555:快照太旧:名称为“”的回滚段号太小
我正在 PL/SQL 开发人员中测试存储过程测试中的过程 我不会重置任何东西,只是清空我想用截断复制到的 tables。
Oracle 不会重用 space 那里有一个活动事务。 这就解释了为什么你的 tablespace 完全被占用了
更多信息在此 Undo tablespace keeps growing
如果你想知道space占用了多少
select tablespace_name,sum(bytes) from dba_segments group by tablespace_name;
这样你就可以找到实际尺寸
select tablespace_name,sum(bytes) from dba_data_files group by tablespace_name;
首先,我不明白"language restrictions"是什么意思。为什么这会阻止您进行直插入?
其次,您正在循环提交 - 说真的,这是一个非常非常糟糕的主意。您可能会发现自己收到快照太旧的错误。
第三,对于你的回答,Oracle 不会立即在 UNDO 中释放 space,一旦你完成它 - 它被标记为不再需要(你对该提交所做的事情,因此为什么跨循环获取是个坏主意!)如果另一个会话需要它 space 那么它会被覆盖。
Tom Kyte,一如既往,says it best
不就是因为开场白是:
光标 table_a_cursor 是 SELECT * 来自 TABLE_A; --从Table_A
获取所有数据因此生成undo,以便本次查询能够成功。这些行上的锁直到完成后才会释放(此时 UNDO 表空间已满)。
这样的事情应该可行:(可能需要对循环进行一些修改 - 我个人会检查提交前处理的 'x' 而不是此方法。
PROCEDURE Copy_tableA_into_tableB AS
l_count integer
BEGIN
-- Count rows in tableA
l_count_total := 'select count(*) from table A';
EXECUTE IMMEDIATE l_sql_regexp_count
INTO l_pancount;
WHILE l_count > 0
LOOP
FETCH table_a_cursor BULK COLLECT
INTO cdplzstb_copy_batch LIMIT 10000;
FORALL i IN 1 .. table_a_cursor.COUNT
INSERT INTO TABLE_B
VALUES tableA_initialized_array (i);
COMMIT;
l_count:=l_count-1;
END LOOP;
END Copy_tableA_into_tableB;