通过外部表改进一个繁琐的大查询

今天处理了一个比较有意思的案例,说是有意思,因为涉及多个部门,但是哪个部门似乎都不愿意接。最后还是用了一些巧力,化干戈为玉帛。
问题的背景是这样的,业务部门需要做一个大查询,他们目前只拿到了部分账号的一个id字段的值,需要匹配得到一个类似手机号的字段值,开发部门提供了对应的sql语句,会关联两张表来匹配得到对的数据,然后反馈到DBA这里的时候就是最终的sql语句了,DBA查询得到数据,然后反馈给业务部门。大体的流程是这样的。
   但是现在的问题是,业务部门需要提供的id有60多万个,开发部门看到这个情况就不太愿意提供这样的语句了,你说一条一条提供吧,可能对于他们来说还需要不少的工作量,而且文件可能几十M,工作量也非常大。对于业务部门来说,他们又不懂技术细节,对于DBA来说,巧妇难为无米之炊。所以这个时候就有些踢皮球了的感觉了。
   我看了下,觉得这活毕竟也不是经常有这种问题,那就接了吧。虽然中途碰到了不少的小问题,不过也着实值得一试。
    开发部门提供的语句类似下面的形式。
select CID from test_user_info  where login_name='?'
select SECURITY_PHONE from test_user_certification_info  where cid='?'
    业务部门就提供了一个excel文件,里面是60多万的id值,想直接转到linux环境里还不行。
    从我的角度来看,大体有这些考虑,也算是问题的一些难点吧。
     (1)这些id值怎么通过excel传输到内网环境,对于内网而言,大文件的传输目前有x M的限制
     (2)因为涉及的id还是有些多,那么这类操作只能备库操作了。
     (3)in 的限制,如果根据提供的id来匹配,那么语句select CID from test_user_info  where login_name='?' 是不可避免要使用in的方式了。但是in的方式会有1000个以内枚举值的限制,对于60万的id值来说,如果这么切分,工作量和难度又会加大。所以in的方式还是不太好。
     (4)等我连接到环境,发现问题比我想的还要难一些,这两个表 test_user_info,test_user_certification_info目前做了拆分,把数据拆成了12份。意味值目前存在12个用户平均存储了这些数据。
对于这个问题的处理,这个时候就不单单是友情支持了,还是需要好好考虑一下,怎么巧妙解决,而不是光靠苦力了。
我们来逐个分析这个问题。
第一个怎么把excel里面的60万id拷贝到内网环境,这个花了我一些时间去琢磨,首先这个excel有近15M,直接拷贝不了,而且还有网络的流量限制。而且就算把excel文件拷贝过去,在linux下也直接解析不了。所以我是通过excel把id列的值拷贝到文本文件中,然后通过云服务器来中转这个文件,避开了流量的限制。间接实现了首要条件。
第二个是目前涉及的id有些多,只能在备库执行,这个倒没有异议,但是结合第三条来看,需要避免使用in list的方式,我们可以采用临时表的方式,或者使用外部表。
所以对此我打算在主库中创建外部表,然后外部表的ddl会同步到备库,然后把实际的文本文件拷贝到备库去,查询操作都在备库执行。这样就和主库没有了关系。备库怎么查询主库都不会收到影响。
所以我在主库做了如下的操作。
首先创建目录。
SQL> create directory ext_dp_dir as '/home/oracle/backup_stage';
Directory created.
然后创建外部表
CREATE TABLE  test_cn
      (cn    varchar2(50)
       )
    ORGANIZATION EXTERNAL
      (TYPE ORACLE_LOADER
      DEFAULT DIRECTORY ext_dp_dir
      ACCESS PARAMETERS
        (
        RECORDS DELIMITED BY NEWLINE      
        )
      LOCATION ('test_cn.txt')
     );
其中test_cn.txt就是最开始所说的文本文件,在主库中执行,在备库中验证。
SQL> @a.sql
Table created.
备库中验证,发现已经能够正常识别了。
SQL> select count(*)from test_cn;
  COUNT(*)
----------
    608816
