oracle connect by很强,但是要慎用,不然有你哭的时候

news2024/10/5 16:49:25

前言:

        第四次工业革命,带来了科技的巨大变更,同时带来了很多半结构化数据,很多数据会做成集合、JSON的形式存储到数据库中,通过ETL工具我们将这些数据抽取到数仓里面,我们怎么进行分析呢?这些数据类似这样的保留在数据库里面。比如下面所示,同一个检测项目由多个人负责检测,因此会通过"\" "/"等等分隔符一次性将数据录入字段里头,方便用户进行数据维护,当然这些数据对分析人员提出较高的要求。为了将这些数据拆分为多行,我们就会使用到connect by来拆分,将数据拆分为多行。

         针对这些数据,我在前面写了一篇文章介绍来处理这些数据,也是因为性能的问题,然后使用存储过程,一条条执行,将一行数据拆分好以后,存储至数据库,直到拆分完毕为止。具体我们可以参考我以前写的文章。

oracle一次性说清楚,多种分隔符的一个字段拆分多行,再多行多列多种分隔符拆多行,最终处理超亿亿。。亿级别数据量_oracle分隔符_他们叫我技术总监的博客-CSDN博客

一、connect by常见用法

        1、万年历

        代码

SELECT '年' lx, TO_CHAR(ADD_MONTHS(SYSDATE, (4 - ROWNUM)*12), 'YYYY') YEAR_LIST 
FROM DUAL CONNECT BY ROWNUM <= 5 --获取近5年的年份

        效果

         2、生成序列

        代码

select rownum from dual connect by rownum<=10;--生成1-10的序列

        效果

        3、一行变多行

        代码

select REGEXP_SUBSTR('01#02#03#04', '[^#]+', 1, rownum) as newport
from dual connect by rownum <= REGEXP_COUNT('01#02#03#04', '[^#]+');--一行数据拆分为多行

         效果

 总结:

        总的来说,connect by在处理少量的树状数据还是很强大的,这也是很多人喜欢应用它的原因。但是oracle 是不清楚connect by后会出现多少行的数据结构,因此oracle 容易错误的cardinality估算,从而走了NESTED LOOPS,因无法估算结果数据行,因此当原始数据量在500-800行时性能就会变的很差。

二、实战案例剖析

        1、union all +connect by

        在我现在的一个项目上就遇到了一个经典的案例,就是因使用了connect by导致,一个数据同步了快3天都没成功,具体为啥会同步3天呢?因刚好是周五下班后用户反馈,然后因下班到家了,不能远程处理,在周日停掉执行后,优化了部分逻辑,再执行,到周一早上发现还是没达到想要的效果。因对应SQ较复杂,就没详细去分析原因。具体SQ如下所示:

select 
   	   
       a.state xtstate,
       a.current_nodes_info dbr,
       c.*,
       b.FILENAME,
       b.FILE_URL,
 case when c.field0035  is null then  round(to_date(to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss'),
                         'yyyy-mm-dd hh24:mi:ss')-  to_date(to_char(c.START_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                     'yyyy-mm-dd hh24:mi:ss'),2)  --没有审批意见的
 when  FIELD0090  is not null then  round(to_date(to_char(FIELD0090, 'yyyy-mm-dd hh24:mi:ss'),
                         'yyyy-mm-dd hh24:mi:ss')-  to_date(to_char(c.START_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                     'yyyy-mm-dd hh24:mi:ss'),2) end     


 clsc,
       to_char(FIELD0090, 'yyyy-mm-dd hh24:mi:ss') FINISH_DATE,
       to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss') etlts,
       case
          when a.FINISH_DATE is not null then
          '关闭'
         when FIELD0090 is  not null  then
          '评审完成'
       
       
         when   case when c.field0035  is null then  round(to_date(to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss'),
                         'yyyy-mm-dd hh24:mi:ss')-  to_date(to_char(c.START_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                     'yyyy-mm-dd hh24:mi:ss'),2)  --没有审批意见的
 when  FIELD0090  is not null then  round(to_date(to_char(FIELD0090, 'yyyy-mm-dd hh24:mi:ss'),
                         'yyyy-mm-dd hh24:mi:ss')-  to_date(to_char(c.START_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                     'yyyy-mm-dd hh24:mi:ss'),2) end   >= 5 then
          '超期'
         when   case when c.field0035  is null then  round(to_date(to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss'),
                         'yyyy-mm-dd hh24:mi:ss')-  to_date(to_char(c.START_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                     'yyyy-mm-dd hh24:mi:ss'),2)  --没有审批意见的
 when  FIELD0090  is not null then  round(to_date(to_char(FIELD0090, 'yyyy-mm-dd hh24:mi:ss'),
                         'yyyy-mm-dd hh24:mi:ss')-  to_date(to_char(c.START_DATE, 'yyyy-mm-dd hh24:mi:ss'),
                     'yyyy-mm-dd hh24:mi:ss'),2) end   < 5 then
          '进行中'
         
        
       end psjd,
       mx.*
  from V3XUSER.COL_SUMMARY A
  left join V3XUSER.CTP_ATTACHMENT b
    on a.id = b.SUB_REFERENCE
 right join  (select * from  V3XUSER.formmain_2182 c where to_char(c.start_date,'yyyy-mm-dd')>to_char(sysdate-60,'yyyy-mm-dd') )  c--只更新近2个半月的数据
    on c.id = a.FORM_RECORDID

  left join (select lscs.*,
                    lswc.field0068 wcsj,
                    lswc.field0069 wcqkms,
                    fj.filename    filename2,
                    fj.file_url    file_url2,
                    FIELD0071      结案确认
               from (select '临时措施' lx,
                            lscs.FIELD0055 csxq,
                            listagg(ry.name, '、') within group(order by ry.name) zrr,
                            lscs.FIELD0057 jhwcsj,
                            lscs.fid,
                            lscs.iid
                       from (SELECT distinct  id iid,
                                             formmain_id fid,
                                             REGEXP_SUBSTR(FIELD0056,
                                                           '[^,]+',
                                                           1,
                                                           LEVEL) cf,
                                             a.*
                               FROM V3XUSER.formson_3565 a
                             CONNECT BY REGEXP_SUBSTR(FIELD0056,
                                                      '[^,]+',
                                                      1,
                                                      LEVEL) is not null) lscs
                       left join V3XUSER.ORG_MEMBER ry
                         on lscs.cf = ry.id
                      group by '临时措施',
                               lscs.FIELD0055,
                               lscs.FIELD0057,
                               lscs.fid,
                               lscs.iid) lscs
               left join V3XUSER.formson_3568 lswc
                 on lscs.fid = lswc.formmain_id
                and lscs.csxq = lswc.field0067
               left join V3XUSER.CTP_ATTACHMENT fj
                 on lswc.field0070 = fj.SUB_REFERENCE
             union all
             select lscs.*,
                    lswc.field0073 wcsj,
                    lswc.field0074 wcqkms,
                    fj.filename,
                    fj.file_url    file_url,
                    field0076      结案确认
               from (select '长久措施' lx,
                            lscs.FIELD0058 csxq,
                            listagg(ry.name, '、') within group(order by ry.name) zrr,
                            lscs.field0060 jhwcsj,
                            lscs.fid,
                            lscs.iid
                       from (SELECT  id iid,
                                             formmain_id fid,
                                             REGEXP_SUBSTR(field0059,
                                                           '[^,]+',
                                                           1,
                                                           LEVEL) cf,
                                             a.*
                               FROM V3XUSER.formson_3566 a
		
                             CONNECT BY REGEXP_SUBSTR(field0059,
                                                      '[^,]+',
                                                      1,
                                                      LEVEL) is not null) lscs
                       left join V3XUSER.ORG_MEMBER ry
                         on lscs.cf = ry.id
                      group by '长久措施',
                               lscs.FIELD0058,
                               lscs.field0060,
                               lscs.fid,
                               lscs.iid) lscs
               left join V3XUSER.formson_3569 lswc
                 on lscs.fid = lswc.formmain_id
                and lscs.csxq = lswc.field0072
               left join V3XUSER.CTP_ATTACHMENT fj
                 on lswc.field0075 = fj.SUB_REFERENCE
             union all
             select lscs.*,
                    lswc.field0078 wcsj,
                    lswc.field0079 wcqkms,
                    fj.filename,
                    fj.file_url    file_url,
                    field0081      结案确认
               from (select '防呆设计' lx,
                            lscs.FIELD0061 csxq,
                            listagg(ry.name, '、') within group(order by ry.name) zrr,
                            lscs.field0063 jhwcsj,
                            lscs.fid,
                            lscs.iid
                       from (SELECT  id iid,
                                             formmain_id fid,
                                             REGEXP_SUBSTR(field0062,
                                                           '[^,]+',
                                                           1,
                                                           LEVEL) cf,
                                             a.*
                               FROM V3XUSER.formson_3567 a
                             CONNECT BY REGEXP_SUBSTR(field0062,
                                                      '[^,]+',
                                                      1,
                                                      LEVEL) is not null) lscs
                       left join V3XUSER.ORG_MEMBER ry
                         on lscs.cf = ry.id
                      group by '防呆设计',
                               lscs.FIELD0061,
                               lscs.field0063,
                               lscs.fid,
                               lscs.iid) lscs
               left join V3XUSER.formson_3570 lswc
                 on lscs.fid = lswc.formmain_id
                and lscs.csxq = lswc.field0077
               left join V3XUSER.CTP_ATTACHMENT fj
                 on lswc.field0080 = fj.SUB_REFERENCE
             
             ) mx
    on c.id = mx.fid

        因为项目初期原始表数据量很小,执行connect by的时候基本还看不到什么性能问题。但是当运行3个月左右数据时,原始数据在600多行左右时,就出现性能问题了,真的是慢的不行。具体我们可以来看下执行日志。

         如上图所示,一共410条数据,执行了快11分钟,而且还是卡住不动的。Oh my god!这是什么鬼。通过拆分每段的执行过程发现,性能卡在了最后的"mx"表查询,即union all +connect by那段。

        2、connect by 具体卡在哪里了

       

         如上图所示,用户会做3个措施,每个措施会有多个责任人,因此会union all 2遍,将3个措施拼接起来,因为责任人会在一行,因此使用了connect by 来进行拆分为多行。看起来逻辑是没啥问题,但是性能时真不行呀。

        单独查询临时措施,拆分后817行数据,耗时了快5分钟,可能还能接受,但是加上union all 后那就是雪上加霜了。

        哈哈哈,不久DBA就过来找我了,说带有connect by进程执行了差不多1000分钟,哈哈哈是有点离谱的。 

              

 三、解决方案

        1、游标执行/分而治之

        如上面所说的connect by 在数据量很小的时候,运行效率还是很高的,因此我们可以采用存储过程,或者将union all 拆分开来执行,然后将数据汇总到一个底表里头。具体如下图所示

        定义变量,用游标一行行拆分执行 

              通过存储过程游标来拆分执行

              2、换个思路

        其实我们仔细分析下需求,我们发现,使用connect by 是为了将责任人拆分为多行来存储,但是在展示的时候又需要使用listegg将责任人组合在一起来展示。那有没有一种办法直接在展示的时候处理呢?

         如上图所示,对应责任人主键使用逗号分离的,是不是和in('A','B','C','D')似曾相识。因此我们在展示的时候,使用类似select name  from BI.Oa_Member where id in ('" + AI2 + "')来获取责任人的名称就ok了,bingo~。希望你下次遇到connect by 相关问题的时候,会对你有所启发~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/720746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

centos7安装git及maven

安装git 直接使用yum安装&#xff0c;指令如下&#xff1a; yum install git然后执行如下指令判断是否安装完成&#xff1a; git --version紧接着需要维护git的用户名及邮箱等信息 git config --global user.name "zzy" git config --global user.email "ex…

JS知识点汇总(十四)--事件循环

1. 对事件循环的理解 JavaScript 在设计之初便是单线程&#xff0c;即指程序运行时&#xff0c;只有一个线程存在&#xff0c;同一时间只能做一件事 JavaScript 初期作为一门浏览器脚本语言&#xff0c;通常用于操作 DOM &#xff0c;如果是多线程&#xff0c;一个线程进行了删…

QT学习笔记:调整控件大小和位置

前面的文章&#xff0c;我讲了怎么用layout去布局。但布局做完后&#xff0c;发现界面有点怪。比如&#xff0c;最低下的“清除”按钮这么大&#xff0c;“消息体”这个label没有位于中间等。下面&#xff0c;我就来讲下怎么把界面继续优化。 1、调整“清除”按钮大小和位置 …

第八步:STM32F4 EXTI

1.0 外部中断概述 STM32F4的每个IO都可以作为外部中断输入。 STM32F4的中断控制器支持22个外部中断/事件请求&#xff1a; EXTI线0~15&#xff1a;对应外部IO口的输入中断。 EXTI线16&#xff1a;连接到PVD输出。 EXTI线17&#xff1a;连接到RTC闹钟事件。 EXTI线18&#xff1…

Kubernetes(k8s)实战:Kubernetes(k8s)部署Springboot项目

文章目录 一、练手&#xff1a;k8s部署部署wordpressmysql1、创建wordpress命名空间2、创建mysql数据库3、创建wordpress应用4、小结 二、实战&#xff1a;部署自己的springboot项目1、准备一个springboot项目2、使用docker打成镜像3、使用k8s部署springboot 三、实战&#xff…

pycharm配置虚拟环境

pychram配置虚拟环境&#xff0c;然后使终端在该目录下 win键r 输入cmd, 进入dos命令。使用conda create -n cleanRobot python3.7 创建cleanRobot虚拟环境。 输入&#xff1a; conda activate cleanRobot 进行虚拟环境激活。 我们在安装的anaconda的目录下可以看到刚刚建…

Java批量操作Excel文件实践

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 | 问题背景 在操作Excel的场景中&#xff0c;通常会有一些针对Excel的批量操作&…

基于matlab使用Grad-CAM探索语义分割网络(附源码)

一、前言 此示例演示如何使用 Grad-CAM 探索预训练语义分割网络的预测。 语义分割网络对图像中的每个像素进行分类&#xff0c;从而生成按类分割的图像。您可以使用深度学习可视化技术 Grad-CAM 来查看图像的哪些区域对像素分类决策很重要。 二、下载预训练网络 从剑桥大学…

基于Java工贸学生信息管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

vscode多主题色功能实现机制

vscode的页面分为两部分&#xff0c;一部分是插件提供&#xff0c;一部分是主体。那么vscode在多主题实现上就要考虑把这两部分结合起来管理&#xff0c;相对来说要比单纯的网页实现多主题功能要复杂一些。 主体部分实现 我们先看下vscode主体部分样式是如何画出来了 registe…

Spring系列2 -- Spring的创建和使用

Spring 就是⼀个包含了众多工具方法的 IOC容器。既然是容器那么它就具备两个最基本的功能&#xff1a; 将对象存储到容器&#xff08;Spring&#xff09;中&#xff1b;从容器中将对象取出来。 在Java中对象也叫做Bean&#xff0c;后续我们就把对象称之为Bean&#xff1b; 目录…

数据结构--二叉树的定义和基本术语

数据结构–二叉树的定义和基本术语 二叉树的基本概念 二叉树是 n ( n ≥ 0 &#xff09; n (n\ge0&#xff09; n(n≥0&#xff09;个结点的有限集合: ①或者为 空二叉树 \color{red}空二叉树 空二叉树&#xff0c;即n 0。 ②或者由一个 根结点 \color{red}根结点 根结点和两…

ModaHub魔搭社区:腾讯发布的向量数据库Tencent Cloud VectorDB有哪些核心能力?

腾讯发布的向量数据库有哪些核心能力&#xff1f; 腾讯云刚刚发布的向量数据库Tencent Cloud VectorDB主要具备以下能力&#xff1a; 高性能向量存储、检索&#xff1a;腾讯云向量数据库具备高性能的向量存储和检索能力&#xff0c;单索引能够轻松支持10亿级别的向量规模。在…

十二、flex练习

需求&#xff1a;做出下面的样式 代码实现&#xff1a; <body><ul class"nav"><li><a href"#">HTML/CSS</a></li><li><a href"#">Browser Side</a></li><li><a href&q…

【Hello mysql】 数据库库操作

Mysql专栏&#xff1a;Mysql 本篇博客简介&#xff1a;介绍数据库的库操作 库的操作 创建数据库创建数据库案例字符集和校验规则查看系统默认字符集和校验规则查看数据库支持的字符集和校验规则 校验规则对于数据库的影响操纵数据库查看数据库显示创建语句修改数据库数据库删除…

【7月新刊】避雷!这4本期刊竟无影响因子?!7月期刊目录已更新 (多本期刊影响因子上涨)~

6月28日&#xff0c;科睿唯安发布了最新JCR报告&#xff0c;一时间几家欢喜几家愁&#xff0c;但有的作者却发现&#xff0c;自己投稿的期刊虽然被核心库收录却没有影响因子&#xff0c;不免慌了神。 总的来说&#xff0c;被核心库收录的期刊没有公布影响因子&#xff0c;一般…

实战干货,自动化测试框架mark标记详细实战,进阶高级测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 pytest可以支持对…

键盘输入一个字符 a’,串口工具显示“b 实现现象:键盘输入一个字符串,串口工具回显输入的字符串

1.键盘输入一个字符 a’,串口工具显示"b 2.实现现象:键盘输入一个字符串&#xff0c;串口工具回显输入的字符串 uart4.h #ifndef __UART4__H__ #define __UART4__H__ #include "stm32mp1xx_uart.h" #include "stm32mp1xx_gpio.h" #include "st…

SQLite Expert Professional将ACCESS数据库文件导入到SQLITE

一、下载与安装 下载对应的位数的SQLite Expert&#xff1a;http://www.sqliteexpert.com/download.html &#xff0c;建议下载professional版本的&#xff0c;功能更加强大。 如果官网进不去可以到百度云下载&#xff1a;https://pan.baidu.com/s/17igndAqQ7SQ57LcjwS4WIQ …

RK3588 PWM调试记录---linux pwm子系统驱动框架

一、RK3588 PWM简介 RK3588一共有4组PWM,每组有4个通道&#xff0c;共可以产生4*416路PWM波形&#xff1b; PWM0 开始地址&#xff1a;0xfd8b0000 PWM1 开始地址&#xff1a;0xfebd0000 PWM2 开始地址&#xff1a;0xfebe0000 PWM3 开始地址&#xff1a;0xfebf0000 即每组PWM的…