首页 文章 精选 留言 我的

精选列表

搜索[日活数],共10000篇文章
优秀的个人博客,低调大师

联通数科 DataOps 一体化能力平台:DolphinScheduler 大规模应用实践

各位小伙伴,我是联通数字科技有限公司数据智能事业部的王兴杰。 今天,我将和大家聊一聊联通数字科技有限公司是如何基于Apache DolphinScheduler构建DataOps一体化能力平台的。 今天的分享主要分为三个部分: 关于DataOps的一些思考; 企业在实施任务调度系统时的一些困境和困难; 我们基于Apache DolphinScheduler所做的一些改造。 DataOps与任务调度 在谈及任务调度系统时,我们往往会提到DataOps。那什么是DataOps?为什么它与任务调度系统密切相关?企业的数据加工链路中涉及的工具往往不仅仅只有任务调度系统,还包括数据集成、数据治理、数据应用等其他平台工具。 这种情况下,如何解决数据加工链路上的断层,以及如何降低用户的使用成本等等问题需要有一个指导思想,这就是DataOps。 DataOps是基于DevOps提出的,参照了软件研发、发布的流程,对数据的研发、治理、运营体系进行指导,旨在优化数据处理流程,提高数据处理的效率和质量。 DataOps面临的问题 在企业实施DataOps的过程中,通常会遇到以下几个主要问题: 复杂的数据接入需求 企业的数据源种类繁多,包含结构化和非结构化数据,并且存在批数据和流数据同时接入的情况。以往单一的开源数据集成工具难以满足企业复杂的数据接入场景和多样的数据源类型。 同时,由于数据源类型和网络等数据加工场景的复杂性,企业很难获取全链路的数据血缘关系。 数据治理介入时机不够完善 企业很难持续高质量的产出满足客户要求的数据。一旦数据出现问题,排查整个数据加工链路的成本很高,如果对数据加工链不熟悉,查找问题节点和修改问题的成本会更大。 长链路的数据加工尤其容易导致问题排查困难,修改问题时还要考虑下游节点的依赖关系,避免盲目修改引发生产事故。当然这种情况的生产事故问题可能不仅由于数据治理,也可能因为需求变更或bug修复导致。 人才需求问题 企业在实施DataOps过程中,通常会遇到技术人员不懂业务,业务人员不懂技术的情况。这主要是企业组织架构问题,尤其在大型企业或数据加工复杂的企业更为明显。 平台维护、数据研发、生产运营的人员通常由不同部门负责,彼此对对方的工作了解不多,数据管理意识薄弱,缺乏统一的数据标准和规范,导致口径不一致,问题处理困难。。 工具集成问题 企业使用的工具通常独立运行,用户操作需要在不同系统间跳转,甚至使用不同账号和配置进行处理。 这种情况不仅增加了操作复杂性,还可能导致数据孤岛和处理效率低下。 数据 VS 软件研发 在讨论DataOps时,理解数据研发与软件研发的差异非常重要。虽然DataOps借鉴了DevOps的概念,但数据研发和软件研发之间仍存在显著差异。 需求与设计阶段 在需求阶段和设计阶段,数据研发和软件研发的差异并不明显。 软件研发关注的是软件的架构设计和需求的流转,而数据研发则更关注数据的来源、分布以及数据研发的架构等问题。 研发阶段 在研发阶段,数据研发和软件研发的方法和流程相似。两者都需要经过需求分析、设计、编码和测试等步骤。 但数据研发更注重数据的处理和转换 ,而软件研发则更注重功能实现和代码质量。 测试阶段 在测试阶段,数据研发和软件研发的差异较为明显。 软件测试:在需求评审阶段,测试人员已经明确了解点击某个按钮或发起某种请求后应该得到的结果。测试周期通常较短,测试人员和研发人员可以快速沟通并修复bug。 数据测试:数据测试过程更为复杂。在需求提出时,可能对数据结果不够明确,结果的判断需要依赖研发人员或业务人员的经验,或通过其他数据搭配可视化分析工具来辅助结果确认。数据测试周期较长,一些大型复杂的数据加工任务可能会经过一个月甚至更长的时间才能得到测试结果。 运维阶段 软件系统的运维阶段,侧重于保障软件系统的稳定运行,处理故障、优化性能、进行系统升级等,以确保业务的连续性。而对于数据来说,除了运维以外,更应该关注的是数据运营,要持续关注数据安全、数据质量等问题。 DataOps从研发管理到运营管理的所有阶段,都可以在任务调度系统中完成。任务调度系统在整个数据加工链路中扮演核心角色,是解决DataOps困境的关键入口。所以我们结合DataOps与任务调度系统可以更好的解决企业在实施任务调度系统和DataOps平台的困境。 数据研发与软件研发虽然在某些阶段和流程上有相似之处,但在测试和运维阶段的差异尤为明显。 理解这些差异对于有效实施DataOps至关重要。通过采用适当的工具和方法,企业可以更好地应对数据研发中的挑战,提升用户体验,提高数据处理的效率和质量。 而Apache DolphinScheduler作为任务调度系统,可以在DataOps的各个阶段提供支持,帮助企业实现一体化的数据处理和管理。 企业实施任务调度系统的挑战 任务调度系统是DataOps平台工具中的重要组成部分,对于企业的数据加工任务来说也是核心平台工具,企业在实施任务调度系统时往往也会有多方面的要求。 挑战一:稳定性要求 企业对任务调度系统的首要要求是稳定性,要充分确保数据加工任务和业务的连续性,同时系统也需要具备一定的风险抵抗和预警能力,以应对突发状况。 Apache DolphinScheduler采用核心的分布式去中心化架构,并结合服务融合机制,能够充分保证系统的稳定性。即使在极端情况下,部分节点丢失也不会立即导致系统崩溃。通过Master和Worker机制及其队列处理机制,系统可以有效避免服务器崩溃的情况。 挑战二:处理复杂多样的数据加工任务 不同企业的数据加工任务场景会有所差异,最好是能够万全兼容原有数据加工任务和场景。对于一些不常见的情况,也要求二次开发成本尽可能低。 Apache DolphinScheduler目前支持38种数据加工类型节点,能够覆盖大多数企业的数据加工需求。 如果遇到极端或不常见的情况,Apache DolphinScheduler的代码结构规范简单,二次开发成本低,可以轻松增加新的数据类型节点。 挑战三:使用简单 企业在选型任务调度系统时,功能的多样性和操作的简便性同样重要。Apache DolphinScheduler提供了可视化的拖拉拽DAG编辑页面,对用户非常友好,降低了学习成本。 对于技术人员和业务人员来说,传统的脚本式开发工具学习成本高,而DAG编辑页面则更易于接受和使用。 挑战四:系统的可扩展性 任务调度系统需要具备灵活的扩展和缩容能力,以适应企业业务的发展和变更。在扩展过程中,不能对现有任务产生任何影响。 Apache DolphinScheduler通过其分布式架构,可以在不影响现有任务的情况下进行系统扩展和缩容,确保系统的高效运行。 Apache DolphinScheduler的解决方案 稳定性: 通过分布式去中心化架构和服务容错机制,确保系统在极端情况下的稳定运行。 多样性处理: 支持38种数据加工类型节点,满足复杂多样的数据接入需求。 易用性: 提供可视化的DAG编辑页面,降低用户的学习和使用成本。 可扩展性: 灵活的扩展和缩容能力,在不影响现有任务的情况下进行系统调整。 系统集成: 统一调度插件简化系统集成,提高整体工作效率(开源之夏正在研发中)。 企业在实施任务调度系统时,面临着稳定性、数据处理多样性、使用简单性、系统可扩展性和工具集成等方面的挑战。 而Apache DolphinScheduler通过其先进的架构设计和丰富的功能,提供了全面的解决方案,帮助企业高效地实现数据加工和任务调度,确保系统的稳定运行和业务的连续性。 调度应用规模 在联通数字科技有限公司,我们基于Apache DolphinScheduler构建了一个大规模的任务调度系统。 以下是我们的当前规模: 单日任务处理量:超过十万。 Worker集群规模:125台机器。 K8s集群:搭配了两套K8s集群用于承接Worker运行的任务。 为了应对庞大的数据量和集群规模,我们进行了以下二次开发和改造。 数据类型节点 我们主要使用以下两种数据类型节点: Shell节点: 主要用于传统服务器运行的任务数据加工类型。结合数据开发平台(后续会详细介绍)和文件管理系统,实现不同数据加工类型任务的运行和封装。 K8s节点: 支持应用镜像的构建、存储,以及K8s集群中的监控和日志查看。由于K8s节点的日志和文件会在pod销毁时丢失,所以我们适配了一套网盘系统,以便下游节点依赖上游节点的数据加工结果(如文件或日志)。 辅助节点类型与功能 为了增强任务调度系统的功能,我们实现了以下辅助节点类型和功能,并将大部分功能贡献给了社区: 流程参数与条件判断节点:用于动态控制任务流程。 批量子流程节点:用于批量任务处理。 业务系统节点:通过统一调度插件实现对业务系统的集成。 调度策略改造 我们还对调度策略进行了改造,主要包括: 任务组控制:用于控制任务的并发度,已贡献到社区。 参数触发:解决下游工作流依赖多个上游工作流的问题,通过参数触发满足功能要求。 数据开发平台 为了配合上述改造,我们还开发了一个数据开发平台。 该平台包括以下功能: 模板与代码管理: 通过模板和代码管理系统(git、hdfs),实现对不同数据加工类型任务的统一管理。 镜像管理: 支持应用镜像的构建、存储。 监控与日志管理: 实现对任务运行状态的监控和日志的集中管理。 通过以上的实践和改造,我们在Apache DolphinScheduler的基础上,构建了一个高效、稳定、功能强大的任务调度系统,能够满足大规模数据处理和复杂数据加工的需求。我们也积极将部分功能贡献给社区,促进开源生态的发展。 服务管理与在线版本升级 在我们基于Apache DolphinScheduler的实践中,服务管理是一个针对开发人员的重要功能模块。 服务管理主要包括以下几个方面: 版本管理和在线升级 支持在线版本升级功能,通过页面实现发布包的分发和版本管理。 服务的重启可以通过页面完成,确保系统在进行版本更新时的平滑过渡。 服务的上下线管理 服务上线:服务正常运行,开始接收新任务。 服务下线:服务停止接收新任务,但现有任务继续运行,直到完成。这个功能主要应用于Worker节点。 通过Worker分组和服务下线管理,可以实现服务的滚动升级,确保升级过程中的任务不会受到影响。 多环境管理 我们的开发平台支持数据的开发和测试环境管理。 可以以DAG为单位进行发布,即整个工作流的定义经过测试后可以发布到生产环境。 确保开发、测试和生产环境的隔离,提高数据加工任务的可靠性和稳定性。 实践应用 在实际应用中,我们通过这些服务管理功能,确保任务调度系统的高可用性和灵活性。 例如: 在线版本升级: 通过在线版本升级功能,开发人员可以在不影响现有任务运行的情况下,对系统进行升级和维护。通过页面实现发布包的分发和服务的重启,极大地提高了运维效率。 服务下线管理: 在一些特殊情况下,需要对某个Worker节点进行维护或升级,通过服务下线功能,可以在不影响现有任务运行的情况下,停止该节点接收新任务,确保系统的平稳过渡。 动态升级和滚动升级: 通过Worker分组和动态升级、滚动升级功能,可以实现系统的平滑升级,避免因升级导致的任务中断或失败。 通过上述功能的实现,我们在确保系统高可用性 的同时,也提高了系统的灵活性和可维护性。 这些功能在实际应用中发挥了重要作用,帮助我们更好地管理和维护任务调度系统。希望这些实践经验对大家有所帮助,也欢迎大家一起交流探讨,共同提升任务调度系统的管理水平。 统计分析与告警 在维护和管理数据处理流程中,我们通过一些统一的分析指标进行统计分析和告警管理。 这些指标提供了对系统运行状况的可视化展现,帮助用户更好地理解和优化任务调度。 分布图和关系图 工作流实例运行分布图 我们为每个项目划分工作流实例的运行时间分布。通过颜色区分不同时间段的运行情况,用户可以直观地看到在某个时段内运行的工作流数量和运行时间分布。 例如,对于T+1的批处理任务,用户可以通过分布图决定最佳的运行时间,以确保服务器的负载均衡。 作业执行关系图 显示作业与执行器之间的关系,Master与工作流、Worker与任务之间的关系。 用户可以通过这些关系图分析在不同时间点的任务运行数量,帮助优化任务调度配置。 这些图表有助于用户在决策过程中找到最佳的任务运行时段,从而实现负载均衡和资源的高效利用。 数据开发平台 我们的数据开发平台内置了一套独立的任务调度系统,支持开发和测试任务的全流程管理。 该平台提供了以下功能: 在线代码编写与测试 用户可以在平台上完成常见数据处理任务的代码编写和测试,包括HiveSQL、Sparksql、Python等。 平台内置了一个在线代码编译器,方便用户进行数据处理任务的开发和测试。 应用镜像构建 根据不同的语言和版本,我们维护了不同的基础镜像,这些镜像可以用于任务开发和测试。 任务调度系统 除了数据开发平台自带的任务调度系统外,我们还提供了生产环境的任务调度系统,两者完全隔离,确保安全和稳定性。 用户可以在开发平台上进行工作流的开发、测试和定义,然后将其发布到生产环境的任务调度系统中,实现全流程的研发、测试和发布。 统一研发和测试环境 我们通过数据开发平台实现了完整的研发和测试流程: 物理隔离 数据开发平台和生产任务调度系统是两套独立部署的系统,物理上完全隔离,确保了环境的安全性和独立性。 完整的工作流管理 用户可以在数据开发平台上完成工作流的研发和测试,然后通过发布功能将工作流同步到生产任务调度系统中,确保工作流在生产环境中的正常运行。 数据资产管理路线 最后会给大家介绍一下我们现在的数据资产管理路线,这是我们今天的重点部分。 当前,我们针对任务调度系统本身的需求已经基本上平稳。最近正在进行整体的改造,即数据加工链路中涉及的平台工具间的集成,这也就是我们提到的DataOps平台工具,一体化数据资产管理平台。 任务调度系统与DataOps 在DataOps的实施中,除了关于人才需求的问题需要企业针对性地做出组织架构调整外,很多在工具层面的问题都可以以任务调度系统为出发点去解决。 现在高版本的Apache DolphinScheduler支持Flink节点,所以围绕数据加工任务,无论是批量数据还是流数据,都可以在任务调度系统内完成。 从数据集成到数据应用,包括中间的数据治理和数据加工之间的依赖关系,都可以在一张图中展示。 伪DAG图与数据处理 我们可以看到在伪DAG图中,包含了从数据采集、数据集成、数据加工和数据治理的整个流程。 当然,数据加工和数据治理可能会有多个环节。可视化数据处理平台是我们内部提供的一个工具,主要用于标签、BI报表和指标等数据应用模块,提供基础的数据处理功能。 这个工具不需要用户具备技术基础,只需通过页面上的可视化操作,拖拽配置即可完成数据加工任务的配置。 对于一些对外交付的小型项目,我们可以简化数据加工过程,直接通过可视化数据处理对接数据采集,为指标报表和BI提供基础数据处理工作。 这个过程可以有效解决数据加工链路的断层问题。以前,如果不在任务调度系统内,其他业务系统可能通过结果通知或轮询数据结果来实现依赖。 而现在,所有数据加工链路的依赖都可以在任务调度系统内通过DAG图直观地看到,避免了数据加工链路的断层问题。 数据治理的集成 将数据治理节点集成到数据加工任务中,可以将数据治理前置,传统做法是完成数据加工任务后再做数据治理,这样出现问题就需要排查整个数据加工链路。 而将数据治理集成到数据加工任务的过程中,可以有效的保证每个节点或某一段数据加工链路的数据质量问题。 全链路血缘与任务血缘 当数据加工任务修改了中间数据加工任务的结果后,我们无法判断哪些下游任务依赖当前数据加工任务的结果。依靠数据血缘分析仅能知道下游依赖的表,但不知道具体任务。 由于任务的依赖关系在任务调度系统中可能出现跨项目或底层数据依赖等情况,所以通过任务调度系统的任务血缘来判断,无法覆盖所有的下游任务。 所以将全链路的数据血缘与任务血缘相结合可以更为全面的覆盖下游任务范围,更好的做到影响分析从而减少生产事故。 本文由 白鲸开源科技 提供发布支持!