然后说说第4个问题,对这个表了拆分,怎么查询好一些。
开发提供的语句如下。
select CID from test_user_info  where login_name='?'
select SECURITY_PHONE from test_user_certification_info  where cid='?'
我们在这个基础上改进,把表的关联糅合起来,输出完整的字段匹配来,到时候提供一个完整的列表,不需要再删除也不怕。
语句如下:
select t2.SECURITY_PHONE,t2.CID from
(
select login_name,cid from acc1.test_USER_INFO
 ) t1,
(
select security_phone,cid  from acc1.test_USER_CERTIFICATION_INFO
)
 t2,TESTDBA.xianjian_cn t3
 where t1.login_name=t3.cn
       and t1.cid=t2.cid;  
但这个语句的缺点是只是其中的一个用户,目前有12个拆分用户,那么我们就包装一下,写个很简单的脚本来。
脚本1 check_data.sh
sqlplus -s / as sysdba <<EOF
spool b.log append
select t2.SECURITY_PHONE,t2.CID from
(
select login_name,cid from $1.CYUC_USER_INFO
 ) t1,
(
select security_phone,cid  from $1.CYUC_USER_CERTIFICATION_INFO
)
 t2,CYDBA.xianjian_cn t3
 where t1.login_name=t3.cn
       and t1.cid=t2.cid;
spool off
EOF

第二个脚本 check_all.sh的内容
sh check_data.sh ACC00
sh check_data.sh ACC02
sh check_data.sh ACC04
sh check_data.sh ACC11
sh check_data.sh ACC13
sh check_data.sh ACC15
sh check_data.sh ACC20
sh check_data.sh ACC22
sh check_data.sh ACC24
sh check_data.sh ACC31
sh check_data.sh ACC33
sh check_data.sh ACC35
逐个击破,对比一个大sql的效率要高了很多。
不到一分钟就查完了。当然开始还是碰到了一个小问题,那就是乱码问题,因为我们的文件是从windows传过来的。开始匹配的时候发现没有任何数据。
SQL> select '>'||cn||'<' from testdba.test_cn where rownum<20;
'>'||CN||'<'
--------------------------------------------------------------------------------
<FA7E3EF3A73E61F4F61561464C79FA7D
<586383418
<609848108
进一步分析,发现是格式的问题。
cat -v xianjian_cn.txt |less
FA7E3EF3A73E61F4F61561464C79FA7D^M
586383418^M
609848108^M
使用dos2unix格式化即可。
$dos2unix xianjian_cn.txt
dos2unix: converting file test_cn.txt to UNIX format ...
再次匹配就可以顺利得到结果了。
这种处理也可以作为一种处理大批量数据查询的一种思路,其实就是比较轻便,如果是一个常规需求,经常会有这类的查询,我们只需要替换这个文本文件即可,其它的部分可以设置成视图之类的,这些功能点就固化起来了。

时间: 2024-09-20 23:22:09

通过外部表改进一个繁琐的大查询的相关文章

《Hadoop实战手册》一1.10 在Greenplum外部表中使用HDFS

1.10 在Greenplum外部表中使用HDFS Greenplum是一个并行数据库,数据的存储与查询基于一个或多个PostgreSQL实例.它补充了Hadoop,提供对大数据的实时或准实时访问,它还支持使用HDFS文件作为外部表.外部表是一个处理Greenplum集群之外数据很好的解决方案.由于外部表访问首先要消耗网络带宽,所以与Greenplum集群内的数据相比,它应该存储那些访问相对不频繁的数据.本节将介绍如何创建只读的外部表和可读写的外部表. 准备工作 在本节假定你使用的Hadoop版

海量数据迁移之外部表并行抽取

在10g开始的新特性中,外部表是一个不容忽视的好工具.对于大型项目中海量数据使用sqlloader是一种全新的方式,不过很明显,sqlloader的可扩展性更强,但是基于oracle平台的数据迁移来说,外部表的性能也不错.对于数据迁移来说也是一个很好的方案. 使用外部表来做数据迁移,可以"动态"加载数据,能够很方便的从数据库中加载数据,对于数据校验来说就显得很有优势了,而对于sqlloader来说,可能得等到数据加载的时候才知道是不是有问题,如果对于数据的准确性要求极高,可以使用外部表

PostgreSQL · 实现分析 · PostgreSQL 10.0 并行查询和外部表的结合

