首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Oracle 19c迁移遇到大容量lob表怎么办?

背景

从Oracle数据库官方服务支持生命周期表,我们可以清晰看到Oracle 11g已过主支持生命周期,2020年后不再支持。基于这个背景,某客户的应用系统数据库将从IBM AIX小型机环境迁移到某国产数据库一体机,同时数据库版本从11g直接升级为19c。

LOB字段带来的问题

经过分析,此数据库的数据量不大,只有区区3TB,同时由于停机时间非常充分,可以考虑采取数据泵datapump的方式实现数据迁移。但是在仔细查看后,发现数据库中有个单表2TB,仔细再查2TB基本全是lob字段,且不是分区表,这个问题就有点棘手了。

根据以往的经验来看,这种大容量TB级的lob表,使用以往常规导出的方式,大概率会报Ora-01555。

稍稍测试一下,果不其然。

解决方法

一般的方法可以修改一下undo_retention参数以及lob字段的retention设置来解决,大致如下:

代码语言:javascript
复制
alter system set undo_retention=7200 scope=both;
alter table table_name MODIFY LOB(col_name)(retention);

然而当前的数据库是一个生产环境,参数修改这样的风险工程还是少做为妙,因此需要另辟蹊径。既然ORA-01555是由于长时间查询引起,我们可以尝试减少倒出的数据量。

最后决定用Expdp的Query试一试,但是2TB的数据量的单表lob还是第一次,那么根据哪个条件进行Query导出呢?

首先需考虑到是根据主键和索引列进行导出,这样的效率会比较高。确认后,问题又来了,索引列不满足均匀分批条件,故这个思路走不通了。

要怎样才能均分呢?看来只能用Rowid试试看。

首先Rowid是用于定位数据库中一条记录的一个相对唯一地址值。通常情况下,该值在该行数据插入到数据库表时即被确定且唯一。Rowid是一个伪列,它并不实际存在于实体表中。

它是Oracle在读取表中数据行时,根据每一行数据的物理地址信息编码而成的一个伪列。所以根据一行数据的Rowid能找到一行数据的物理地址信息,从而快速地定位到数据行,而且使用Rowid来进行单记录定位速度是最快的。

上图是Rowid的结构图,主要包含4个部分:

  • 第一部分6位表示:该行数据所在的数据对象的Data_object_id
  • 第二部分3位表示:该行数据所在的相对数据文件的id
  • 第三部分6位表示:该数据行所在的数据块的编号
  • 第四部分3位表示:该行数据的行的编号

一个扩展Rowid采用10个byte来存储,共80bit,其中obj#32bit, rfile#10bit, block#22bit, row#16bit。所以相对文件号不能超过1023,也就是一个表空间的数据文件不能超过1023个(不存在文件号为0的文件),一个Datafile只能有2^22=4M个 block,一个block中不能超过2^16=64K行数据的由来。

了解了Rowid后,怎么进行均匀分批呢?我们可以利用Oracle提供的DBMS_ROWID 包。

导出脚本修改如下

参数说明

  • Content=DATA_ONLY:只导出表中的数据,导出会更快,导入时也更快,index之类的对象在data导入后单独处理;
  • COMPRESSION=DATA_ONLY:数据量太大,节省空间,传输到新环境时效更高;
  • Query=“……”:将表数据根据条件进行分批导出全部数据。

为什么选用rowid_block_number呢?因为导出这个大表的需求下,Object_id就一个,分不了批次,Fileid只有150个,BLOCK_ID 是126924个,ROW_NUMBER是19,数据量数值进行Mod取余分批的差异就越小,所以使用rowid_block_number。使用这个方法后还是很顺利地导出了数据。

将参数文件复制并修改取模的余数值,分为十个进程并发执行。查看全部导出日志,每个批次耗时相差不大,满足均匀分批导出的计划。

小结

遇到超大lob表导出需要,一般的思路是尽可能通过分区或者过滤查询减少单表数据导出的数据量,减少整体耗时,办法可以分为:

1、查看是否是分区表,分区表的话按分区导出

代码语言:javascript
复制
userid=' / as sysdba'
directory=DMP
dumpfile=export.dmp
logfile=export.log
CONTENT=DATA_ONLY
COMPRESSION=DATA_ONLY
tables=(
onwer.tbale_name:part_name
)

2、业务沟通,是否存在均匀分布的字段值,按照字段值分批导出,例如

代码语言:javascript
复制
USERID=' / as sysdba'
directory= DMP
CONTENT=DATA_ONLY
COMPRESSION=DATA_ONLY
dumpfile=export.dmp
logfile=export.log
tables=owner.table_name
QUERY="WHERE column_name > 100000

3、不满足以上的都可以使用本文rowid方式进行导出

代码语言:javascript
复制
Cat exp_owner_table_seq.par
USERID='/ as sysdba'
directory= DMP
CONTENT=DATA_ONLY
COMPRESSION=DATA_ONLY
dumpfile=export.dmp
logfile=export.log
tables=owner.table_name
QUERY="wheremod(dbms_rowid.rowid_block_number(rowid),10)=1"

作者介绍

梁铭图,新炬网络首席架构师,十多年数据库运维、数据库设计、数据治理以及系统规划建设经验,拥有Oracle OCM、Togaf企业架构师(鉴定级)、IBM CATE等认证,曾获dbaplus年度MVP以及华为云MVP等荣誉,并参与数据资产管理国家标准的编写工作。在数据库运维管理和架构设计、运维体系规划、数据资产管理方面有深入研究。

王涛,新炬网络资深数据库专家,长期服务于运营商、金融、制造业及政企客户。扎根客户一线,多次主导运营商数据库大版本升级,擅长数据割接及同步技术的研究和应用,割接实战经验丰富。

本文由 dbaplus 社群授权转载。

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/OeYzdcZDravM7wqu3ymw
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券