优秀的个人博客,低调大师

数仓调优实践丨多次关联发散导致数据爆炸案例分析改写

本文分享自华为云社区《GaussDB(DWS)性能调优:求字段全体值中大于本行值的最小值——多次关联发散导致数据爆炸案例分析改写》,作者: Zawami 。 1、【问题描述】 语句中存在同一个表多次自关联,且均为发散关联,数据爆炸导致性能瓶颈。 2、【原始SQL】 explain verbose WITH TMP AS ( SELECT WH_ID , (IFNULL(SUBSTR(THE_DATE,1,10),'1900-01-01') || ' ' || STOP_TIME)::TIMESTAMP AS STOP_TIME , (IFNULL(SUBSTR(THE_DATE,1,10),'1900-01-01') || ' ' || '23:59:59')::TIMESTAMP AS MAX_ASD FROM DMISC.DM_DIM_CBG_WH_HOLIDAY_D WHERE IS_OPEN = 'Y' AND STOP_TIME IS NOT NULL ) SELECT T1.WH_ID , T1.THE_DATE , T1.IS_OPEN , MIN(T2.STOP_TIME) AS STOP_TIME , MIN(T2.MAX_ASD) AS TODAY_MAX_ASD , MIN(T3.MAX_ASD) AS NEXT_MAX_ASD FROM (SELECT WH_ID , THE_DATE , IS_OPEN , (IFNULL(SUBSTR(THE_DATE,1,10),'1900-01-01') || ' ' || STOP_TIME)::TIMESTAMP AS STOP_TIME FROM DMISC.DM_DIM_CBG_WH_HOLIDAY_D ) T1 LEFT JOIN TMP T2 ON T1.WH_ID = T2.WH_ID AND T1.THE_DATE < T2.STOP_TIME LEFT JOIN TMP T3 ON T1.WH_ID = T3.WH_ID AND ADDDATE(T1.THE_DATE,1) < T3.STOP_TIME GROUP BY T1.WH_ID, T1.THE_DATE, T1.IS_OPEN; 从SQL中不难看出,物理表HOLIDAY_D使用WH_ID为关联键,并使用其它字段做不等值关联。 3、【性能分析】 QUERY PLAN | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| id | operation | E-rows | E-distinct | E-memory | E-width | E-costs | ----+----------------------------------------------------------------------------------+---------------+------------+---------------+---------+----------------- | 1 | -> Row Adapter | 51584 | | | 67 | 377559930171.36 | 2 | -> Vector Streaming (type: GATHER) | 51584 | | | 67 | 377559930171.36 | 3 | -> Vector Hash Aggregate | 51584 | | 16MB | 67 | 377559929546.36 | 4 | -> Vector CTE Append(5, 7) | 5699739636332 | | 1MB | 43 | 292063834485.54 | 5 | -> Vector Streaming(type: BROADCAST) | 757752 | | 2MB | 22 | 1474.87 | 6 | -> CStore Scan on dmisc.dm_dim_cbg_wh_holiday_d [5, CTE tmp(1)] | 757752 | | 1MB | 22 | 1474.87 | 7 | -> Vector Hash Left Join (8, 11) | 5699739636332 | | 107MB(6863MB) | 43 | 292063833010.67 | 8 | -> Vector Hash Right Join (9, 10) | 542231841 | 50 | 16MB | 27 | 22365789.31 | 9 | -> Vector CTE Scan on tmp(1) t3 | 31573 | 50 | 1MB | 48 | 15155.04 | 10 | -> CStore Scan on dmisc.dm_dim_cbg_wh_holiday_d | 51584 | 50 | 1MB | 19 | 556.58 | 11 | -> Vector CTE Scan on tmp(1) t2 | 31573 | 50 | 1MB | 48 | 15155.04 | 由于SQL非常慢,难以打出performance计划,我们先看verbose计划。从计划中我们看到,经过两次的关联发散,估计数据量达到了5万亿行;因为hash join根据WH_ID列进行关联,实际不会有这么多。所以调优的思路就是取消一些发散,让中间结果集行数变少。 4、【改写SQL】 分析SQL,可知发散是为了寻找所有STOP_TIME中大于本行THE_DATE的最小值。像这种每行都需要用到本行数据和所有数据的逻辑,或许可以使用窗口函数进行编写;但囿于笔者能力,先提供单次自关联的方法。 SQL改写如下: explain performance WITH TMP AS ( SELECT WH_ID , (IFNULL(SUBSTR(THE_DATE,1,10),'1900-01-01') || ' ' || STOP_TIME)::TIMESTAMP AS STOP_TIME , (IFNULL(SUBSTR(THE_DATE,1,10),'1900-01-01') || ' ' || '23:59:59')::TIMESTAMP AS MAX_ASD FROM DMISC.DM_DIM_CBG_WH_HOLIDAY_D WHERE IS_OPEN = 'Y' AND STOP_TIME IS NOT NULL ) SELECT T1.WH_ID , T1.THE_DATE , T1.IS_OPEN , MIN(CASE WHEN T1.THE_DATE < T2.STOP_TIME THEN STOP_TIME ELSE NULL END) AS STOP_TIME , MIN(CASE WHEN T1.THE_DATE < T2.STOP_TIME THEN T2.MAX_ASD ELSE NULL END) AS TODAY_MAX_ASD , MIN(CASE WHEN ADDDATE(T1.THE_DATE, 1) < T2.STOP_TIME THEN T2.MAX_ASD ELSE NULL END) AS NEXT_MAX_ASD FROM (SELECT DISTINCT WH_ID , THE_DATE , IS_OPEN FROM DMISC.DM_DIM_CBG_WH_HOLIDAY_D ) T1 LEFT JOIN TMP T2 ON T1.WH_ID = T2.WH_ID GROUP BY T1.WH_ID , T1.THE_DATE , T1.IS_OPEN ; 经过改写,取消了一次自关联,SQL的中间结果集变小。在关联后,通过条件聚合来得到需要的值。 id | operation | A-time | A-rows | E-rows | E-distinct | Peak Memory | E-memory | A-width | E-width | E-costs ----+-----------------------------------------------------------------+----------------------+----------+--------+------------+----------------+----------+-----------+---------+---------- 1 | -> Row Adapter | 7490.354 | 34035 | 200 | | 70KB | | | 58 | 15149.80 2 | -> Vector Streaming (type: GATHER) | 7488.129 | 34035 | 200 | | 216KB | | | 58 | 15149.80 3 | -> Vector Hash Aggregate | [7481.430, 7481.430] | 34035 | 200 | | [9MB, 9MB] | 16MB | [112,112] | 58 | 15137.30 4 | -> Vector Hash Left Join (5, 7) | [909.377, 909.377] | 31204164 | 109803 | | [2MB, 2MB] | 16MB | | 34 | 3880.50 5 | -> Vector Sonic Hash Aggregate | [5.876, 5.876] | 34035 | 34036 | 6807 | [3MB, 3MB] | 16MB | [51,51] | 18 | 1127.67 6 | -> CStore Scan on dmisc.dm_dim_cbg_wh_holiday_d | [0.199, 0.199] | 34036 | 34036 | | [792KB, 792KB] | 1MB | | 18 | 532.04 7 | -> CStore Scan on dmisc.dm_dim_cbg_wh_holiday_d | [40.794, 40.794] | 25122 | 21960 | 19 | [1MB, 1MB] | 1MB | [59,59] | 24 | 617.13 从执行计划中可以看到,中间结果集大小已经在可接受的范围内。但是又看到聚合3千万数据使用了6s+的时间,这是过慢的,需要看执行计划中的DN信息寻找原因 。 Datanode Information (identified by plan id) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1 --Row Adapter (actual time=7486.498..7490.354 rows=34035 loops=1) (CPU: ex c/r=107, ex row=34035, ex cyc=3668104, inc cyc=22468059912) 2 --Vector Streaming (type: GATHER) (actual time=7486.466..7488.129 rows=34035 loops=1) (Buffers: shared hit=1) (CPU: ex c/r=660037, ex row=34035, ex cyc=22464391808, inc cyc=22464391808) 3 --Vector Hash Aggregate dn_6083_6084 (actual time=7479.644..7481.430 rows=34035 loops=1) (projection time=4488.807) dn_6083_6084 (Buffers: shared hit=40) dn_6083_6084 (CPU: ex c/r=631, ex row=31204164, ex cyc=19718763112, inc cyc=22443886288) 4 --Vector Hash Left Join (5, 7) dn_6083_6084 (actual time=48.009..909.377 rows=31204164 loops=1) dn_6083_6084 (Buffers: shared hit=36) dn_6083_6084 (CPU: ex c/r=43699, ex row=59157, ex cyc=2585141400, inc cyc=2725123176) 5 --Vector Sonic Hash Aggregate dn_6083_6084 (actual time=5.177..5.876 rows=34035 loops=1) dn_6083_6084 (Buffers: shared hit=11) dn_6083_6084 (CPU: ex c/r=500, ex row=34036, ex cyc=17027544, inc cyc=17619064) 6 --CStore Scan on dmisc.dm_dim_cbg_wh_holiday_d dn_6083_6084 (actual time=0.043..0.199 rows=34036 loops=1) (CU ScanInfo: smallCu: 0, totalCu: 1, avrCuRow: 34036, totalDeadRows: 0) dn_6083_6084 (Buffers: shared hit=11) dn_6083_6084 (CPU: ex c/r=17, ex row=34036, ex cyc=591520, inc cyc=591520) 7 --CStore Scan on dmisc.dm_dim_cbg_wh_holiday_d dn_6083_6084 (actual time=6.464..40.794 rows=25122 loops=1) (filter time=0.872 projection time=33.671) (RoughCheck CU: CUNone: 0, CUTagNone: 0, CUSome: 1) (CU ScanInfo: smallCu: 0, totalCu: 1, avrCuRow: 34036, totalDeadRows: 0) dn_6083_6084 (Buffers: shared hit=25) dn_6083_6084 (CPU: ex c/r=3595, ex row=34036, ex cyc=122362712, inc cyc=122362712) 从中可以看出,所有算子都只在一个DN上运行了。这可以视为严重的计算倾斜,若对单点性能有更高要求需要继续优化。查看DMISC.DM_DIM_CBG_WH_HOLIDAY_D表的定义,发现它是一个复制表(distribute by replication),在进行各层运算的时候只用其中一个DN来算。而在本SQL中,使用到这张表的时候,关联键都是WH_ID。 再查看调整分布列为WH_ID的倾斜情况: select * from pg_catalog.table_skewness('DMISC.DM_DIM_CBG_WH_HOLIDAY_D', 'wh_id'); 结果有23行,小于集群DN个数,且存在倾斜。但是本SQL需要使用该表的全量数据,故可以把这张表改为使用WH_ID作为分步键进行重分布。 由表分布方式为复制表导致的计算倾斜无法使用skew hint解决,可以改变物理表分布方式或者创建临时表来解决(复制表通常较小)。由于表在SQL中的使用情况和表的倾斜情况,不适合更改物理表分步键为WH_ID,故本例中试使用创建临时表指定重分布方式的办法解决。 DROP TABLE IF EXISTS holiday_d_tmp; CREATE TEMP TABLE holiday_d_tmp WITH ( orientation = COLUMN, compression = low ) distribute BY hash ( wh_id ) AS ( SELECT * FROM DMISC.DM_DIM_CBG_WH_HOLIDAY_D ); EXPLAIN performance WITH TMP AS ( SELECT WH_ID, ( IFNULL ( SUBSTR( THE_DATE, 1, 10 ), '1900-01-01' ) || ' ' || STOP_TIME ) :: TIMESTAMP AS STOP_TIME, ( IFNULL ( SUBSTR( THE_DATE, 1, 10 ), '1900-01-01' ) || ' ' || '23:59:59' ) :: TIMESTAMP AS MAX_ASD FROM holiday_d_tmp WHERE IS_OPEN = 'Y' AND STOP_TIME IS NOT NULL ) SELECT T1.WH_ID, T1.THE_DATE, T1.IS_OPEN, MIN ( CASE WHEN T1.THE_DATE < T2.STOP_TIME THEN STOP_TIME ELSE NULL END ) AS STOP_TIME, MIN ( CASE WHEN T1.THE_DATE < T2.STOP_TIME THEN T2.MAX_ASD ELSE NULL END ) AS TODAY_MAX_ASD, MIN ( CASE WHEN ADDDATE ( T1.THE_DATE, 1 ) < T2.STOP_TIME THEN T2.MAX_ASD ELSE NULL END ) AS NEXT_MAX_ASD FROM ( SELECT WH_ID, THE_DATE, IS_OPEN FROM holiday_d_tmp ) T1 LEFT JOIN TMP T2 ON T1.WH_ID = T2.WH_ID GROUP BY T1.WH_ID, T1.THE_DATE, T1.IS_OPEN; 下面是对应的执行计划: id | operation | A-time | A-rows | E-rows | E-distinct | Peak Memory | E-memory | A-width | E-width | E-costs ----+--------------------------------------------------------------------------------------+------------------+----------+----------+------------+----------------+----------+---------+---------+---------- 1 | -> Row Adapter | 673.495 | 34035 | 34032 | | 70KB | | | 58 | 68112.60 2 | -> Vector Streaming (type: GATHER) | 671.103 | 34035 | 34032 | | 216KB | | | 58 | 68112.60 3 | -> Vector Hash Aggregate | [0.079, 672.724] | 34035 | 34032 | | [1MB, 1MB] | 16MB | [0,114] | 58 | 67794.10 4 | -> Vector Hash Left Join (5, 6) | [0.047, 76.395] | 31205167 | 27587201 | | [324KB, 485KB] | 16MB | | 34 | 8876.88 5 | -> CStore Scan on pg_temp_cn_5003_6_22022_139764371019520.holiday_d_tmp | [0.004, 0.098] | 34036 | 34036 | 1 | [760KB, 792KB] | 1MB | | 18 | 1553.65 6 | -> CStore Scan on pg_temp_cn_5003_6_22022_139764371019520.holiday_d_tmp | [0.008, 3.253] | 25122 | 22018 | 1 | [880KB, 1MB] | 1MB | [0,61] | 24 | 1557.76 从计划中我们可以看到,耗时比单个DN运算快了不少,当然这里没有算上创建临时表的时间约0.2s。 5、【调优总结】 在本案例中,因为实际执行SQL时间太长先看了verbose计划而非performance计划,发现中间结果集发散问题后,进行等价逻辑改写,把两个(等值-不等值)关联改为一个等值关联和条件聚合。之后,我们发现SQL因复制表存在计算倾斜问题,考虑SQL消费表数据的方式和表的统计数据,采用了使用临时表重新指定分布方式的方法,解决了计算倾斜问题,SQL从单点25min+优化到单点800ms。 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

