在使用 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
二、环境信息
三、问题根因分析
事务太大,超出 UNDO 最大容量
源表数据 100G,而 UNDO 表空间最大仅 64G;
插入期间未做任何分批或索引优化;
导致 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 数据文件;
修改插入逻辑,改为分批插入 + 拆分事务提交。
五、经验建议与总结
线上环境避免大事务
1、UNDO 空间提前规划
默认最大 64G,虽然支持自动扩展,但到上限后需手动扩容; 建议在大数据导入前手动添加数据文件,提升上限。
2、大事务建议先删除索引再导入
插入前删除或设置为 UNUSABLE; 插入完成后再 create index 或 rebuild; 可显著提升写入和 rollback 性能。
3、回滚期间尽量不操作系统
rollback 期间不建议频繁尝试新操作;
可通过 v$rollback、iostat 等观察进度;
避免再次触发新一轮 “YAS-02016” 错误。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。