Oracle 19c Blob批量迁移至S3 Glacier性能优化咨询
问题背景
场景
本地Oracle 19c数据库中有一张在线表,包含不到10个字符串列和1个存储PDF二进制数据的Blob列。每个Blob平均大小为2MB,表总容量约9TB。
需求
表内共有1000万条记录,需基于过期标记布尔列,将900万条记录的Blob值迁移至S3 Glacier存储库,同时删除原表中这些Blob数据,并更新原表的archive_id列以存储Glacier归档的引用ID,从而节省Oracle存储空间。
初始方案
开发了基于AWS SDK Glacier Client的Java应用,负责Blob上传与表数据更新。采用每次500条的批量处理逻辑避免Java堆内存错误,核心代码如下:
//FileEntity包含fileId、byte[]类型的pdf字段和archiveId字段 void migrateBlobs(){ List<FileEntity> files = jpaRepository.getNextBatch(); // 获取500条数据约耗时16秒 files.forEach( fileItem -> { String archiveId = uploadClient.uploadFile(fileItem.getPdf()); fileItem.setArchiveId(archiveId); jpaRepository.save(fileItem); // 每条数据保存耗时2-4秒 }); }
客户端初始化及上传代码:
@Bean public AmazonGlacier glacierClient(){ return AmazonGlacierClient.builder() .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, "region")) .withCredentials(new AWSStaticCredentialsProvider(awsCreds)) .build(); } public String uploadFile(byte[] pdf){ UploadArchiveRequest uploadRequest = new UploadArchiveRequest() .withVaultName(vaultName) // 代码中的环境变量 .withBody(new ByteArrayInputStream(pdf)) .withContentLength((long) pdf.length); UploadArchiveResult uploadResult = glacierClient.uploadArchive(uploadRequest); return uploadResult.getArchiveId(); }
现存问题
该操作为一次性任务,但生产环境处理速度极慢——试运行1小时仅处理1500条记录,需优化性能以确保在1-2周内完成迁移。
咨询问题
- 是否可通过单次HTTP请求将500个PDF上传至S3 Glacier存储库,而非逐个上传?
- 是否有AWS服务可替代Java应用,完成文件上传及原表
archive_id的更新?
解决方案
问题1:批量上传S3 Glacier的可能性
S3 Glacier原生不支持单次请求上传多个归档,每个UploadArchive API调用仅能上传单个归档文件,但可通过以下方式优化上传效率:
- 并行上传:放弃串行的
forEach处理,改用线程池(如ExecutorService)并行执行上传任务,线程数可根据网络带宽调整(建议20-50线程),大幅压缩总上传耗时。 - 复用Glacier客户端:确保Glacier客户端为单例复用模式,避免每次上传重复初始化客户端,减少连接建立开销。
- 流式读取Blob:不要将整个Blob加载至
byte[]内存,直接从Oracle获取Blob输入流传递给Glacier上传请求,既减少内存占用,又避免内存拷贝的额外耗时。
问题2:替代Java应用的AWS服务组合
可通过以下AWS服务组合实现低代码/无代码迁移,无需自行维护Java应用:
- AWS DMS + S3 + Lambda
- 用AWS Database Migration Service (DMS)从Oracle抽取需归档的Blob数据,先导出至S3标准存储桶,再通过S3生命周期规则自动归档至Glacier。
- 借助Lambda触发S3对象归档事件,获取Glacier的
archive_id,再通过JDBC批量更新Oracle表的archive_id列。
- AWS Lambda + 批量SQL
- 用Lambda替代Java应用,设置定时/批量触发逻辑,每次拉取500条数据并行上传至Glacier,之后通过批量SQL(而非单条保存)更新Oracle表:
UPDATE your_table SET archive_id = CASE file_id WHEN ? THEN ? WHEN ? THEN ? ... END WHERE file_id IN (...) - Lambda支持弹性伸缩,可配置更高内存(对应更高CPU与网络带宽)提升处理速度,注意控制单批次处理量以避免15分钟执行超时限制。
- 用Lambda替代Java应用,设置定时/批量触发逻辑,每次拉取500条数据并行上传至Glacier,之后通过批量SQL(而非单条保存)更新Oracle表:
- S3 Batch Operations + Lambda
- 先将所有Blob导出至S3,再用S3 Batch Operations批量将对象归档至Glacier,最后通过Lambda批量获取每个对象的
archive_id并更新Oracle表。
- 先将所有Blob导出至S3,再用S3 Batch Operations批量将对象归档至Glacier,最后通过Lambda批量获取每个对象的
额外Oracle端优化建议
- 为过期标记列添加索引,优化
getNextBatch()的查询效率,避免全表扫描。 - 替换逐条
save为批量更新SQL,将500条更新操作压缩为1条SQL,大幅降低数据库交互耗时。
内容的提问来源于stack exchange,提问作者Niteesh Bhargava
相关产品推荐
相关产品推荐