数仓实践丨表扫描时过滤行数过多引起的性能瓶颈问题

本文分享自华为云社区《GaussDB(DWS)性能调优:表扫描时过滤行数过多引起的性能瓶颈问题案例》,作者: O泡果奶~ 。 1、【问题描述】 SQL语句执行过程中,对12亿数据量的大表进行扫描,过滤99%的数据仅留617行数据,性能瓶颈位于扫描该表这里。 2、【原始语句】 set search_path = 'bi_dashboard'; WITH F_SRV_DB_DIM_PRD_D AS (SELECT EXTERNAL_NAME FROM ( SELECT MKT_NAME EXTERNAL_NAME FROM BI_DASHBOARD.DM_MSS_ITEM_PRODUCT_D PRD WHERE PRD.COMPANY_BRAND =any(array[string_to_array('HUAWEI',',')]) AND PRD.MKT_NAME =any(array[string_to_array('畅享 60,畅享 50,畅享 60X,畅享 60 Pro,畅享 50 Pro,畅享 50z,nova 10z,畅享 20e,畅享20 Pro,畅享 10e,畅享10 Plus,畅享20 SE,畅享10,nova 11i,畅享20 Plus,畅享9 Plus,畅享20 5G,nova Y90,畅享 10S,nova Y70,畅享Z,畅享 9S,nova 8 SE 活力版,麦芒9 5G,Y9s,麦芒9 5G',',')]) ) WHERE EXTERNAL_NAME<>'SNULL' GROUP BY EXTERNAL_NAME), V_PERIOD AS ( SELECT PERIOD_ID AS PERIOD_ID_M, LEAST(TO_CHAR(PERIOD_END_DATE, 'YYYYMMDD'), '20230630') AS PERIOD_ID, PERIOD_ID AS DATES FROM BI_DASHBOARD.RPT_TML_ACCOUNT_PERIOD_D WHERE PERIOD_TYPE = 'M' AND PERIOD_ID BETWEEN 202207 AND 202306 ), V_DATA_BASE AS ( SELECT A.PERIOD_ID, IFNULL(A.CHANNEL_NAME, 'SNULL') AS DISTRIBUTOR_CHANNEL_NAME, SUM(A.SO_QTY_MTD) AS SO_QTY, SUM(DECODE(A.PERIOD_ID, 20230630, A.SO_QTY_MTD)) AS SO_QTY_ORDER select count(*) FROM DM_MSS_CN_PC_REP_RP_ST_D_F A INNER JOIN F_SRV_DB_DIM_PRD_D PRD ON A.EXTERNAL_NAME = PRD.EXTERNAL_NAME WHERE 1 = 1 AND A.CHANNEL_ID IN ('100013388802') AND A.ORG_KEY IN (10000651) AND A.SALES_FLAG IN ('1', '0') AND A.PERIOD_ID IN (20220731,20221031,20220930,20220831,20221130,20221231,20230131,20230228,20230430,20230331,20230531,20230630) AND (A.SO_QTY_MTD <> 0) -- 过滤所有日期SO_QTY为0的数据 GROUP BY A.PERIOD_ID, IFNULL(A.CHANNEL_NAME, 'SNULL') ), V_DATA AS ( SELECT PERIOD_ID, NVL(DISTRIBUTOR_CHANNEL_NAME, 'Total') AS DISTRIBUTOR_CHANNEL_NAME, SUM(SO_QTY) AS SO_QTY, SUM(SO_QTY_ORDER) AS SO_QTY_ORDER FROM V_DATA_BASE A GROUP BY GROUPING SETS ((PERIOD_ID), (PERIOD_ID, DISTRIBUTOR_CHANNEL_NAME)) ) SELECT STRING_AGG(P.DATES, ',' ORDER BY P.PERIOD_ID_M) AS PERIOD_LIST, B.DISTRIBUTOR_CHANNEL_NAME, STRING_AGG(NVL(TO_CHAR(ROUND(A.SO_QTY)), '0'), ',' ORDER BY P.PERIOD_ID_M) AS SO_QTY FROM V_PERIOD P FULL JOIN (SELECT DISTINCT DISTRIBUTOR_CHANNEL_NAME FROM V_DATA) B ON 1 = 1 LEFT JOIN V_DATA A ON A.PERIOD_ID = P.PERIOD_ID AND A.DISTRIBUTOR_CHANNEL_NAME = B.DISTRIBUTOR_CHANNEL_NAME GROUP BY B.DISTRIBUTOR_CHANNEL_NAME ORDER BY DECODE(B.DISTRIBUTOR_CHANNEL_NAME, 'Total', 0, 'SOURCE IS NULL', 2, '源为空', 3, 'SNULL', 4, 1), SUM(A.SO_QTY_ORDER) DESC NULLS LAST LIMIT 50 OFFSET 0 3、【性能分析】 从上图的performance执行计划中可以看出(完整执行计划放在附件一),该SQL语句慢在扫描表a(bi_dashboard.dm_mss_cn_pc_rep_rp_st_d_f_test)。扫描时过滤条件包括:sales_flag、so_qty_mtd、channel_id、org_key、period_id,该表上原本的局部聚簇键PCK只包含了period_id,并没有包括其余三个过滤条件之一,因此,可以调整PCK,以减少扫描表a的执行时间。 补充:局部聚簇键 局部聚簇 (Partial Cluster Key, 简称PCK),列存储下一种通过min/max稀疏索引实现基表快速扫描的索引技术。Partial Cluster Key可以指定多列,但是一般不建议超过2列。PCK适用于列存大表点查询加速。 另外,查看语句中where条件中in值较多(12个),在DWS中,in后面的条件默认就只能是5个,超过6个就过滤不下推,此时,可以用or将12个值改写, A.PERIOD_ID IN (20220731,20221031,20220930,20220831,20221130) or A.PERIOD_ID IN (20221231,20230131,20230228,20230430,20230331) or A.PERIOD_ID IN (20230531,20230630) 此时,SQL语句执行时间减少为487ms,完整performance计划如附件二所示。 附件:优化后—performance.txt466.64KB 附件:优化前—performance.txt449.47KB 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

