当前位置: 首页 > 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.dtcms.com/a/270772.html

相关文章:

  • qml加载html以及交互
  • python安装pandas模块报错问题
  • Opencv探索之旅:从像素变化到世界轮廓的奥秘
  • Adobe Illustrator 2025 安装图文教程 | 快速上手平面设计
  • 让AI绘图更可控!ComfyUI-Cosmos-Predict2基础使用指南
  • 分治算法---快排
  • ts学习1
  • 宏集案例 | 基于CODESYS的自动化控制系统,开放架构 × 高度集成 × 远程运维
  • 打破传统,开启 AR 智慧课堂​
  • react16-react19都更新哪些内容?
  • 【LeetCode 热题 100】136. 只出现一次的数字——异或
  • Deepoc具身智能大模型:送餐机器人如何学会“读心术”
  • Java结构型模式---装饰者模式
  • Vue3 Element plus table有fixed列时错行
  • Embarcadero Delphi 12.3 Crack
  • C++ 中最短路算法的详细介绍
  • B站排名优化:从算法密码到流量密钥的全方位解析
  • vue快速上手
  • 前端开发自动化设计详解
  • 【牛客刷题】游游的字母串
  • 2023年IEEE TITS SCI2区TOP,增强回溯搜索算法EBSA+多无人机辅助商业包裹递送系统飞行规划,深度解析+性能实测
  • NLP:初识RNN模型(概念、分类、作用)
  • HarmonyOS应用开发者高级试题2025年7月部分单选题
  • 【深度学习】【入门】Sequential的使用和简单神经网络搭建
  • Selenium+Pytest自动化测试框架实战前言#
  • 使用LLaMA-Factory微调Qwen2.5-VL-3B 的目标检测任务-数据集格式转换(voc 转 ShareGPT)
  • Mac mini 高性价比扩容 + Crossover 游戏实测 全流程手册
  • SpringCloud系列 - Seata 分布式事务(六)
  • AJAX 学习
  • 如何将华为手机中的照片传输到电脑