在使用 YashanDB 过程中,一位用户因执行大数据量插入操作而导致全库卡死,后续操作全部报错:

YAS-02016 no free undo blocks

该问题背后,其实是 UNDO空间管理不当+大事务操作未做拆分 所引发的连锁反应。

一、问题现场回顾

客户执行如下操作:

insert into target_table
select * from big_table; -- 源表数据量达 100G+
执行持续时间长达 20 小时未完成;

客户为进行后续操作,强行kill +重启数据库;

之后数据库一直处于回滚状态,任何 SQL 操作均失败,并报错:

YAS-02016 no free undo blocks
二、环境信息

image.png
三、问题根因分析

事务太大,超出 UNDO 最大容量
源表数据 100G,而 UNDO 表空间最大仅 64G;
插入期间未做任何分批或索引优化;
image.png

导致 rollback 阶段也需要大量 UNDO 空间,但空间已满,写入失败。

强制 kill 导致 rollback 更慢
kill 后数据库自动执行 rollback;
rollback 过程中不能 truncate、不能重用 UNDO,只能原样重放;
且 rollback 阶段不能新增 undo file(会报 YAS-02042),空间释放完全依赖 rollback 完成;
索引过多,导致 IO 写入慢,进一步拖慢进度。
回滚期间 UNDO 空间未释放,影响全局操作
rollback 期间,所有新事务都需申请 UNDO;

但 UNDO 被大事务“霸占”,没有空闲块,导致所有操作都失败。

四、处理过程与关键操作

操作 1:尝试扩展 UNDO 空间(失败)

alter tablespace undo_ts add datafile 'undo02.dbf' size 10g;
报错:YAS-02042 cannot execute tablespace DDL when the database is rolling back

操作 2:尝试缩短 UNDO 保留时间(效果有限)

alter system set UNDO_RETENTION = 3;
alter system checkpoint;
提交事务的 UNDO 可被释放;

但回滚事务仍占用空间,无法提前释放。

操作 3:删除目标表索引,提升 rollback IO 速度(效果显著)

rollback 前写入速度仅 400K/s;

删除索引后提升至 4MB/s;

rollback 完成耗时从数小时缩短至 20 分钟。

操作 4:rollback 后重建 undo 策略

增加两个 UNDO 数据文件;

修改插入逻辑,改为分批插入 + 拆分事务提交。

五、经验建议与总结

线上环境避免大事务

image.png

1、UNDO 空间提前规划

默认最大 64G,虽然支持自动扩展,但到上限后需手动扩容; 建议在大数据导入前手动添加数据文件,提升上限。

2、大事务建议先删除索引再导入

插入前删除或设置为 UNUSABLE; 插入完成后再 create index 或 rebuild; 可显著提升写入和 rollback 性能。

3、回滚期间尽量不操作系统

rollback 期间不建议频繁尝试新操作;

可通过 v$rollback、iostat 等观察进度;

避免再次触发新一轮 “YAS-02016” 错误。


数据库砖家
1 声望0 粉丝