数仓实时场景下表行数估算不准确引起的的性能瓶颈问题案例

本文分享自华为云社区《GaussDB(DWS)性能调优:实时场景下表行数估算不准确引起的的性能瓶颈问题案例》,作者: O泡果奶~。 本文针对实时场景下SQL语句因表行数估算不准确而导致语句执行超时报错的案例进行分析。 1、【问题描述】 实时场景下,select查询语句执行时间过长,该语句verbose执行计划中存在nestloop,且使用hint(set (enable_index_nestloop off)) 无法生效。 2、【原始语句】 select * from ( select wo.work_order_id /*工单id*/, wo.work_order_code /*工单编码*/, wo.work_order_name /*工单名称*/, wo.work_order_level /*工单层级(第一层级(未拆分工单/父工单):1,第二层级(子工单):10)*/, decode(wo.work_order_level,1, '第一层级(未拆分工单/父工单)', 10,'第二层级(子工单)') as work_order_level_desc /*工单层级描述*/, substrb(wo.wo_description, 1, 1000) as wo_description /*工单描述*/, wo.wo_version /*工单版本号*/, wo.wo_lifecycle_status /*生命周期标识:0:正常工单,-1: 已删除*/, wo.business_id /*工单来源业务id*/, wo.business_type /*工单来源业务类型(10:活动流工单 20:手工派单 30:拆单工单 40:临时mos工单 50:ihub工单 60:ipmo工单 70:wbs工单 80:ncs工单 90:hr工单 100:ls工单 默认10)*/, decode( wo.business_type, '10', '活动流工单', '20', '手工派单', '30', '拆单工单', '40', '临时MOS工单', '50', 'ihub工单', '60', 'ipmo工单', '70', 'WBS工单', '80', 'NCS工单', '90', 'HR工单', '100', 'LS工单' ) as business_type_desc /*工单来源业务类型描述*/, wo.parent_activity_id /*父节点活动id*/, wo.activity_lib_id /*活动库活动id*/, wo.activity_type /*作业类型,1wbs,2活动,3里程碑*/, ac.activity_name /*活动名称*/, ac.std_ms_code as standard_ms_code /*标准里程碑编码*/, wo.plan_id /*计划id*/, wo.project_number as proj_num /*项目编码*/, wo.du_id /*交付单元id*/, wo.duration /*工期*/, wo.billing_flag /*开票标识:y-开票*/, wo.na_flag /*na标识*/, wo.inv_flag /*inv标识*/, wo.master_flag /*拆分标示,n:未拆分 ; y:已拆分*/, wo.created_by as created_by_id /*创建人user id*/, u1.lname as created_by /*创建人*/, wo.creation_date /*创建时间*/, wo.last_updated_by as last_updated_by_id /*最后更新人user id*/, u2.lname as last_updated_by /*最后更新人*/, wo.last_update_date /*最后更新时间*/, wp.wo_progress_id /*活动进度id*/, wp.expect_start_date /*预期开始日期*/, wp.expect_end_date /*预期结束日期*/, wp.plan_start_time /*计划开始时间*/, wp.plan_end_time /*计划完成时间*/, wp.actual_start_time /*实际开始时间*/, wp.actual_end_time /*实际完成时间*/, wp.close_time /*活动关闭时间*/, wp.completion_rate /*完工比率(数值如 0.8666)*/, to_char(substr(wp.remark, 1, 333)) as progress_description /*进度备注信息*/, wp.total_value /*总值*/, wp.accumulate_value /*累计值*/, wp.report_time /*值反馈时间*/, wp.total_plan_value /*总计划值*/, wp.ehs_risk /*高危活动类型*/, wp.delay_reason_id /*延迟原因id*/, substrb(ag.description, 1, 1000) as delay_reason_description /*延迟原因描述*/, wp.wo_status /*活动状态 psc_lookup_item_t_3220 classify_code = 'WO_STATUS_CODE'*/, l2.item_name as wo_status_desc /*活动状态描述*/,( case when lengthb(wp.approve_status) = 0 then null else wp.approve_status end ) :: number as approve_status /*审批状态 psc_lookup_item_t_3220 classify_code = 'WORK_ORDER_APPROVE_STATUS'*/, l3.item_name as approve_status_desc /*审批状态描述*/, wp.par_workorder_doc_flag /*父工单是否有交付件(y/n)*/, wp.deliverables_complete /*交付件上传状态 0:不涉及交付件 1:待上传交付件 2:交付件上传中,未上传完9:交付件已上传完*/, wp.revenue_trigger_status /*触发状态(0:未触发过 1:已触发 2:已触发,pc校验触发失败 3:pc触发成功)*/, wp.billing_status /*开票状态(空值:未触发过 1:已开票)*/, wp.frozen_flag /*冻结标识(y/n)*/, wp.mr_frozen_flag /*mr是否冻结站点要货通过更新实施计划刷新字段*/, wp.mr_status /*站点签状态 1未签收,2部分签收,3全部签收,10未签收,20部分签收,30全部签收,40部分超配置签收,50全部超配置签收 完工验状态 p:部分完成,f:全部完成*/, wp.tool_flag /*是否挂工具工单回写(y/n)*/, wp.split_cp_flag /*拆分施工计划标识 y已拆分 n未拆分*/, wp.mos_data_source /*站点签完工验状数据来源*/, wo.template_id /*模板id,例如活动流节点id*/, tfn.task_flow_id /*任务流id*/, tfn.task_flow_node_id /*活动流节点id*/, tfn.revenue_flag /*收入里程碑标识(y/n)*/, tfn.on_site /*是否现场*/, nvl(l1.item_name, tfn.owner_type) as owner_type /*责任方类型 客户/华为/分包商*/, tfn.subcon /*是否分包*/ /*产品域*/,case when wo.enable_flag = 'Y' and wp.enable_flag = 'Y' and wo.wo_lifecycle_status = 0 and nvl(du.enable_flag, 'Y') = 'Y' then 'Y' else 'N' end as enable_flag /*有效标识,y为有效n为失效*/, 'N' as del_flag /*删除标识 y为已删除*/, 3 as data_center_id /*数据中心id*/, tf.task_flow_code /*活动流编码 add by jwx528041 20200408*/, tfn.task_flow_node_code /*任务流节点编码 add by jwx528041 20200408*/, tfn.task_flow_node_name /*任务流节点名称 add by jwx528041 20200408*/, tfn.task_flow_node_type /*任务流节点类型 add by jwx528041 20200408*/, tfn.enable_flag as flow_enable_flag /*活动流有效标识 add by jwx528041 20200408*/, wo.tenant_code /*租户编码 add by jwx528041 20200408*/, tfn.activity_id /*活动流水号 add by jwx528041 20200408*/, tfn.lead_time /*持续时间 add by jwx528041 20200408*/, wo.resource_id as wo_actual_owner_id /*工单实际责任人id update by swx949890 202207*/, wo.resource_name as wo_actual_owner /*工单实际责任人 update by swx949890 202207*/, wo.contractor_id as wo_actual_owner_contr_id /*工单实际责任人分包商id update by swx949890 202207*/, wo.contractor_name as wo_actual_owner_contr_name /*工单实际责任人分包商名称 update by swx949890 202207*/, nvl(l4.item_name, tfn.delivery_model) as delivery_model /*工单交付模式 add by cwx613468 20200711*/, tfn.on_line_site /*是否上站 add by cwx613468 20200711*/, u3.lname as dispatcher_user_name /*调度人 add by cwx613468 20200711*/, tfn.approve_level_qty /*审批总层级 add by jwx528041 20200819*/, tf.task_flow_name /*活动流名称 add by jwx528041 20200819*/, tf.task_flow_type /*活动流类型 add by jwx528041 20200819*/, wp.source_code /*标识actual时间的修改来源,值为mobile标识从手机端回写 add by jwx528041 20200819*/, wp.plan_updated_by /*实际开始时间更新人user id add by jwx528041 20200819*/, wp.plan_update_time /*计划时间更新时间 add by jwx528041 20200819*/, wp.dispatch_time /*调度时间 add by jwx528041 20200819*/, wp.first_actual_update_time /*第一次实际开始时间填入时间 add by jwx528041 20200819*/, wp.first_actual_end_time /*第一次实际结束时间填入时间 add by jwx528041 20200819*/, wp.first_actual_updated_by /*第一次实际时间填入人user id add by jwx528041 20200819*/, wp.actual_start_update_time /*实际开始时间更新日期 add by jwx528041 20200819*/, wp.actual_start_updated_by /*实际开始时间更新人user id add by jwx528041 20200819*/, wp.actual_time_source /*实际完成时间更新来源 add by jwx528041 20200819*/, wp.actual_end_update_time /*实际完成时间更新日期 add by jwx528041 20200819*/, wp.actual_end_updated_by /*实际完成时间更新人user id add by jwx528041 20200819*/, wp.revenue_trigger_failed_msg /*收入触发失败原因 add by jwx528041 20200819*/, ag.souce_type as delay_reason_souce_type /*延迟原因数据来源:1、自定义 2、 add by jwx528041 20200819*/ --,ras.tree_type as wo_owner_tree_type /*工单责任人项目树节点类型tree_type add by jwx528041 20200819*/ , wo.tree_type as wo_owner_tree_type /*工单责任人项目树节点类型tree_type update by swx949890 202207*/, dr.resouce_type as wo_owner_resouce_type /*工单责任人资源类型 add by jwx528041 20200819*/, l5.item_name as wo_owner_resouce_type_desc /*工单责任人资源类型 add by jwx528041 20200819*/, u4.w3_account as wo_owner_w3_account /*工单责任人w3账号 add by jwx528041 20200819*/, rel.du_tf_rel_enable /*du与活动流关系有效性标识 y:有效 n:失效 add by lwx617215 20210116*/, t.billing_sla /*sla*/, t.billing_milestone /*开票里程碑*/, tf.required_tools, wp.active, gp.plan_code, gp.plan_name, gp.template_plan_id from sdisd.ogg_wo_work_order_2_3220 wo inner join sdisd.ogg_wo_progress_2_3220 wp on wo.work_order_id = wp.work_order_id left join sdisd.ogg_wo_task_flow_node_br_3220 tfn on wo.template_id = tfn.task_flow_node_id and nvl(wo.wo_version, 0) = case when nvl(wo.wo_version, 0) > 0 then tfn.version else tfn.wo_version end and wo.project_number = tfn.project_number left join sdisd.ogg_sds_activity_t_br_3220 ac on wo.activity_lib_id = ac.activity_id left join sdisd.ogg_sds_task_flow_t_br_3220 tf on tfn.task_flow_id = tf.task_flow_id left join sdisd.ogg_du_release_t_br_3220 du /*enable_flag新增有效du的判断 lwx617215 20210116*/ on wo.du_id = du.du_id left join sdisd.ogg_gcc_plan_2_3220 gp --dwx1189869 on wo.plan_id = gp.plan_id and gp.tenant_code = 'RolloutPlan' and gp.parent_plan_id = -1 and gp.enable_flag = 'Y' left join ( select r.du_id, r.task_flow_id, /*du与活动流有效标识*/ case when r.enable_flag = 'Y' and publish_flag = 'P' then 'Y' else 'N' end as du_tf_rel_enable, row_number() over( partition by r.du_id, r.task_flow_id order by r.last_update_date desc ) as rn from sdisd.ogg_rp_du_tf_release_3_3220 r ) rel on wo.du_id = rel.du_id and tfn.task_flow_id = rel.task_flow_id and rel.rn = 1 left join sdisd.ogg_tpl_user_t_3220 u1 on wo.created_by = u1.user_id left join sdisd.ogg_tpl_user_t_3220 u2 on wo.last_updated_by = u2.user_id left join sdisd.ogg_tpl_user_t_3220 u3 on wp.dispatcher_user_id = u3.user_id left join sdisd.ogg_sds_activity_gap_t_br_3220 ag on wp.delay_reason_id = ag.activity_gap_id left join sdisd.ogg_tpl_lookup_item_t_3220 l1 on tfn.owner_type = l1.item_code and l1.classify_code = 'SDS_TASK_OWNER_TYPE' and l1.language = 'en_US' left join sdisd.ogg_psc_lookup_item_t_3220 l2 on wp.wo_status = l2.item_code and l2.classify_code = 'WO_STATUS_CODE' and l2.language = 'en_US' left join sdisd.ogg_psc_lookup_item_t_3220 l3 on wp.approve_status = l3.item_code and l3.classify_code = 'WORK_ORDER_APPROVE_STATUS' and l3.language = 'en_US' left join sdisd.ogg_tpl_lookup_item_t_3220 l4 on tfn.delivery_model = l4.item_code and l4.classify_code = 'SDS_TASK_ON_SITE' and l4.language = 'en_US' left join sdisd.ogg_pm_project_tree_node_3220 tn on wo.resource_id = tn.tree_id left join sdisd.ogg_pm_delivery_resource_3220 dr on tn.resource_id = dr.resource_id left join sdisd.ogg_tpl_user_t_3220 u4 on dr.user_id = u4.user_id left join sdisd.ogg_tpl_lookup_item_t_3220 l5 on dr.resouce_type = l5.item_code and l5.classify_code = 'PM_RESOURCE_TYPE' and l5.language = 'zh_CN' left join sdisd.ogg_sds_task_flow_node_br_3220 t on tfn.task_flow_node_id = t.task_flow_node_id where ( wo.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or wp.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or tfn.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or ag.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 ) union all select wo.work_order_id /*工单id*/, wo.work_order_code /*工单编码*/, wo.work_order_name /*工单名称*/, wo.work_order_level /*工单层级(第一层级(未拆分工单/父工单):1,第二层级(子工单):10)*/, decode( wo.work_order_level, 1, '第一层级(未拆分工单/父工单)', 10, '第二层级(子工单)' ) as work_order_level_desc /*工单层级描述*/, substrb(wo.wo_description, 1, 1000) as wo_description /*工单描述*/, wo.wo_version /*工单版本号*/, wo.wo_lifecycle_status /*生命周期标识:0:正常工单,-1: 已删除*/, wo.business_id /*工单来源业务id*/, wo.business_type /*工单来源业务类型(10:活动流工单 20:手工派单 30:拆单工单 40:临时mos工单 50:ihub工单 60:ipmo工单 70:wbs工单 80:ncs工单 90:hr工单 100:ls工单 默认10)*/, decode( wo.business_type, '10', '活动流工单', '20', '手工派单', '30', '拆单工单', '40', '临时MOS工单', '50', 'ihub工单', '60', 'ipmo工单', '70', 'WBS工单', '80', 'NCS工单', '90', 'HR工单', '100', 'LS工单' ) as business_type_desc /*工单来源业务类型描述*/, wo.parent_activity_id /*父节点活动id*/, wo.activity_lib_id /*活动库活动id*/, wo.activity_type /*作业类型,1wbs,2活动,3里程碑*/, ac.activity_name /*活动名称*/, ac.std_ms_code as standard_ms_code /*标准里程碑编码*/, wo.plan_id /*计划id*/, wo.project_number as proj_num /*项目编码*/, wo.du_id /*交付单元id*/, wo.duration /*工期*/, wo.billing_flag /*开票标识:y-开票*/, wo.na_flag /*na标识*/, wo.inv_flag /*inv标识*/, wo.master_flag /*拆分标示,n:未拆分 ; y:已拆分*/, wo.created_by as created_by_id /*创建人user id*/, u1.lname as created_by /*创建人*/, wo.creation_date /*创建时间*/, wo.last_updated_by as last_updated_by_id /*最后更新人user id*/, u2.lname as last_updated_by /*最后更新人*/, wo.last_update_date /*最后更新时间*/, wp.wo_progress_id /*活动进度id*/, wp.expect_start_date /*预期开始日期*/, wp.expect_end_date /*预期结束日期*/, wp.plan_start_time /*计划开始时间*/, wp.plan_end_time /*计划完成时间*/, wp.actual_start_time /*实际开始时间*/, wp.actual_end_time /*实际完成时间*/, wp.close_time /*活动关闭时间*/, wp.completion_rate /*完工比率(数值如 0.8666)*/, to_char(substr(wp.remark, 1, 333)) as progress_description /*进度备注信息*/, wp.total_value /*总值*/, wp.accumulate_value /*累计值*/, wp.report_time /*值反馈时间*/, wp.total_plan_value /*总计划值*/, wp.ehs_risk /*高危活动类型*/, wp.delay_reason_id /*延迟原因id*/, substrb(ag.description, 1, 1000) as delay_reason_description /*延迟原因描述*/, wp.wo_status /*活动状态 psc_lookup_item_t_3220 classify_code = 'WO_STATUS_CODE'*/, l2.item_name as wo_status_desc /*活动状态描述*/,( case when lengthb(wp.approve_status) = 0 then null else wp.approve_status end ) :: number as approve_status /*审批状态 psc_lookup_item_t_3220 classify_code = 'WORK_ORDER_APPROVE_STATUS'*/, l3.item_name as approve_status_desc /*审批状态描述*/, wp.par_workorder_doc_flag /*父工单是否有交付件(y/n)*/, wp.deliverables_complete /*交付件上传状态 0:不涉及交付件 1:待上传交付件 2:交付件上传中,未上传完9:交付件已上传完*/, wp.revenue_trigger_status /*触发状态(0:未触发过 1:已触发 2:已触发,pc校验触发失败 3:pc触发成功)*/, wp.billing_status /*开票状态(空值:未触发过 1:已开票)*/, wp.frozen_flag /*冻结标识(y/n)*/, wp.mr_frozen_flag /*mr是否冻结站点要货通过更新实施计划刷新字段*/, wp.mr_status /*站点签状态 1未签收,2部分签收,3全部签收,10未签收,20部分签收,30全部签收,40部分超配置签收,50全部超配置签收 完工验状态 p:部分完成,f:全部完成*/, wp.tool_flag /*是否挂工具工单回写(y/n)*/, wp.split_cp_flag /*拆分施工计划标识 y已拆分 n未拆分*/, wp.mos_data_source /*站点签完工验状数据来源*/, wo.template_id /*模板id,例如活动流节点id*/, tfn.task_flow_id /*任务流id*/, tfn.task_flow_node_id /*活动流节点id*/, tfn.revenue_flag /*收入里程碑标识(y/n)*/, tfn.on_site /*是否现场*/, nvl(l1.item_name, tfn.owner_type) as owner_type /*责任方类型 客户/华为/分包商*/, tfn.subcon /*是否分包*/ /*产品域*/,case when wo.enable_flag = 'Y' and wp.enable_flag = 'Y' and wo.wo_lifecycle_status = 0 and nvl(du.enable_flag, 'Y') = 'Y' then 'Y' else 'N' end as enable_flag /*有效标识,y为有效n为失效*/, 'N' as del_flag /*删除标识 y为已删除*/, 4 as data_center_id /*数据中心id*/, tf.task_flow_code /*活动流编码 add by jwx528041 20200408*/, tfn.task_flow_node_code /*任务流节点编码 add by jwx528041 20200408*/, tfn.task_flow_node_name /*任务流节点名称 add by jwx528041 20200408*/, tfn.task_flow_node_type /*任务流节点类型 add by jwx528041 20200408*/, tfn.enable_flag as flow_enable_flag /*活动流有效标识 add by jwx528041 20200408*/, wo.tenant_code /*租户编码 add by jwx528041 20200408*/, tfn.activity_id /*活动流水号 add by jwx528041 20200408*/, tfn.lead_time /*持续时间 add by jwx528041 20200408*/, wo.resource_id as wo_actual_owner_id /*工单实际责任人id update by swx949890 202207*/, wo.resource_name as wo_actual_owner /*工单实际责任人 update by swx949890 202207*/, wo.contractor_id as wo_actual_owner_contr_id /*工单实际责任人分包商id update by swx949890 202207*/, wo.contractor_name as wo_actual_owner_contr_name /*工单实际责任人分包商名称 update by swx949890 202207*/, nvl(l4.item_name, tfn.delivery_model) as delivery_model /*工单交付模式 add by cwx613468 20200711*/, tfn.on_line_site /*是否上站 add by cwx613468 20200711*/, u3.lname as dispatcher_user_name /*调度人 add by cwx613468 20200711*/, tfn.approve_level_qty /*审批总层级 add by jwx528041 20200819*/, tf.task_flow_name /*活动流名称 add by jwx528041 20200819*/, tf.task_flow_type /*活动流类型 add by jwx528041 20200819*/, wp.source_code /*标识actual时间的修改来源,值为mobile标识从手机端回写 add by jwx528041 20200819*/, wp.plan_updated_by /*实际开始时间更新人user id add by jwx528041 20200819*/, wp.plan_update_time /*计划时间更新时间 add by jwx528041 20200819*/, wp.dispatch_time /*调度时间 add by jwx528041 20200819*/, wp.first_actual_update_time /*第一次实际开始时间填入时间 add by jwx528041 20200819*/, wp.first_actual_end_time /*第一次实际结束时间填入时间 add by jwx528041 20200819*/, wp.first_actual_updated_by /*第一次实际时间填入人user id add by jwx528041 20200819*/, wp.actual_start_update_time /*实际开始时间更新日期 add by jwx528041 20200819*/, wp.actual_start_updated_by /*实际开始时间更新人user id add by jwx528041 20200819*/, wp.actual_time_source /*实际完成时间更新来源 add by jwx528041 20200819*/, wp.actual_end_update_time /*实际完成时间更新日期 add by jwx528041 20200819*/, wp.actual_end_updated_by /*实际完成时间更新人user id add by jwx528041 20200819*/, wp.revenue_trigger_failed_msg /*收入触发失败原因 add by jwx528041 20200819*/, ag.souce_type as delay_reason_souce_type /*延迟原因数据来源:1、自定义 2、 add by jwx528041 20200819*/ --,ras.tree_type as wo_owner_tree_type /*工单责任人项目树节点类型tree_type add by jwx528041 20200819*/ , wo.tree_type as wo_owner_tree_type /*工单责任人项目树节点类型tree_type update by swx949890 202207*/, dr.resouce_type as wo_owner_resouce_type /*工单责任人资源类型 add by jwx528041 20200819*/, l5.item_name as wo_owner_resouce_type_desc /*工单责任人资源类型 add by jwx528041 20200819*/, u4.w3_account as wo_owner_w3_account /*工单责任人w3账号 add by jwx528041 20200819*/, rel.du_tf_rel_enable /*du与活动流关系有效性标识 y:有效 n:失效 add by lwx617215 20210116*/, t.billing_sla /*sla*/, t.billing_milestone /*开票里程碑*/, tf.required_tools, wp.active, gp.plan_code, gp.plan_name, gp.template_plan_id from sdisd.ogg_wo_work_order17_3220 wo inner join sdisd.ogg_wo_progress17_3220 wp on wo.work_order_id = wp.work_order_id left join sdisd.ogg_wo_task_flow_node_za_3220 tfn on wo.template_id = tfn.task_flow_node_id and nvl(wo.wo_version, 0) = case when nvl(wo.wo_version, 0) > 0 then tfn.version else tfn.wo_version end and wo.project_number = tfn.project_number left join sdisd.ogg_sds_activity_t_za_3220 ac on wo.activity_lib_id = ac.activity_id left join sdisd.ogg_sds_task_flow_t_za_3220 tf on tfn.task_flow_id = tf.task_flow_id left join sdisd.ogg_du_release_t_za_3220 du /*enable_flag新增有效du的判断 lwx617215 20210116*/ on wo.du_id = du.du_id left join sdisd.ogg_gcc_plan17_3220 gp --dwx1189869 on wo.plan_id = gp.plan_id and gp.tenant_code = 'RolloutPlan' and gp.parent_plan_id = -1 and gp.enable_flag = 'Y' left join ( select r.du_id, r.task_flow_id, /*du与活动流有效标识*/ case when r.enable_flag = 'Y' and publish_flag = 'P' then 'Y' else 'N' end as du_tf_rel_enable, row_number() over( partition by r.du_id, r.task_flow_id order by r.last_update_date desc ) as rn from sdisd.ogg_rp_du_tf_release18_3220 r ) rel on wo.du_id = rel.du_id and tfn.task_flow_id = rel.task_flow_id and rel.rn = 1 left join sdisd.ogg_tpl_user_t_3220 u1 on wo.created_by = u1.user_id left join sdisd.ogg_tpl_user_t_3220 u2 on wo.last_updated_by = u2.user_id left join sdisd.ogg_tpl_user_t_3220 u3 on wp.dispatcher_user_id = u3.user_id left join sdisd.ogg_sds_activity_gap_t_za_3220 ag on wp.delay_reason_id = ag.activity_gap_id left join sdisd.ogg_tpl_lookup_item_t_3220 l1 on tfn.owner_type = l1.item_code and l1.classify_code = 'SDS_TASK_OWNER_TYPE' and l1.language = 'en_US' left join sdisd.ogg_psc_lookup_item_t_3220 l2 on wp.wo_status = l2.item_code and l2.classify_code = 'WO_STATUS_CODE' and l2.language = 'en_US' left join sdisd.ogg_psc_lookup_item_t_3220 l3 on wp.approve_status = l3.item_code and l3.classify_code = 'WORK_ORDER_APPROVE_STATUS' and l3.language = 'en_US' left join sdisd.ogg_tpl_lookup_item_t_3220 l4 on tfn.delivery_model = l4.item_code and l4.classify_code = 'SDS_TASK_ON_SITE' and l4.language = 'en_US' left join sdisd.ogg_pm_project_tree_node_3220 tn on wo.resource_id = tn.tree_id left join sdisd.ogg_pm_delivery_resource_3220 dr on tn.resource_id = dr.resource_id left join sdisd.ogg_tpl_user_t_3220 u4 on dr.user_id = u4.user_id left join sdisd.ogg_tpl_lookup_item_t_3220 l5 on dr.resouce_type = l5.item_code and l5.classify_code = 'PM_RESOURCE_TYPE' and l5.language = 'zh_CN' left join sdisd.ogg_sds_task_flow_node_za_3220 t on tfn.task_flow_node_id = t.task_flow_node_id where ( wo.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or wp.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or tfn.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or ag.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 )) as t limit 10 3、【性能分析】 优化前SQL语句执行时间达到3600s,超时自动报错,如下图所示: 可以看出(具体verbose执行计划如附件1所示),verbose执行计划中存在过多的NestLoop算子,一般情况下,该算子影响SQL语句执行性能,应该尽可能避免使用。通常可以利用语句 set [global] (enable_index_nestloop off) 来避免执行器走NestLoop算子。但有些场景下,该语句无法保证不使用NestLoop算子。因此,可以从另一方面入手解决这一问题,优化器因为对表估算不准确,故给出NestLoop算子的方案,可以利用tablescan这一hint对表进行全表扫描,以保证执行器走HashJoin算子而非NestLoop算子,从而提高语句执行性能。注意:在使用tablescan这个hint时要保证NestLoop算子涉及到的表都要加上 优化后的SQL语句如下所示: select * from ( select/*+tablescan(wp) tablescan(wo) tablescan(du) tablescan(ac) tablescan(u3) tablescan(u1) tablescan(u2) tablescan(tn) tablescan(dr) tablescan(u4) tablescan(t)*/ wo.work_order_id /*工单id*/, wo.work_order_code /*工单编码*/, wo.work_order_name /*工单名称*/, wo.work_order_level /*工单层级(第一层级(未拆分工单/父工单):1,第二层级(子工单):10)*/, decode(wo.work_order_level,1, '第一层级(未拆分工单/父工单)', 10,'第二层级(子工单)') as work_order_level_desc /*工单层级描述*/, substrb(wo.wo_description, 1, 1000) as wo_description /*工单描述*/, wo.wo_version /*工单版本号*/, wo.wo_lifecycle_status /*生命周期标识:0:正常工单,-1: 已删除*/, wo.business_id /*工单来源业务id*/, wo.business_type /*工单来源业务类型(10:活动流工单 20:手工派单 30:拆单工单 40:临时mos工单 50:ihub工单 60:ipmo工单 70:wbs工单 80:ncs工单 90:hr工单 100:ls工单 默认10)*/, decode( wo.business_type, '10', '活动流工单', '20', '手工派单', '30', '拆单工单', '40', '临时MOS工单', '50', 'ihub工单', '60', 'ipmo工单', '70', 'WBS工单', '80', 'NCS工单', '90', 'HR工单', '100', 'LS工单' ) as business_type_desc /*工单来源业务类型描述*/, wo.parent_activity_id /*父节点活动id*/, wo.activity_lib_id /*活动库活动id*/, wo.activity_type /*作业类型,1wbs,2活动,3里程碑*/, ac.activity_name /*活动名称*/, ac.std_ms_code as standard_ms_code /*标准里程碑编码*/, wo.plan_id /*计划id*/, wo.project_number as proj_num /*项目编码*/, wo.du_id /*交付单元id*/, wo.duration /*工期*/, wo.billing_flag /*开票标识:y-开票*/, wo.na_flag /*na标识*/, wo.inv_flag /*inv标识*/, wo.master_flag /*拆分标示,n:未拆分 ; y:已拆分*/, wo.created_by as created_by_id /*创建人user id*/, u1.lname as created_by /*创建人*/, wo.creation_date /*创建时间*/, wo.last_updated_by as last_updated_by_id /*最后更新人user id*/, u2.lname as last_updated_by /*最后更新人*/, wo.last_update_date /*最后更新时间*/, wp.wo_progress_id /*活动进度id*/, wp.expect_start_date /*预期开始日期*/, wp.expect_end_date /*预期结束日期*/, wp.plan_start_time /*计划开始时间*/, wp.plan_end_time /*计划完成时间*/, wp.actual_start_time /*实际开始时间*/, wp.actual_end_time /*实际完成时间*/, wp.close_time /*活动关闭时间*/, wp.completion_rate /*完工比率(数值如 0.8666)*/, to_char(substr(wp.remark, 1, 333)) as progress_description /*进度备注信息*/, wp.total_value /*总值*/, wp.accumulate_value /*累计值*/, wp.report_time /*值反馈时间*/, wp.total_plan_value /*总计划值*/, wp.ehs_risk /*高危活动类型*/, wp.delay_reason_id /*延迟原因id*/, substrb(ag.description, 1, 1000) as delay_reason_description /*延迟原因描述*/, wp.wo_status /*活动状态 psc_lookup_item_t_3220 classify_code = 'WO_STATUS_CODE'*/, l2.item_name as wo_status_desc /*活动状态描述*/,( case when lengthb(wp.approve_status) = 0 then null else wp.approve_status end ) :: number as approve_status /*审批状态 psc_lookup_item_t_3220 classify_code = 'WORK_ORDER_APPROVE_STATUS'*/, l3.item_name as approve_status_desc /*审批状态描述*/, wp.par_workorder_doc_flag /*父工单是否有交付件(y/n)*/, wp.deliverables_complete /*交付件上传状态 0:不涉及交付件 1:待上传交付件 2:交付件上传中,未上传完9:交付件已上传完*/, wp.revenue_trigger_status /*触发状态(0:未触发过 1:已触发 2:已触发,pc校验触发失败 3:pc触发成功)*/, wp.billing_status /*开票状态(空值:未触发过 1:已开票)*/, wp.frozen_flag /*冻结标识(y/n)*/, wp.mr_frozen_flag /*mr是否冻结站点要货通过更新实施计划刷新字段*/, wp.mr_status /*站点签状态 1未签收,2部分签收,3全部签收,10未签收,20部分签收,30全部签收,40部分超配置签收,50全部超配置签收 完工验状态 p:部分完成,f:全部完成*/, wp.tool_flag /*是否挂工具工单回写(y/n)*/, wp.split_cp_flag /*拆分施工计划标识 y已拆分 n未拆分*/, wp.mos_data_source /*站点签完工验状数据来源*/, wo.template_id /*模板id,例如活动流节点id*/, tfn.task_flow_id /*任务流id*/, tfn.task_flow_node_id /*活动流节点id*/, tfn.revenue_flag /*收入里程碑标识(y/n)*/, tfn.on_site /*是否现场*/, nvl(l1.item_name, tfn.owner_type) as owner_type /*责任方类型 客户/华为/分包商*/, tfn.subcon /*是否分包*/ /*产品域*/,case when wo.enable_flag = 'Y' and wp.enable_flag = 'Y' and wo.wo_lifecycle_status = 0 and nvl(du.enable_flag, 'Y') = 'Y' then 'Y' else 'N' end as enable_flag /*有效标识,y为有效n为失效*/, 'N' as del_flag /*删除标识 y为已删除*/, 3 as data_center_id /*数据中心id*/, tf.task_flow_code /*活动流编码 add by jwx528041 20200408*/, tfn.task_flow_node_code /*任务流节点编码 add by jwx528041 20200408*/, tfn.task_flow_node_name /*任务流节点名称 add by jwx528041 20200408*/, tfn.task_flow_node_type /*任务流节点类型 add by jwx528041 20200408*/, tfn.enable_flag as flow_enable_flag /*活动流有效标识 add by jwx528041 20200408*/, wo.tenant_code /*租户编码 add by jwx528041 20200408*/, tfn.activity_id /*活动流水号 add by jwx528041 20200408*/, tfn.lead_time /*持续时间 add by jwx528041 20200408*/, wo.resource_id as wo_actual_owner_id /*工单实际责任人id update by swx949890 202207*/, wo.resource_name as wo_actual_owner /*工单实际责任人 update by swx949890 202207*/, wo.contractor_id as wo_actual_owner_contr_id /*工单实际责任人分包商id update by swx949890 202207*/, wo.contractor_name as wo_actual_owner_contr_name /*工单实际责任人分包商名称 update by swx949890 202207*/, nvl(l4.item_name, tfn.delivery_model) as delivery_model /*工单交付模式 add by cwx613468 20200711*/, tfn.on_line_site /*是否上站 add by cwx613468 20200711*/, u3.lname as dispatcher_user_name /*调度人 add by cwx613468 20200711*/, tfn.approve_level_qty /*审批总层级 add by jwx528041 20200819*/, tf.task_flow_name /*活动流名称 add by jwx528041 20200819*/, tf.task_flow_type /*活动流类型 add by jwx528041 20200819*/, wp.source_code /*标识actual时间的修改来源,值为mobile标识从手机端回写 add by jwx528041 20200819*/, wp.plan_updated_by /*实际开始时间更新人user id add by jwx528041 20200819*/, wp.plan_update_time /*计划时间更新时间 add by jwx528041 20200819*/, wp.dispatch_time /*调度时间 add by jwx528041 20200819*/, wp.first_actual_update_time /*第一次实际开始时间填入时间 add by jwx528041 20200819*/, wp.first_actual_end_time /*第一次实际结束时间填入时间 add by jwx528041 20200819*/, wp.first_actual_updated_by /*第一次实际时间填入人user id add by jwx528041 20200819*/, wp.actual_start_update_time /*实际开始时间更新日期 add by jwx528041 20200819*/, wp.actual_start_updated_by /*实际开始时间更新人user id add by jwx528041 20200819*/, wp.actual_time_source /*实际完成时间更新来源 add by jwx528041 20200819*/, wp.actual_end_update_time /*实际完成时间更新日期 add by jwx528041 20200819*/, wp.actual_end_updated_by /*实际完成时间更新人user id add by jwx528041 20200819*/, wp.revenue_trigger_failed_msg /*收入触发失败原因 add by jwx528041 20200819*/, ag.souce_type as delay_reason_souce_type /*延迟原因数据来源:1、自定义 2、 add by jwx528041 20200819*/ --,ras.tree_type as wo_owner_tree_type /*工单责任人项目树节点类型tree_type add by jwx528041 20200819*/ , wo.tree_type as wo_owner_tree_type /*工单责任人项目树节点类型tree_type update by swx949890 202207*/, dr.resouce_type as wo_owner_resouce_type /*工单责任人资源类型 add by jwx528041 20200819*/, l5.item_name as wo_owner_resouce_type_desc /*工单责任人资源类型 add by jwx528041 20200819*/, u4.w3_account as wo_owner_w3_account /*工单责任人w3账号 add by jwx528041 20200819*/, rel.du_tf_rel_enable /*du与活动流关系有效性标识 y:有效 n:失效 add by lwx617215 20210116*/, t.billing_sla /*sla*/, t.billing_milestone /*开票里程碑*/, tf.required_tools, wp.active, gp.plan_code, gp.plan_name, gp.template_plan_id from sdisd.ogg_wo_work_order_2_3220 wo inner join sdisd.ogg_wo_progress_2_3220 wp on wo.work_order_id = wp.work_order_id left join sdisd.ogg_wo_task_flow_node_br_3220 tfn on wo.template_id = tfn.task_flow_node_id and nvl(wo.wo_version, 0) = case when nvl(wo.wo_version, 0) > 0 then tfn.version else tfn.wo_version end and wo.project_number = tfn.project_number left join sdisd.ogg_sds_activity_t_br_3220 ac on wo.activity_lib_id = ac.activity_id left join sdisd.ogg_sds_task_flow_t_br_3220 tf on tfn.task_flow_id = tf.task_flow_id left join sdisd.ogg_du_release_t_br_3220 du /*enable_flag新增有效du的判断 lwx617215 20210116*/ on wo.du_id = du.du_id left join sdisd.ogg_gcc_plan_2_3220 gp --dwx1189869 on wo.plan_id = gp.plan_id and gp.tenant_code = 'RolloutPlan' and gp.parent_plan_id = -1 and gp.enable_flag = 'Y' left join ( select r.du_id, r.task_flow_id, /*du与活动流有效标识*/ case when r.enable_flag = 'Y' and publish_flag = 'P' then 'Y' else 'N' end as du_tf_rel_enable, row_number() over( partition by r.du_id, r.task_flow_id order by r.last_update_date desc ) as rn from sdisd.ogg_rp_du_tf_release_3_3220 r ) rel on wo.du_id = rel.du_id and tfn.task_flow_id = rel.task_flow_id and rel.rn = 1 left join sdisd.ogg_tpl_user_t_3220 u1 on wo.created_by = u1.user_id left join sdisd.ogg_tpl_user_t_3220 u2 on wo.last_updated_by = u2.user_id left join sdisd.ogg_tpl_user_t_3220 u3 on wp.dispatcher_user_id = u3.user_id left join sdisd.ogg_sds_activity_gap_t_br_3220 ag on wp.delay_reason_id = ag.activity_gap_id left join sdisd.ogg_tpl_lookup_item_t_3220 l1 on tfn.owner_type = l1.item_code and l1.classify_code = 'SDS_TASK_OWNER_TYPE' and l1.language = 'en_US' left join sdisd.ogg_psc_lookup_item_t_3220 l2 on wp.wo_status = l2.item_code and l2.classify_code = 'WO_STATUS_CODE' and l2.language = 'en_US' left join sdisd.ogg_psc_lookup_item_t_3220 l3 on wp.approve_status = l3.item_code and l3.classify_code = 'WORK_ORDER_APPROVE_STATUS' and l3.language = 'en_US' left join sdisd.ogg_tpl_lookup_item_t_3220 l4 on tfn.delivery_model = l4.item_code and l4.classify_code = 'SDS_TASK_ON_SITE' and l4.language = 'en_US' left join sdisd.ogg_pm_project_tree_node_3220 tn on wo.resource_id = tn.tree_id left join sdisd.ogg_pm_delivery_resource_3220 dr on tn.resource_id = dr.resource_id left join sdisd.ogg_tpl_user_t_3220 u4 on dr.user_id = u4.user_id left join sdisd.ogg_tpl_lookup_item_t_3220 l5 on dr.resouce_type = l5.item_code and l5.classify_code = 'PM_RESOURCE_TYPE' and l5.language = 'zh_CN' left join sdisd.ogg_sds_task_flow_node_br_3220 t on tfn.task_flow_node_id = t.task_flow_node_id where ( wo.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or wp.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or tfn.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or ag.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 ) union all select wo.work_order_id /*工单id*/, wo.work_order_code /*工单编码*/, wo.work_order_name /*工单名称*/, wo.work_order_level /*工单层级(第一层级(未拆分工单/父工单):1,第二层级(子工单):10)*/, decode( wo.work_order_level, 1, '第一层级(未拆分工单/父工单)', 10, '第二层级(子工单)' ) as work_order_level_desc /*工单层级描述*/, substrb(wo.wo_description, 1, 1000) as wo_description /*工单描述*/, wo.wo_version /*工单版本号*/, wo.wo_lifecycle_status /*生命周期标识:0:正常工单,-1: 已删除*/, wo.business_id /*工单来源业务id*/, wo.business_type /*工单来源业务类型(10:活动流工单 20:手工派单 30:拆单工单 40:临时mos工单 50:ihub工单 60:ipmo工单 70:wbs工单 80:ncs工单 90:hr工单 100:ls工单 默认10)*/, decode( wo.business_type, '10', '活动流工单', '20', '手工派单', '30', '拆单工单', '40', '临时MOS工单', '50', 'ihub工单', '60', 'ipmo工单', '70', 'WBS工单', '80', 'NCS工单', '90', 'HR工单', '100', 'LS工单' ) as business_type_desc /*工单来源业务类型描述*/, wo.parent_activity_id /*父节点活动id*/, wo.activity_lib_id /*活动库活动id*/, wo.activity_type /*作业类型,1wbs,2活动,3里程碑*/, ac.activity_name /*活动名称*/, ac.std_ms_code as standard_ms_code /*标准里程碑编码*/, wo.plan_id /*计划id*/, wo.project_number as proj_num /*项目编码*/, wo.du_id /*交付单元id*/, wo.duration /*工期*/, wo.billing_flag /*开票标识:y-开票*/, wo.na_flag /*na标识*/, wo.inv_flag /*inv标识*/, wo.master_flag /*拆分标示,n:未拆分 ; y:已拆分*/, wo.created_by as created_by_id /*创建人user id*/, u1.lname as created_by /*创建人*/, wo.creation_date /*创建时间*/, wo.last_updated_by as last_updated_by_id /*最后更新人user id*/, u2.lname as last_updated_by /*最后更新人*/, wo.last_update_date /*最后更新时间*/, wp.wo_progress_id /*活动进度id*/, wp.expect_start_date /*预期开始日期*/, wp.expect_end_date /*预期结束日期*/, wp.plan_start_time /*计划开始时间*/, wp.plan_end_time /*计划完成时间*/, wp.actual_start_time /*实际开始时间*/, wp.actual_end_time /*实际完成时间*/, wp.close_time /*活动关闭时间*/, wp.completion_rate /*完工比率(数值如 0.8666)*/, to_char(substr(wp.remark, 1, 333)) as progress_description /*进度备注信息*/, wp.total_value /*总值*/, wp.accumulate_value /*累计值*/, wp.report_time /*值反馈时间*/, wp.total_plan_value /*总计划值*/, wp.ehs_risk /*高危活动类型*/, wp.delay_reason_id /*延迟原因id*/, substrb(ag.description, 1, 1000) as delay_reason_description /*延迟原因描述*/, wp.wo_status /*活动状态 psc_lookup_item_t_3220 classify_code = 'WO_STATUS_CODE'*/, l2.item_name as wo_status_desc /*活动状态描述*/,( case when lengthb(wp.approve_status) = 0 then null else wp.approve_status end ) :: number as approve_status /*审批状态 psc_lookup_item_t_3220 classify_code = 'WORK_ORDER_APPROVE_STATUS'*/, l3.item_name as approve_status_desc /*审批状态描述*/, wp.par_workorder_doc_flag /*父工单是否有交付件(y/n)*/, wp.deliverables_complete /*交付件上传状态 0:不涉及交付件 1:待上传交付件 2:交付件上传中,未上传完9:交付件已上传完*/, wp.revenue_trigger_status /*触发状态(0:未触发过 1:已触发 2:已触发,pc校验触发失败 3:pc触发成功)*/, wp.billing_status /*开票状态(空值:未触发过 1:已开票)*/, wp.frozen_flag /*冻结标识(y/n)*/, wp.mr_frozen_flag /*mr是否冻结站点要货通过更新实施计划刷新字段*/, wp.mr_status /*站点签状态 1未签收,2部分签收,3全部签收,10未签收,20部分签收,30全部签收,40部分超配置签收,50全部超配置签收 完工验状态 p:部分完成,f:全部完成*/, wp.tool_flag /*是否挂工具工单回写(y/n)*/, wp.split_cp_flag /*拆分施工计划标识 y已拆分 n未拆分*/, wp.mos_data_source /*站点签完工验状数据来源*/, wo.template_id /*模板id,例如活动流节点id*/, tfn.task_flow_id /*任务流id*/, tfn.task_flow_node_id /*活动流节点id*/, tfn.revenue_flag /*收入里程碑标识(y/n)*/, tfn.on_site /*是否现场*/, nvl(l1.item_name, tfn.owner_type) as owner_type /*责任方类型 客户/华为/分包商*/, tfn.subcon /*是否分包*/ /*产品域*/,case when wo.enable_flag = 'Y' and wp.enable_flag = 'Y' and wo.wo_lifecycle_status = 0 and nvl(du.enable_flag, 'Y') = 'Y' then 'Y' else 'N' end as enable_flag /*有效标识,y为有效n为失效*/, 'N' as del_flag /*删除标识 y为已删除*/, 4 as data_center_id /*数据中心id*/, tf.task_flow_code /*活动流编码 add by jwx528041 20200408*/, tfn.task_flow_node_code /*任务流节点编码 add by jwx528041 20200408*/, tfn.task_flow_node_name /*任务流节点名称 add by jwx528041 20200408*/, tfn.task_flow_node_type /*任务流节点类型 add by jwx528041 20200408*/, tfn.enable_flag as flow_enable_flag /*活动流有效标识 add by jwx528041 20200408*/, wo.tenant_code /*租户编码 add by jwx528041 20200408*/, tfn.activity_id /*活动流水号 add by jwx528041 20200408*/, tfn.lead_time /*持续时间 add by jwx528041 20200408*/, wo.resource_id as wo_actual_owner_id /*工单实际责任人id update by swx949890 202207*/, wo.resource_name as wo_actual_owner /*工单实际责任人 update by swx949890 202207*/, wo.contractor_id as wo_actual_owner_contr_id /*工单实际责任人分包商id update by swx949890 202207*/, wo.contractor_name as wo_actual_owner_contr_name /*工单实际责任人分包商名称 update by swx949890 202207*/, nvl(l4.item_name, tfn.delivery_model) as delivery_model /*工单交付模式 add by cwx613468 20200711*/, tfn.on_line_site /*是否上站 add by cwx613468 20200711*/, u3.lname as dispatcher_user_name /*调度人 add by cwx613468 20200711*/, tfn.approve_level_qty /*审批总层级 add by jwx528041 20200819*/, tf.task_flow_name /*活动流名称 add by jwx528041 20200819*/, tf.task_flow_type /*活动流类型 add by jwx528041 20200819*/, wp.source_code /*标识actual时间的修改来源,值为mobile标识从手机端回写 add by jwx528041 20200819*/, wp.plan_updated_by /*实际开始时间更新人user id add by jwx528041 20200819*/, wp.plan_update_time /*计划时间更新时间 add by jwx528041 20200819*/, wp.dispatch_time /*调度时间 add by jwx528041 20200819*/, wp.first_actual_update_time /*第一次实际开始时间填入时间 add by jwx528041 20200819*/, wp.first_actual_end_time /*第一次实际结束时间填入时间 add by jwx528041 20200819*/, wp.first_actual_updated_by /*第一次实际时间填入人user id add by jwx528041 20200819*/, wp.actual_start_update_time /*实际开始时间更新日期 add by jwx528041 20200819*/, wp.actual_start_updated_by /*实际开始时间更新人user id add by jwx528041 20200819*/, wp.actual_time_source /*实际完成时间更新来源 add by jwx528041 20200819*/, wp.actual_end_update_time /*实际完成时间更新日期 add by jwx528041 20200819*/, wp.actual_end_updated_by /*实际完成时间更新人user id add by jwx528041 20200819*/, wp.revenue_trigger_failed_msg /*收入触发失败原因 add by jwx528041 20200819*/, ag.souce_type as delay_reason_souce_type /*延迟原因数据来源:1、自定义 2、 add by jwx528041 20200819*/ --,ras.tree_type as wo_owner_tree_type /*工单责任人项目树节点类型tree_type add by jwx528041 20200819*/ , wo.tree_type as wo_owner_tree_type /*工单责任人项目树节点类型tree_type update by swx949890 202207*/, dr.resouce_type as wo_owner_resouce_type /*工单责任人资源类型 add by jwx528041 20200819*/, l5.item_name as wo_owner_resouce_type_desc /*工单责任人资源类型 add by jwx528041 20200819*/, u4.w3_account as wo_owner_w3_account /*工单责任人w3账号 add by jwx528041 20200819*/, rel.du_tf_rel_enable /*du与活动流关系有效性标识 y:有效 n:失效 add by lwx617215 20210116*/, t.billing_sla /*sla*/, t.billing_milestone /*开票里程碑*/, tf.required_tools, wp.active, gp.plan_code, gp.plan_name, gp.template_plan_id from sdisd.ogg_wo_work_order17_3220 wo inner join sdisd.ogg_wo_progress17_3220 wp on wo.work_order_id = wp.work_order_id left join sdisd.ogg_wo_task_flow_node_za_3220 tfn on wo.template_id = tfn.task_flow_node_id and nvl(wo.wo_version, 0) = case when nvl(wo.wo_version, 0) > 0 then tfn.version else tfn.wo_version end and wo.project_number = tfn.project_number left join sdisd.ogg_sds_activity_t_za_3220 ac on wo.activity_lib_id = ac.activity_id left join sdisd.ogg_sds_task_flow_t_za_3220 tf on tfn.task_flow_id = tf.task_flow_id left join sdisd.ogg_du_release_t_za_3220 du /*enable_flag新增有效du的判断 lwx617215 20210116*/ on wo.du_id = du.du_id left join sdisd.ogg_gcc_plan17_3220 gp --dwx1189869 on wo.plan_id = gp.plan_id and gp.tenant_code = 'RolloutPlan' and gp.parent_plan_id = -1 and gp.enable_flag = 'Y' left join ( select r.du_id, r.task_flow_id, /*du与活动流有效标识*/ case when r.enable_flag = 'Y' and publish_flag = 'P' then 'Y' else 'N' end as du_tf_rel_enable, row_number() over( partition by r.du_id, r.task_flow_id order by r.last_update_date desc ) as rn from sdisd.ogg_rp_du_tf_release18_3220 r ) rel on wo.du_id = rel.du_id and tfn.task_flow_id = rel.task_flow_id and rel.rn = 1 left join sdisd.ogg_tpl_user_t_3220 u1 on wo.created_by = u1.user_id left join sdisd.ogg_tpl_user_t_3220 u2 on wo.last_updated_by = u2.user_id left join sdisd.ogg_tpl_user_t_3220 u3 on wp.dispatcher_user_id = u3.user_id left join sdisd.ogg_sds_activity_gap_t_za_3220 ag on wp.delay_reason_id = ag.activity_gap_id left join sdisd.ogg_tpl_lookup_item_t_3220 l1 on tfn.owner_type = l1.item_code and l1.classify_code = 'SDS_TASK_OWNER_TYPE' and l1.language = 'en_US' left join sdisd.ogg_psc_lookup_item_t_3220 l2 on wp.wo_status = l2.item_code and l2.classify_code = 'WO_STATUS_CODE' and l2.language = 'en_US' left join sdisd.ogg_psc_lookup_item_t_3220 l3 on wp.approve_status = l3.item_code and l3.classify_code = 'WORK_ORDER_APPROVE_STATUS' and l3.language = 'en_US' left join sdisd.ogg_tpl_lookup_item_t_3220 l4 on tfn.delivery_model = l4.item_code and l4.classify_code = 'SDS_TASK_ON_SITE' and l4.language = 'en_US' left join sdisd.ogg_pm_project_tree_node_3220 tn on wo.resource_id = tn.tree_id left join sdisd.ogg_pm_delivery_resource_3220 dr on tn.resource_id = dr.resource_id left join sdisd.ogg_tpl_user_t_3220 u4 on dr.user_id = u4.user_id left join sdisd.ogg_tpl_lookup_item_t_3220 l5 on dr.resouce_type = l5.item_code and l5.classify_code = 'PM_RESOURCE_TYPE' and l5.language = 'zh_CN' left join sdisd.ogg_sds_task_flow_node_za_3220 t on tfn.task_flow_node_id = t.task_flow_node_id where ( wo.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or wp.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or tfn.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 or ag.cdc_create_date >= to_timestamp('20231021', 'yyyy-mm-dd hh24:mi:ss.ff') -1 / 24 / 60 )) as t limit 10 如下图所示,该语句执行时间降为27s+,提升了语句的执行性能。 具体的performance执行计划如附件2所示。 附件:tablescan-performance.txt 附件:tablescan-verbose.txt 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

