sqlplus远程数据迁移及etl轻粒度加工

说明:

        本文基于linux操作系统,通过安装sqlplus客户端,使用sqlload加载数据文件到oracle数据库,执行sql脚本进行粒度加工,最后通过spool工具导出数据文件到指定目录,由shell脚本主导的数据迁移过程

一、sqlplus安装

安装包下载:

sqlplus工具包下载-官网

注:请根据自身linux系统下载相应安装包,我这里是aarch64系统;可通过命令:uname -a 查看当前系统框架。

下载对应系统工具包:

oracle-instantclient19.10-basic-19.10.0.0.0-1.aarch64

oracle-instantclient19.10-sqlplus-19.10.0.0.0-1.aarch64

oracle-instantclient19.10-tools-19.10.0.0.0-1.aarch64

安装工具包命令:

rpm -ivh ./*

当前文件夹有其他安装包时请逐个安装,无先后之分

查看客户端目录: 

whereis oracle                   #一般都是   /usr/lib/oracle

创建tnsnames.ora文件,此文件用于记录、创建dblink信息:

cd /usr/lib/oracle/19.10/client64

mkdir -p network/admin

vim tnsnames.ora

增加如下内容,创建dblink注意修改ip地址:

orcl =
    (DESCRIPTION =
      (ADDRESS_LIST =
         (ADDRESS = (PROTOCOL = TCP)(HOST = IPADDR)(PORT =1521))
      ) 
           (CONNECT_DATA =
              (SERVICE_NAME = ORCL)
           )
    )

编辑环境变量:

vim /etc/profile        

在尾部增加如下变量:

export ORACLE_HOME=/usr/lib/oracle/19.10/client64
export LD_LIBRARY_PATH=$ORACLE_HOME/lib
export TNS_ADMIN=$ORACLE_HOME/network/admin
export PATH=$ORACLE_HOME/bin:$PATH

编译环境变量使之生效:

source /etc/profile

测试连接远端oracle数据库(dwm用户):

sqlplus dwm/dwm@orcl

二、sqlload导入数据

        1.由于这里是测试和开发阶段表结构并没有固定,因此采用触发式采集表结构的方式导入数据。这里要导出表结构,因此先说一下导出数据工具spool

    spool常用的设置:

  • set head off:输出域标题,缺省为on
  • set pagesize 0:输出每页行数,缺省为24,为了避免分页,可设定为0
  • set feedback off:回显本次sql命令处理的记录条数,缺省为on
  • set linesize 2000:行宽设置的稍微大点,防止数据被截断,导致导出文本尾部有太多空格
  • set trimspool on:去除重定向(spool)输出每行的拖尾空格,缺省为off
#从数据库中提取列名,用逗号隔开,并对特殊类型做转换
sqlplus -S dwm/dwm@orcl<<EOF>/dev/null
set head off
set pagesize 0
spool /oracle/column_dwm.txt
desc table_name;
spool off
exit
EOF
sed -i '1,2d;$d' /oracle/column_dwm.txt
column_dwm=`cat /oracle/column_dwm.txt|awk '{print $1}'|xargs|sed 's/ /,/g'|sed "s/CRTTIME/crttime timestamp 'YYYY-MM-DD HH24:MI:SS.FF3'/g"`
#大部分数据类型均可自动插入,时间戳类型比较特殊需要注明数据类型

        2.使用sqlload工具将文本导入数据库需要进行两部操作:

        第一步:生成 ctl 格式的控制文件

        控制文件的组成部分:

  1. load data
  2. infile 'data_file.txt'                           --指定数据文件,可以指定多个文件
  3. insert into table_name                    --以何种方式加载,insert要求表数据为空
  4. fields terminated by ','                     --被加载数据文件的分隔符,这里以逗号为例
  5. (col1,col2,col3...)                             --导入表的列名,注意顺序

        加载数据时(基础第三步) insert 可根据需要更换加载方式:

        append                                              --追加插入,相当于增量插入

        replace                                              --替换插入,针对表中有键值约束的插入方式

        truncate                                             --清表插入,相当于全量插入

        以上五步为控制文件的基础步骤,根据实际需求会增加不同的内容

        OPTIONS(...)                                    --加载数据时的参数设置和命令显示

        CHARACTERSET  'UTF8'                --指定编码格式

        TRAILING NULLCOLS                     --表的字段没有对应值时允许为空       

        OPTIONALLY ENCLOSED BY ' " '   --数据中的包围符

        以下是shell中自动追加控制文件的样例

#此处需延用上一部生成的列名
echo "(${column_dwm})"                    >/oracle/ctl/table_name.ctl
sed -i '1i TRAILING NULLCOLS'              /oracle/ctl/table_name.ctl
sed -i '1i FIELDS TERMINATED BY ','"       /oracle/ctl/table_name.ctl
sed -i '1i TRUNCATE INTO TABLE TABLE_NAME' /oracle/ctl/table_name.ctl
sed -i "1i INFILE 'data_file_path'"        /oracle/ctl/table_name.ctl
sed -i '1i CHARACTERSET 'UTF8''            /oracle/ctl/table_name.ctl
sed -i '1i LOAD DATA'                      /oracle/ctl/table_name.ctl
sed -i '1i  OPTIONS(readsize=270900000,bindsize=270900000,rows=10000,parallel=true,errors=1,silent=(feedback))' /oracle/ctl/table_name.ctl

bindsize 每次提交记录的缓冲区的最大值,满存则提交,默认256000 Bytes

rows       每次提交的行数,默认6,最大值65534

通过bindsize的设定,要比默认值和通过参数rows计算的缓冲区大小更优先,即两者是相互制约的关系

行长*rows>bindsize则以bindsize大小提交,相反则按rows设定值提交,设定时应同时考虑两个参数的设定值

parallel   执行并行加载 

readsize 为读取数据的大小

errors     允许的错误的数目

silent      运行中隐藏消息,feedback每次提交信息 

        代码中的bindsize和rows的参数设定是通过对其中一张宽表的测试得出的最优值。从下图,log文件中标红色的部分可以算出行长根据行长预设想要提交的行数及bindsize参数。通过调整参数测出加载数据的时长,进而得出最优参数

cc80ce320e2947bdb1230b022e1f2c41.png

         第二步:加载数据

        sqlldr导入命令格式:

sqlldr dwm/dwm@orcl control=/oracle/ctl/table_name.ctl log=/oracle/logs/table_name_dwm.log bad=/oracle/logs/table_name_dwm.bad

        这里可以设置log和bad文件的保存路径,日志文件中可以看到相关控制文件中的部分参数以及报错信息,bad文件中保存加载税局过程中的报错数据

三、执行sql脚本,进行数据的粒度加工

        由于此步骤需要跨用户,且是远程操作,即数仓上面的跨层进行数据加工,因此需要角色拥有对其他用户表查询的权限。以dwm到dws两个用户为例,数据加载到dws层势必会用到dwm层的表数据,确保表存在的情况下,如果权限不足则报如下图错误,可以预先尝试跨用户对表进行 DML 操作

c53e089596714ab5896d7c3dd7dbc95d.png

        查看角色拥有的系统权限:

select * from role_sys_privs;

        查看用户拥有的系统权限:   

select * from user_sys_privs;

        在本地客户端以管理员身份授予用户权限:

grant select any table to dwm;

grant select any table to dws;

为了方便跨用户进行DML操作,我这里赋予用户所有权限;

grant all privileges to dwm;

grant all privileges to dws;

        下面就可以执行sql脚本进行数据加工

sqlplus dws/dws@orcl<<EOF>/oracle/logs/table_name_dws.log
@/oracle/sql_file/table_name.sql;
commit;
exit
EOF

        这里可以直接使用sqlplus采用@脚本存放路径来执行sql脚本,标准输出到log文件,以便查看报错信息;进行 DML 操作时注意commit

四、导出数据

        1.为了输出规范的、符合格式要求的数据文件,需要再select时用字符串连接老规范格式。比如要输出 ‘1,张三,18,广东深圳’ 这样的数据格式,就需要用select id||','||name||','||age||','||addr from emp这样的语句。因此,需要触发输出表字段拼接的字符串

#提取卸数层表字段,并用“||','||”拼接
sqlplus -S dws/dws@orcl <<EOF>/dev/null 2>&1
set head off
set pagesize 0
spool /oracle/column_dws.txt
desc table_name;
spool off
exit
EOF
sed -i '1,2d;$d' /oracle/column_dws.txt
column_dws=`cat /oracle/column_dws.txt|awk '{print $1}'|xargs|sed 's/ /||'\',\''||/g'`

        2.导出数据

        spool导出数据命令格式:

sqlplus -S dws/dws@orcl <<EOF>/dev/null
set head off
set trimspool on
set feedback off
set pagesize 0
set linesize 2500
set arraysize 5000
spool /oracle/unload/table_name.txt
select ${column_dws} from table_name;
spool off
exit
EOF

        导出数据结束!

        另外再说几个特殊报错:        

        1.SQLLDR导入数据,字段长度默认是char的极限值 255 字节,如果数据长度超过这个值就要注明长度,扩容。如字段:khzwm char(1000) 

        2.如果表字段与select,from,group等关键字重名,建表时字段要加双引号。查询时同样也要加双引号不然报错

        3.ORA-00923:FROM keyword not found where expected

        “关键字未发现”----有可能时手误写错如:FROM误写成FORM。这属于常规报错,但当你语法都改完之后还报这个错就要注意了,由于oracle存储中文默认是UTF-8格式,当有中文注释时就可能出现格式问题,导致这个报错,我这里是把SQL脚本改为UTF-8格式完美解决。

        4.SP2-0734:unknown command beginning ''....'' -rest of line ignored

        “未知的命令开头...”----出现这个错误一般都是格式的问题或是注释的问题

        ①将SQL文件的语句中的所有中文注释改为英文注释(这个备选优先下面方法)

        ②SQL文件开头设置参数:set sqlblanklines on,这是因为有空行导致sql语句加载到机器内存中截断了,一般设置这个参数就能解决问题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值