当前位置: 首页 > news >正文

迁移Oracle SH 示例 schema 到 PostgreSQL

接着上一篇文章:迁移Oracle HR 示例 schema 到 PostgreSQL中,本文做Oracle SH(Sales History)示例 schema的迁移,SH schema比HR schema更大更复杂,本次迁移的重点是:

  • 分区表
  • 外部数据加载

使用的是Oracle 19c的示例 schema,下载命令如下:

git clone --depth 1 --branch v19c https://github.com/oracle-samples/db-sample-schemas.git

SH schema的安装脚本为sales_history/sh_main.sql,其主要构成按序为(以下省略.sql后缀):

  1. csh_v3:创建表
  2. lsh_v3:加载数据到表
  3. psh_v3:加载后的操作

我们也按以上顺序来迁移。依次形成了以下脚本:

  • csh_v3.sql:创建表
  • lsh_v3.sql:加载数据
  • cons_v3.sql:创建约束
  • idx_v3.sql:创建索引
  • views_v3.sql:创建视图,物化视图
  • cmnts_v3.sql:创建注释

csh_v3:创建表

这部分比较容易,分区的语法对应上就好,另外建立约束的部分放在数据加载后来做。

还有PG并没有Oracle的OLTP表压缩功能。

Oracle的分区语法丰富,普适性较强。例如范围分区支持VALUES LESS THAN。PG只支持FOR VALUES FROM … TO。不过问题不大。

看一个sales表的示例。

Oracle语法:

CREATE TABLE sales (prod_id             NUMBER          NOT NULL,cust_id             NUMBER          NOT NULL,time_id             DATE            NOT NULL,channel_id          NUMBER          NOT NULL,promo_id            NUMBER          NOT NULL,quantity_sold       NUMBER(10,2)    NOT NULL,amount_sold         NUMBER(10,2)    NOT NULL)PARTITION BY RANGE (time_id)( partition sales_1995 VALUES LESS THAN(TO_DATE('1996-01-01 00:00:00','SYYYY-MM-DD HH24:MI:SS','NLS_CALENDAR=GREGORIAN')) COMPRESS,partition sales_1996 VALUES LESS THAN(TO_DATE('1997-01-01 00:00:00','SYYYY-MM-DD HH24:MI:SS','NLS_CALENDAR=GREGORIAN')) COMPRESS,
...

PostgreSQL的语法:

CREATE TABLE sales (prod_id             NUMERIC                 NOT NULL,cust_id             NUMERIC                 NOT NULL,time_id             DATE            NOT NULL,channel_id          NUMERIC         NOT NULL,promo_id            NUMERIC                 NOT NULL,quantity_sold       NUMERIC(10,2)   NOT NULL,amount_sold         NUMERIC(10,2)   NOT NULL)PARTITION BY RANGE (time_id);CREATE TABLE sales_1995 PARTITION OF salesFOR VALUES FROM (MINVALUE) TO ('1996-01-01');CREATE TABLE sales_1996 PARTITION OF salesFOR VALUES FROM ('1996-01-01') TO ('1997-01-01');...

lsh_v3:加载数据到表

这部分消耗时间最多,主要在数据文件的格式转换。Oracle是用SQL Loader,PostgreSQL则用COPY。

💡 先厘清一个概念。对于DATE数据类型,PG的精度是到天,而Oracle的精度是到秒。

本部分处理的主要问题:

  • 1:Oracle示例表中用DATE定义的列,实际只需要到天就可以了,但数据文件中的值却是1998-12-27-00-00-00,而非1998-12-27。所以我们需要去掉尾部的00-00-00
  • 2:多余的分隔符。按说3个字段只需要2个分隔符,但Oracle也支持尾部再多放一个分隔符。而PG不认,我们只需要去掉行末的分隔符即可。
  • 3:数据文件的字段比表的字段多
  • 4:建立外部表

问题1的处理较简单,例如对于times表:

\copy times from program 'sed "s/-00-00-00//g" time_v3.dat'WITH (FORMAT csv,DELIMITER '|'
);

用元命令而非SQL命令的原因在于要使用相对路径。

问题2的处理也是用sed,例如对于countries表:

\copy countries from program 'sed "s/|$//g" coun_v3.dat'WITH (FORMAT csv,DELIMITER '|'
);

有些表同时出现了问题1和2,例如customers表和products表:

\copy customers from program 'sed "s/-00-00-00//g;s/|$//g" cust1v3.dat'WITH (FORMAT csv,DELIMITER '|'
);

问题3的处理稍微不同,出于性能考虑,预处理生成了中间文件,而非之前的即时处理。例如对于sales表,他只有7个字段,而数据文件有9个字段。

即时处理如下,但结果1小时后也没出来,所以放弃了:

\copy sales from program 'sed "s/-*[0-9]\+\(\.[0-9]\+\)\?|$//g"|sed "s/|-*[0-9]\+\(\.[0-9]\+\)\?|$//g" sale1v3.dat'WITH (FORMAT csv,DELIMITER '|'
);

预处理方式如下:

sampledb=> \timing
Timing is on.sampledb=> \! time sed "s/-*[0-9]\+\(\.[0-9]\+\)\?|$//g" sale1v3.dat > 1real    0m34.503s
user    0m33.504s
sys     0m0.271s
sampledb=> \! time sed "s/|-*[0-9]\+\(\.[0-9]\+\)\?|$//g" 1 > 2real    0m19.119s
user    0m18.517s
sys     0m0.226s
sampledb=> \! mv 2 sale1v3_pg.dat
sampledb=> \copy sales from sale1v3_pg.datWITH (FORMAT csv,DELIMITER '|'
);
COPY 916039
Time: 9422.693 ms (00:09.423)

可以看到,预处理用了近54秒,导入用了9秒。

问题4的例子是costs表。他其实用到了之前9个字段的数据文件。

外部表的建立用了file_fdw扩展,这是PG原生的扩展,详见这里。

CREATE FOREIGN TABLE sales_transactions_ext
( PROD_ID               NUMERIC,CUST_ID               NUMERIC,TIME_ID               DATE,CHANNEL_ID    NUMERIC,PROMO_ID              NUMERIC,QUANTITY_SOLD   NUMERIC,AMOUNT_SOLD   NUMERIC(10,2),UNIT_COST     NUMERIC(10,2),UNIT_PRICE    NUMERIC(10,2)
) SERVER file_server
OPTIONS
(
format 'csv', filename 'sale1v3_fdw.dat', delimiter '|'
);

需要特别说明,我用的是相对路径,因此需要把数据文件拷贝到PG服务器可访问的目录,如$PGDATA。不过还是建议用绝对路径。

psh_v3:加载后的操作

我没有psh_v3.sql,而是用idx_v3.sql,views_v3.sql和cmnts_v3.sql对应。

最后

所有的脚本都在Github上了,下一篇我们迁Customer Orders 示例 schema。

http://www.xdnf.cn/news/1090819.html

相关文章:

  • 双指针-15.三数之和-力扣(LeetCode)
  • 算法核心知识复习:排序算法对比 + 递归与递推深度解析(根据GESP四级题目总结)
  • Oracle 数据库升级踩坑:DBLink ORA-02019 问题解决思路
  • 使用 Docker 搭建 Rust Web 应用开发环境——AI教你学Docker
  • 工程改Mvvm
  • 一天一道Sql题(day04)
  • 基于lottie的微信小程序动画开发指南
  • CSS中的Element语法
  • 仓颉语言 1.0.0 升级指南:工具链适配、collection 操作重构与 Map 遍历删除避坑
  • ali linux 安装libreoffice
  • 《重构项目》基于Apollo架构设计的项目重构方案(多种地图、多阶段、多任务、状态机管理)
  • Context Engineering:从Prompt Engineering到上下文工程的演进
  • Ragas的Prompt Object
  • 微软 Bluetooth LE Explorer 实用工具的详细使用分析
  • JVM字节码加载与存储中的细节
  • 川翔云电脑:突破硬件极限,重构设计生产力范式
  • 【vim中替换】
  • 【自动驾驶】经典LSS算法解析——深度估计
  • BEV感知算法:自动驾驶的“上帝视角“革命
  • django 一个表中包括id和parentid,如何通过parentid找到全部父爷id
  • 免费扫描软件NAPS2:跨平台支持 旋转裁剪 + 多页合并,纸质文档变 PDF / 图片
  • 详解Kafka重平衡机制详解
  • Python(30)基于itertools生成器的量子计算模拟技术深度解析
  • 18-C#改变形参内容
  • 《设计模式之禅》笔记摘录 - 5.代理模式
  • AI应用实践:制作一个支持超长计算公式的计算器,计算内容只包含加减乘除算法,保存在一个HTML文件中
  • 设计模式(行为型)-责任链模式
  • Flink Forward Asia 2025 主旨演讲精彩回顾
  • 两张图片对比clip功能
  • React 19 概览:新特性与生态系统变革