带你走进数仓大集群内幕丨详解关于作业hang及残留问题定位

本文分享自华为云社区《【带你走进DWS大集群内幕】大集群通信:作业hang、残留问题定位》,作者: 雨落天穹丶。 前言: 测试过程中,我们会遇到这样一种情况,我的作业都执行很久了,为啥还不结束,是不是作业hang掉了? 或者说,明明看到CN上的作业都没了,为什么通过全局视图发现DN上还有作业在执行而没有退出,这是不是有问题啊?那么就带着这样的疑问点来阅读本篇分析问题的方式方法,给初学者一点定位思路。 【通信系统视图】 pgxc_comm_send_stream :展示所有DN上的通信库发送流状态。 pgxc_comm_recv_stream :展示所有DN上的通信库接收流状态。 pg_thread_wait_status :通过PG_THREAD_WAIT_STATUS视图可以检测当前实例中工作线程(backend thread)以及辅助线程(auxiliary thread)的阻塞等待情况。 pgxc_thread_wait_status :通过CN节点查看PGXC_THREAD_WAIT_STATUS视图,可以查看集群全局各个节点上所有SQL语句产生的线程之间的调用层次关系,以及各个线程的阻塞等待状态,从而更容易定位进程停止响应问题以及类似现象的原因。 pg_stat_activity :PG_STAT_ACTIVITY视图显示和当前用户查询相关的信息。若有管理员权限或预置角色权限可以显示和所有用户查询相关的信息。 pgxc_stat_activity :PGXC_STAT_ACTIVITY视图显示当前集群下所有CN的当前用户查询相关的信息。 单实例查询:可直连DN/CN 通过此条SQL进行DN/CN上活跃会话访问查询。 select datname,usename,pid,query_id,query_start,query from pg_stat_activity where state='active' order by query_start; 全局查询: 获取所有的CN上当前的作业执行情况 select coorname,datname,usename,pid,query_id,query_start,query from pgxc_stat_activity where state='active' order by query_start; 【发现问题】1. 集群作业停止一段时间后,发现集群DN还存在比较高的压力CPU,查询活跃会话视图,观察是否存在未执行完的作业,或者只是主备DN数据同步(同步属于正常情况,但持续时间过长,就要分析DN HA catchup 机制是否正常) 例如,如下查询到的结果可以观察到,当前时间19:38,作业已经退出很久了,发现在linux0802集群的6606端口DN上还存在16:49分的作业还在执行,且通过作业分析发现,该作业是简单的 create table as select * 场景 ,正常测试返回结果在10s之内,那当前作业还存在于此DN上处于active执行状态,就显得很不正常。 那我们就针对这条存在的活跃会话进行分析。 【分析问题】通过全局会话等待视图观察这个作业当前的执行状态 获取上图中的执行query的 query_id 通过query_id查询作业执行状态: select * from pgxc_thread_wait_status where query_id='219269006857675600' order by 1,2; -- 通过上面查出query_id分析 查询结果发现所有的线程都是在获取stream连接状态,且已经不存在与CN的连接信息 那我们找一个DN节点查看堆栈:选取 dn_6007_6008 lwtid = 2238755 通过cm_ctl query -Cv 查找dn 6007 所在的物理节点环,观察当前主DN是 6007 还是 6008(一般业务连接都是主DN,如果发生主备切换,那么我们查看堆栈就要到6008节点[当前的主DN节点]) 连接到到所在物理节点, 用gstack 2238755 (多执行几遍,如果栈内容一直不变,可能就是hang,需要分析位,如果栈一直在变可能是在工作,确实是sql执行慢,可联系开发帮忙确认分析是不是正常堆栈) 【问题初步结论】初步分析堆栈代码属于通信相关,找对应的责任田定位问题。 【发现问题】2. 集群作业停止一段时间后,发现集群CN上还存在未执行完的作业,但是DN上的作业连接已经全部退出 还是通过上面的例子中的查询活跃会话的语句,分析找到对应的query id。 通过线程等待视图查询当前作业执行情况。 select * from pgxc_thread_wait_status where query_id='237283405371509247' order by 1,2; 上图中当前只剩下CN线程,DN线程全部退出,那么这种情况就需要去分析CN对应等待状态中的dn 6301实例上的对应远端线程在干什么 通过通信pooler视图查询对应的remote node 线程号: select * from pg_pooler_status where pid=140069915589224; 然后用线程等待视图查询:select * from pgxc_thread_wait_status where pid = 140704341249976 order by 1,2; 可以按上面第一种类型的查询DN节点操作 访问dn_6301_6302 主DN 所在的物理机器节点 用 gstack 39625 观察堆栈。 【问题初步结论】 初步判断是DN在等主备同步呢,此时DN上的query id清0了,用query_id匹配不到,后续联系对应责任田分析。 点击关注,第一时间了解华为云新鲜技术~

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册