title: PostgreSQL · 实现分析 · PostgreSQL 10.0 并行查询和外部表的结合 author: 义从 前言 大家都知道,PostgreSQL 近几大版本中加入了很多 OLAP 相关特性.9.6 的并行扫描应该算最大的相关特性.在今年发布的 10.0 中,并行扫描也在不断加强,新增了并行的索引扫描. 我们知道并行扫描是支持外部数据源的.在云上,有很多存储存储产品可以以外部数据源的形式做数据库的外部存储.例如,阿里云的 OSS 和 AWS 的 S3 都是绝佳的外部数据源

阿里云RDS PostgreSQL OSS 外部表 - 并行写提速案例

标签 PostgreSQL , oss对象存储 , 阿里云RDS PG , 并行写 , dblink , 异步调用 , 异步任务监控 , OSS外部表 , 数据传输 背景 阿里云RDS PostgreSQL.HybridDB for PostgreSQL提供了一个非常强大的功能,OSS对象存储外部表. 阿里云的RDS PostgreSQL用户可以利用OSS存储冷数据(OSS外部表的形态呈现),实现冷热分离:也可以利用OSS作为数据的中转桥梁,打通其他云端业务,例如HDB FOR PostgreS

ORACLE外部表总结

外部表介绍   ORACLE外部表用来存取数据库以外的文本文 件(Text File)或ORACLE专属格式文件.因此,建立外部表时不会产生段.区.数据块等存储结构,只有与表相关的定义放在数据字典中.外部表,顾名思义,存 储在数据库外面的表.当存取时才能从ORACLE专属格式文件中取得数据,外部表仅供查询,不能对外部表的内容进行修改(INSERT.UPDATE. DELETE操作).不能对外部表建立索引.因为创建索引就意味着要存在对应的索引记录.而外部表其实在没有存储在数据库中.故在外部是无法建

Oracle 外部表

--================= -- Oracle 外部表 --=================       外部表只能在Oracle 9i 之后来使用.简单地说,外部表,是指不存在于数据库中的表.通过向Oracle提供描述外部表的元数据,我们 可以把一个操作系统文件当成一个只读的数据库表,就像这些数据存储在一个普通数据库表中一样来进行访问.外部表是对数据库表的延伸.   一.外部表的特性     位于文件系统之中,按一定格式分割,如文本文件或者其他类型的表可以作为外部表.     对

使用外部表管理Oracle 告警日志(ALAERT_$SID.LOG)

--================================================ -- 使用外部表管理Oracle 告警日志(ALAERT_$SID.LOG) --================================================       Oracle 告警日志时DBA维护数据库经常需要关注的一部分内容.然而告警日志以文本文件,按时间的先后顺序不断累积的形式来存储,久而 久之,势必造成告警日志的过大,难于维护和查找相关的信息.使用外表表方式来

使用外部表关联MySQL数据到Oracle

因为业务需要,有个临时的活动需要DBA来支持一些数据业务,问题来了,需要从MySQL端同步一部分数据到Oracle端,然后从Oracle端匹配查到相应的数据返回给MySQL,至于原因,也是不同的业务系统,不同的权限分配,还没法做到一个应用端去读取这些信息,而且也有安全的考虑,大体就是两部分的数据也是互相补充,但又彼此独立,是一个全集和子集的关系. 这个流程本来从开发的角度来看似乎是一头雾水,所以交给他们来规划就容易出现问题,最后沟通后的流程是下面的形式. 下面这个图左边是Oracle的环境,右边

巧用外部表备份历史数据

在很多的系统中,随着时间的推移,都会沉淀大量的历史数据.一般数据量达到一定程度都会考虑使用分区表来处理.根据业务规则,可能有些历史数据隔一段时间就需要做清理了,这个时候历史数据就需要在分区级进行清理.在不同的系统,不同厂商都有不同的实现方案.但是从数据安全角度来说,都需要做备份工作,也是预防万一. 比如说我们存在一个表charge,就可能会有下面的几种分区规则, 一种是按照日期来分区,这样就能够很清楚的定位到哪些天的数据可以清理. 比如 6月9日的充值记录,分区表就为P_20150609,相关的