首页 文章 精选 留言 我的

精选列表

搜索[内核],共10002篇文章
优秀的个人博客,低调大师

置换业务架构内核,为IT和业务搭桥

# 开篇 企业架构的理论传入中国已有二十多年,TOGAF、ArchiMate、BIZBOK轮番登场,学华为的实践方法也一度成为标杆。但一个尴尬的事实是:大多数企业的架构资产做完了就锁进柜子,业务部门不看,技术团队不用,IT建设照旧我行我素。 问题出在哪里?本文认为,根源在业务架构的核心要素——“能力”立不住。它把沟通的枢纽放在"能力"上,而能力恰恰是业务人员无法在头脑中映射的概念。枢纽松动,整个架构就失去了业务与技术之间的桥梁作用。 本文在梳理业务架构困境的基础上,提出以运营模式图替代能力地图,作为业务架构的核心;并以一家水务公司为例,说明运营模式图如何标注出IT规划视图,进而推导应用架构和数据架构。 # 一、为什么说业务架构的核心要素“能力”没用? 企业架构的一系列架构概念、方法,最早可以追溯到1960年代IBM的IT系统规划方法,目的就在于解决IT与业务脱节的问题。这其中,业务架构在企业架构中居于核心地位,对上承接企业业务战略,对下推导出应用架构、数据架构、技术架构。 ![](https://developer.qcloudimg.com/http-save/audit-12626904/2ac66ba7e24dfea1900c097ad4456ea8.png) 然而,在实践中企业架构“业务部门看不懂、技术团队看不上”。陈果(波士顿咨询董事总经理)在《企业架构的中国实践:四大流派与本质回归》说,国内企业架构实践里有四大流派,其中"文档工程派"的产物被概括为"业务看不懂、技术看不上";另一支学华为的派别把能力层层细化,被批评"忘了初心是让决策者看清全局",细化到最后谁也读不下去。 问题在哪里?追根溯源在业务架构的核心要素“能力”立不住。 企业架构的三大权威来源包括TOGAF(The Open Group Architecture Framework,开放群组架构框架)、ArchiMate、BIZBOK(Business Architecture Body of Knowledge,业务架构知识体系),它们都定义业务架构的核心要素包括能力、价值流、组织、信息,其中能力在业务架构的四大核心要素中居于枢纽地位。 ![](https://developer.qcloudimg.com/http-save/audit-12626904/225aafb11d08d4518b9ca8ed5629f8b5.png) 恰恰是能力,业务架构的核心要素,是实践中业务部门和IT团队难以对话的要素。因为能力不是一个实体要素,IT人员头脑中映射的是IT模块,业务人员头脑中却无所映射、似有似无。当IT人员和业务人员沟通这样或那样的能力时,业务人员多数时候只能茫然点头。 现实中,IT人员和业务人员沟通的是单据、数据、职责、流程。 # 二、运营模式是什么? BIZBOK在其2017年7月颁布的v6.0版本中首次引入“运营模式”的讨论,2022年5月颁布的v11.0版本基本定形,沿用至今。它认为“任何战略规划若没有同时识别并定义出支撑性的运营模式,以交付目标业务模式所期望的价值,就很可能是不完整的”。运营模式和战备、业务模式(亦可称为商业模式)、业务架构之间的关系如下图所示。 ![](https://developer.qcloudimg.com/http-save/audit-12626904/46bd33c9957df264349c0d41cf0e970c.png) 然而,它又认为“运营模式的构成要素尚无公认定义,一个通用描述是:运营模式提供了「一种关于组织如何跨一系列领域运作以完成其职能的抽象表征」。至于运营模式的核心要素(构件)应当是什么、在真实企业中又该如何表达,同样缺乏共识”。 那么,运营模式到底是什么?笔者依据长期企业运营咨询实践,认为:运营模式是企业内部不同部门基于价值流的协同运作方式,它应以战略为引导、以卓越绩效为目标,体现PDCA方式的持续改进。如下图所示: ![](https://developer.qcloudimg.com/http-save/audit-12626904/943c7a316f7fc6772f28ca0efaf0e9ee.png) 由于运营模式图纵向体现组织分工、横向体现价值流、内容体现部门职能及交接流程,业务人员看到的自己的工作,IT人员脑中映射的是应用模块、数据流,因而是双方沟通的桥梁;图中融合了业务架构中的价值流、组织、信息等核心要素,可以标注IT规划视图,推导应用架构、数据架构,因而可以替代能力地图,成为业务架构的核心。 ![](https://developer.qcloudimg.com/http-save/audit-12626904/c8280b4412c0d2ab86031a09a0e944f9.png) # 三、应用运营模式图标注IT规划视图,推导应用架构、数据架构 运营模式图作为业务人员和IT人员的沟通桥梁,可以在此基础上标注出IT规划视图,进而推导应用架构、数据架构。 ## (一)应用运营模式图标注IT规划视图 在运营模式图上标出现有IT系统,就能根据运营需要,规划出未来的整体系统架构,根据轻重缓急确定IT规划。 ![](https://developer.qcloudimg.com/http-save/audit-12626904/40b626ca9dcfef725be9a3988a07624c.png) ### 第一步:在图3上“贴标签”(现状梳理 / AS-IS) 让业务人员和IT人员一起,在运营模式图的每一个黄框(业务动作)上,标注“目前靠什么支撑”。 **已建系统:**比如“抄表收费”旁贴上【营收系统】,“会计处理”旁贴上【ERP财务】,“采购供应”旁贴上【进销存】。 无系统(空白/手工):比如“客户报装”旁边可能只写了【Excel/纸质登记】,“水表安装”旁边是【电话派单】,“绩效监测”旁边是【人工拼表】。 **痛点标记:**用红圈标出“断点”。比如“客服中心”到“水表管理部”的绿箭头上,画一个断裂符号(说明数据靠人工传递,极易出错)。 ### 第二步:进行“差距分析”(找痛点 / Gap Analysis) 盯着这张贴满标签的图,业务和IT就能开展最高效的对话: **纵向看(部门墙)**:为什么客服中心有客户数据,但营销部收不到?因为系统没打通。 **横向看(流程断点)**:为什么“管网建设”到“管网供水”的物理流没问题,但信息流总是滞后?因为没有物联网(IoT)和GIS系统。 **看反馈(红色箭头)**:所有的“绩效监测”都是人工做,说明没有统一的【数据中台/BI系统】。业务人员此时会强烈感受到:“我们月底为了报这些绩效指标,天天加班算Excel,根本没法指导前端改进。” ### 第三步:推导“未来整体系统架构”(规划蓝图 / TO-BE) 根据运营需要,把图上的黄框和断点,转化为系统建设的需求,直接推导出目标架构: **横线打通:**为了填补“客户报装”到“水表安装”的断点,需要规划【CRM系统】和【工单调度系统】。 **纵向集成:**为了让“财务绩效”能拿到“营销收费”和“采购供应”的数据,需要规划【ERP系统】与【营收系统】、【采购系统】的集成接口。 **底层支撑:**为了自动生成“绩效监测”,需要规划【数据仓库】或【数据中台】。 **最终产出:**一张“未来整体应用架构图”。这张图不是凭空画出来的,而是从运营模式图上的“痛点”直接生长出来的。 ### 第四步:根据“轻重缓急”确定IT规划(实施路线图 / Roadmap) 系统的建设不能一把抓。什么是“轻重缓急”?标准绝不是“技术先不先进”,而是“对运营模式的支撑程度”。 **急(一期):**直接影响客户体验和核心营收的断点。比如“客服报装到水表安装”的工单系统,以及“抄表收费到会计处理”的业财一体化。这能最快见效。 **重(二期):**影响企业核心资产和效率的。比如“管网供水”的GIS/SCADA系统,以及支撑决策的“绩效监测”BI系统。 **缓(三期):**属于锦上添花的辅助支持。比如“人力规划”、“文化建设”等模块的系统化。 ## (二)应用运营模式图推导应用架构 基于运营模式图推导应用架构,本质上是一个“业务动作向系统功能直译”的过程。这不需要中间那个抽象的“业务架构”来转译,而是直接把运营模式图上的黄框(活动)、泳道(部门)和箭头(数据/信息流),转化为应用模块、系统边界和集成接口。 具体来说,可以按照以下四步法进行严格的推导: ### 第一步:黄框映射模块(定功能) 运营模式图上的每一个黄框,代表一个具体的业务动作(如“客户报装”、“水表安装”、“抄表收费”)。将这些动作按业务领域进行聚类,直接推导出应用系统的功能模块。 客户中心/营销部的“客户报装、抄表收费” → 推导出【CRM系统】和【计费营收系统】的功能模块。 水表管理部/安装公司的“水表安装、管网建设” → 推导出【工程项目管理系统】和【移动工单系统】的功能模块。 水厂/生产部的“制水、水质监测” → 推导出【SCADA系统】(数据采集与监视控制)和【MES系统】(生产执行系统)的功能模块。 物资部的“采购计划、采购供应” → 推导出【SRM系统】(供应商关系管理)或【ERP采购模块】。 财务部的“会计处理、资产管理” → 推导出【ERP财务模块】或【EAM资产管理系统】。 企业发展部的“绩效监测、经营分析改进” → 推导出【BI系统】或【数据中台】的决策分析模块。 推导逻辑:业务动作 → 业务能力 → 应用系统功能。不要凭空想象系统,系统的功能完全来自业务动作的需要。 ### 第二步:箭头映射集成(定接口) 运营模式图上的箭头,代表数据的流转和业务的协同。应用架构中最难的“系统集成”,完全可以通过这些箭头直接推导出来。 绿色箭头(信息流):“客户报装”流向“水表安装”,意味着【CRM系统】需要向【工单系统】推送客户信息和报装单。 黑色箭头(物理流/指令流):“管网建设”流向“管网供水”,意味着【工程管理系统】竣工后,需要将管网资产数据移交给【GIS系统】和【SCADA系统】。 红色箭头(反馈流):所有绩效监测指向各部门,意味着【各业务系统】需要向【数据中台/BI系统】抽取数据,进行绩效计算。 跨泳道的连线:“抄表收费”流向“会计处理”,意味着【计费营收系统】必须与【ERP财务模块】打通,实现“业财一体化”,自动生成凭证。 推导逻辑:业务流断点 → 系统集成需求。图上有多少条跨越部门的线,应用架构上就需要多少个接口(API或消息队列)。 ### 第三步:泳道映射边界与权限(定架构层级) 运营模式图的纵向泳道(部门),决定了应用系统的权限边界、数据主责和组织架构映射。 前台(交互层):面向客户和一线员工的系统,如客服的【报装门户】、安装工人的【移动App】。 中台(业务能力层):支撑跨部门协作的核心系统,如【工单调度系统】、【GIS管网系统】、【计费系统】。这些系统往往跨越多个泳道,是架构的核心。 后台(核心资源与决策层):如【ERP财务系统】、【人力资源系统】、【BI数据平台】。 推导逻辑:部门职责 → 系统权限矩阵 → 应用分层架构。泳道图天然划清了“谁录入、谁修改、谁查看”的边界,避免了应用架构中常见的“数据主责不清”。 ### 第四步:痛点映射建设优先级(定路线图) 应用架构不是一堆系统的堆砌,而是一张有演进路线的蓝图。运营模式图上的“断点”和“瓶颈”,直接决定了IT规划的轻重缓急。 **急(一期)**:如果“客户报装”到“水表安装”目前全靠电话和Excel,效率极低,这就是核心痛点。一期应用架构的重点就是建设【CRM】+【移动工单系统】,打通这条绿箭头。 **重(二期)**:如果“制水”和“管网供水”数据不互通,导致漏损率高,二期重点就是建设【SCADA】+【GIS系统】,支撑“管网绩效监测”这个红色反馈。 **缓(三期)**:如“人力资源规划”、“文化建设实施”等辅助流程,可以在核心业务系统跑通后,再逐步接入【HR系统】和【协同办公系统】。 📊 最终产出:目标应用架构图 ![](https://developer.qcloudimg.com/http-save/audit-12626904/0d6aa0878e1140a63fe5ed043396ddb1.png) 经过以上四步推导,你可以画出一张清晰的目标应用架构图(通常分为四层): **用户与渠道层:**客服门户、移动抄表App、领导驾驶舱。 **业务运营层(核心)**:CRM、工单调度、计费营收、工程管理、SCADA、SRM。 **数据与集成层:**数据中台、API网关、ESB(企业服务总线)。 **基础平台层:**ERP(财务/资产/HR)、云基础设施。 ## (三)基于运营模式图推导数据架构 基于运营模式图推导数据架构,本质上是一个“业务活动数据化”的过程。具体可以按照以下四步法严丝合缝地推导: ### 第一步:从“黄框(业务活动)”推导“数据实体”(定核心数据资产) 运营模式图上的每一个黄框,都代表着一次数据的产生(Create)、更新(Update)或消费(Read)。这些动作直接定义了企业需要管理的数据实体。 客服中心 - “客户报装” → 产生【客户主数据】、【报装工单数据】。 水表管理部 - “水表安装” → 产生/更新【水表资产数据】、【安装工单数据】。 安装公司 - “管网建设” → 产生【管网资产数据】、【工程进度数据】。 水厂/水质检测站 - “制水/水质监测” → 产生【生产运行数据】、【水质检测数据】。 营销部 - “抄表收费” → 产生【抄表读数数据】、【营收账单数据】。 财务部 - “会计处理” → 产生【财务凭证数据】、【资金流水数据】。 推导逻辑:业务动作 → 数据实体。不要凭空画ER图,每一个数据实体都必须能在图上找到它产生的源头(黄框)。 ### 第二步:从“箭头(数据流向)”推导“数据流图”(定数据集成与共享) 运营模式图上的箭头,就是数据架构中最宝贵的“数据血缘(Data Lineage)”和“数据流”。数据架构的核心任务,就是让这些箭头顺畅、自动化地流转。 绿色箭头(信息流):“客户报装”流向“水表安装”,意味着【客户主数据】和【报装工单数据】需要从客服系统流向工单系统。 黑色箭头(物理流/指令流):“管网建设”流向“管网供水”,意味着【管网资产数据】竣工后,需要移交给管网管理部和调度中心。 红色箭头(反馈流):“抄表收费”流向“营销绩效监测”,意味着【营收数据】需要流向数据分析平台,计算“水费回收率”。 推导逻辑:业务流断点 → 数据集成需求。数据架构师不需要再去问“数据怎么共享”,图上的箭头就是数据流图(DFD)的雏形。 ### 第三步:从“泳道(部门)”推导“数据主责与治理体系”(定数据Owner) 数据架构中最难、最扯皮的就是“数据主责”(谁产生、谁维护、谁负责质量)。运营模式图的纵向泳道(部门),天然解决了这个问题。 数据产生在哪个泳道,该部门就是数据的“源Owner”。例如,“客户主数据”产生在客服中心,客服中心就是客户数据的主责部门。 数据流向哪个泳道,该部门就是数据的“消费方”。例如,营销部消费客户数据,财务部消费营收数据。 基于此,可以制定数据质量规则:客服中心录入的客户信息必须完整准确,否则营销部无法抄表收费,财务部无法做账。 推导逻辑:部门职责 → 数据主责 → 数据标准与质量规则。这避免了IT部门“既管数据、又背数据质量锅”的尴尬。 ### 第四步:从“绩效监测(红箭头)”推导“数据仓库与BI指标体系”(定分析架构) 运营模式图右侧最醒目的部分,就是大量的红色箭头指向“绩效监测”和“经营分析改进”。这是数据架构中“分析型数据”的直接来源。 财务绩效、营销绩效、管网绩效、制水绩效、采购绩效、人力资源绩效 → 直接推导出企业的【指标体系】和【KPI字典】。 为了自动计算这些跨部门的绩效,不能靠人工拼Excel,必须规划【数据仓库(DW)】或【数据中台】,以及【BI报表系统】。 红色箭头意味着“反馈闭环”,意味着数据架构不仅要支持“看”,还要支持“改”(即通过分析结果反哺前端流程优化)。 推导逻辑:绩效反馈节点 → 指标体系 → 数据仓库/BI架构。没有这张图上的红箭头,企业上马“数据中台”往往找不到业务价值,最后变成一个大号的报表库。 📊 最终产出:目标数据架构图(由运营模式图直接生成) 经过这四步推导,可以直接得出一份清晰的数据架构蓝图: ![](https://developer.qcloudimg.com/http-save/audit-12626904/ed5185eb7c9e1e050ffd13f45829f13b.png) **主数据层(MDM):**客户主数据、水表资产主数据、管网主数据、供应商主数据、科目主数据。 **业务数据层(OLTP):**分布在CRM、工单系统、计费系统、ERP、SCADA中,支撑日常运营。 **数据集成层(API/ETL)**:对应图上的绿/黑箭头,负责跨系统、跨部门的数据流转。 **分析数据层(DW/BI)**:对应图上的红箭头和绩效监测,负责指标计算和决策支持。 # 【结语】 业务架构把企业架构的枢纽押在"能力"这个业务人员无法感知的概念上,这是它难以落地的根源;运营模式以部门协同、单据流转、绩效反馈为骨架,业务人员和IT人员能读同一张图、说同一套话;有了这张图,IT规划、应用架构、数据架构都不再是悬空的设计,而是从运营痛点里长出来的答案。

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

openGauss内核分析-统计信息与行数估计

目录 统计信息 行数估计 SQL引擎执行查询主要经历了词法语法解析、查询重写、查询规划和计划执行等步骤。其中,在查询规划过程中,为了生成可执行的最优计划,首先要生成路径,而由于路径存在多样性,因此需要对路径进行淘汰选择。目前优化器进行路径的选择主要是基于估算的代价,因此这种优化器也被称为基于代价的优化器(Cost Based Optimization,CBO)。相对于逻辑优化,这种优化方法是物理优化:根据数据的分布(统计信息)情况来对查询执行路径进行评估,从可选的路径中选择一个执行代价最小的路径进行执行,例如是否选择索引SeqScan vs. IndexScan,选择哪个索引,两表关联选择什么样的连接顺序,选择怎样的具体算法等。 在代价估算时,需要使用基表或连接表的行数,而在很多时候,优化器无法获得准确的行数值,因此需要对行数进行估算(Cardinality Estimation),然后再计算代价。 统计信息 统计信息是物理优化的依据,来源于表信息的统计。其中描述基表数据的特征包括唯一值、MCV(Most Common Value)值等,用于行数估算。 Table-Level表级别统计信息,存储在系统表pg_class。 relptuples总元组数:描述表对应的元组数。 relpages总页面数:描述表对应的磁盘页数。 Column-Level列级别统计信息,存储在系统表pg_statistics,也可以使用视图pg_stats查看数据。 Starelid:表的oid。 Staattnum:表属性编号。 stadistinct:用于描述字段里唯一的非 NULL 数据值的数目,一般用于估算集合分组之后的大小,Join结果集大小。 stanullfrac:用于描述当前列中NULL值在总数中的占比。 属性组{stakind1, stanumbers1, stavalues1}构成PG_STATISTIC表的一个卡槽,在PG_STATISTIC表中有5个卡槽。一般情况下,第一个卡槽存储MCV(Most Common Value)信息:描述出现频率大于一定百分比的值的集合,按照出现的频率进行排序,通常用于表征哪些值上出现了倾斜。第二个卡槽存储Histogram直方图信息,描述除了NULL值、MCV值以外的值的分布情况,一般用于估算选择率。 以MCV卡槽为例属性“stakind1”标识卡槽类型为MCV,其中“1”为“STATISTIC_KIND_MCV”的枚举值;属性stanumbers1与属性stavalues1记录MCV的具体内容,其中stavalues1记录key值,stanumbers1记录key对应的频次。 系统表pg_statistics的定义在文件pg_statistic.h中。 #define STATISTIC_KIND_MCV 1 #define STATISTIC_KIND_HISTOGRAM 2 #define STATISTIC_KIND_CORRELATION 3 #define STATISTIC_KIND_MCELEM 4 #define STATISTIC_KIND_DECHIST 5 统计信息通过analyze命令获得。 表tt的oid为40960,有10000行数据占用345个pages页。第1列unique1的分布情况可以从直方图信息获取,直方图有100个区间,并且没有空值和MCV。第16列string4的分布情况可以通过MCV信息获取,这一列有4个distinct值”AAAAxx” ,”HHHHxx” , “OOOOxx” , “VVVVxx” ,4个值的分布频次都有0.25。 行数估计 行数估算是代价估算的基础,来源于基表统计信息的推算,估算基表baserel、Join中间结果集joinrel、Aggregation中结果集大小,为代价估算做准备。 SQL查询常常带有where约束(过滤条件),比如SELECT * FROM tt WHERE string4 = 'AAAAxx'。知道了约束条件的选择率,也就是知道了通过扫描路径要扫描出来的结果所占的比例或者通过连接操作所获得的元组所占的比例,通过这个比例就可以推算出中间结果和最终结果的数量,进而使用这些数量来计算代价。 这里重点分析基表的简单查询——基于OpExpr类型的选择率计算,处理函数在clause_selectivity。如果是过滤条件就调用restriction_selectivity函数来获得OpExpr表达式的选择率,如果是连接条件则调用join_selectivity函数来获得选择率。 SELECT * FROM tt WHERE string4 = 'AAAAxx'为过滤条件,调用restriction_selectivity进行选择率估算。 restriction_selectivity函数识别出string4 = 'AAAAxx'是形如Var = Const的等值约束,操作符的约束选择性计算函数存储在系统表PG_OPERATOR,opno = 93对应的选择率计算函数为eqsel,通过eqsel函数调用var_eq_const函数进行选择率估算。在该过程中,var_eq_const函数会读取PG_STATISTIC表中string4列分布信息,并利用MCV信息直接返回选择率为0.25。 函数set_baserel_size_estimates计算估计行数。 函数调用关系:standard_planner-> subquery_planner-> grouping_planner-> query_planner-> make_one_rel-> set_base_rel_sizes-> set_rel_size-> set_plain_rel_size-> set_baserel_size_estimates-> clauselist_selectivity-> clause_selectivity-> restriction_selectivity-> OidFunctionCall4Coll-> eqsel->var_eq_const

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

从内核代码了解SQL如何解析

目录 词法分析Lexical Analysis 语法分析Syntax Analysis 语义分析Semantic Analysis 在传统数据库中SQL引擎一般指对用户输入的SQL语句进行解析、优化的软件模块。 SQL的解析过程主要分为: 词法分析Lexical Analysis:将用户输入的SQL语句拆解成单词(Token)序列,并识别出关键字、标识、常量等。 语法分析Syntax Analysis:分析器对词法分析器解析出来的单词(Token)序列在语法上是否满足SQL语法规则。 语义分析Semantic Analysis:语义分析是SQL解析过程的一个逻辑阶段,主要任务是在语法正确的基础上进行上下文有关性质的审查,在SQL解析过程中该阶段完成表名、操作符、类型等元素的合法性判断,同时检测语义上的二义性。 openGauss在pg_parse_query中调用raw_parser函数对用户输入的SQL命令进行词法分析和语法分析,生成语法树添加到链表parsetree_list中。完成语法分析后,对于parsetree_list中的每一颗语法树parsetree,会调用parse_analyze函数进行语义分析,根据SQL命令的不同,执行对应的入口函数,最终生成查询树。 词法分析Lexical Analysis openGauss使用flex工具进行词法分析。flex工具通过对已经定义好的词法文件进行编译,生成词法分析的代码。词法文件是scan.l,它根据SQL语言标准对SQL语言中的关键字、标识符、操作符、常量、终结符进行了定义和识别。在kwlist.h中定义了大量的关键字,按照字母的顺序排列,方便在查找关键字时通过二分法进行查找。在scan.l中处理“标识符”时,会到关键字列表中进行匹配,如果一个标识符匹配到关键字,则认为是关键字,否则才是标识符,即关键字优先. 以“select a, b from item”为例说明词法分析结果。 名称 词性 内容 说明 关键字 keyword SELECT,FROM 如SELECT/FROM/WHERE等,对大小写不敏感 标识符 IDENT a,b,item 用户自己定义的名字、常量名、变量名和过程名,若无括号修饰则对大小写不敏感 语法分析Syntax Analysis openGauss中定义了bison工具能够识别的语法文件gram.y,根据SQL语言的不同定义了一系列表达Statement的结构体(这些结构体通常以Stmt作为命名后缀),用来保存语法分析结果。以SELECT查询为例,它对应的Statement结构体如下。 typedef struct SelectStmt { NodeTag type; List *distinctClause; /* NULL, list of DISTINCT ON exprs, or * lcons(NIL,NIL) for all (SELECT DISTINCT) */ IntoClause *intoClause; /* target for SELECT INTO */ List *targetList; /* the target list (of ResTarget) */ List *fromClause; /* the FROM clause */ Node *whereClause; /* WHERE qualification */ List *groupClause; /* GROUP BY clauses */ Node *havingClause; /* HAVING conditional-expression */ List *windowClause; /* WINDOW window_name AS (...), ... */ WithClause *withClause; /* WITH clause */ List *valuesLists; /* untransformed list of expression lists */ List *sortClause; /* sort clause (a list of SortBy's) */ Node *limitOffset; /* # of result tuples to skip */ Node *limitCount; /* # of result tuples to return */ …… } SelectStmt; 这个结构体可以看作一个多叉树,每个叶子节点都表达了SELECT查询语句中的一个语法结构,对应到gram.y中,它会有一个SelectStmt。代码如下: 从simple_select语法分析结构可以看出,一条简单的查询语句由以下子句组成:去除行重复的distinctClause、目标属性targetList、SELECT INTO子句intoClause、FROM子句fromClause、WHERE子句whereClause、GROUP BY子句groupClause、HAVING子句havingClause、窗口子句windowClause和plan_hint子句。在成功匹配simple_select语法结构后,将会创建一个Statement结构体,将各个子句进行相应的赋值。对simple_select而言,目标属性、FROM子句、WHERE子句是最重要的组成部分。SelectStmt与其他结构体的关系如下: 下面以“select a, b from item”为例说明简单select语句的解析过程,函数exec_simple_query调用pg_parse_query执行解析,解析树中只有一个元素。 (gdb) p *parsetree_list $47 = {type = T_List, length = 1, head = 0x7f5ff986c8f0, tail = 0x7f5ff986c8f0} List中的节点类型为T_SelectStmt (gdb) p *(Node *)(parsetree_list->head.data->ptr_value) $45 = {type = T_SelectStmt} 查看SelectStmt结构体,targetList 和fromClause非空 (gdb) set $stmt = (SelectStmt *)(parsetree_list->head.data->ptr_value) (gdb) p *$stmt $50 = {type = T_SelectStmt, distinctClause = 0x0, intoClause = 0x0, targetList = 0x7f5ffa43d588, fromClause = 0x7f5ff986c888, startWithClause = 0x0, whereClause = 0x0, groupClause = 0x0, havingClause = 0x0, windowClause = 0x0, withClause = 0x0, valuesLists = 0x0, sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, lockingClause = 0x0, hintState = 0x0, op = SETOP_NONE, all = false, larg = 0x0, rarg = 0x0, hasPlus = false} 查看SelectStmt的targetlist,有两个ResTarget (gdb) p *($stmt->targetList) $55 = {type = T_List, length = 2, head = 0x7f5ffa43d540, tail = 0x7f5ffa43d800} (gdb) p *(Node *)($stmt->targetList->head.data->ptr_value) $57 = {type = T_ResTarget} (gdb) set $restarget1=(ResTarget *)($stmt->targetList->head.data->ptr_value) (gdb) p *$restarget1 $60 = {type = T_ResTarget, name = 0x0, indirection = 0x0, val = 0x7f5ffa43d378, location = 7} (gdb) p *$restarget1->val $63 = {type = T_ColumnRef} (gdb) p *(ColumnRef *)$restarget1->val $64 = {type = T_ColumnRef, fields = 0x7f5ffa43d470, prior = false, indnum = 0, location = 7} (gdb) p *((ColumnRef *)$restarget1->val)->fields $66 = {type = T_List, length = 1, head = 0x7f5ffa43d428, tail = 0x7f5ffa43d428} (gdb) p *(Node *)(((ColumnRef *)$restarget1->val)->fields)->head.data->ptr_value $67 = {type = T_String} (gdb) p *(Value *)(((ColumnRef *)$restarget1->val)->fields)->head.data->ptr_value $77 = {type = T_String, val = {ival = 140050197369648, str = 0x7f5ffa43d330 "a"}} (gdb) set $restarget2=(ResTarget *)($stmt->targetList->tail.data->ptr_value) (gdb) p *$restarget2 $89 = {type = T_ResTarget, name = 0x0, indirection = 0x0, val = 0x7f5ffa43d638, location = 10} (gdb) p *$restarget2->val $90 = {type = T_ColumnRef} (gdb) p *(ColumnRef *)$restarget2->val $91 = {type = T_ColumnRef, fields = 0x7f5ffa43d730, prior = false, indnum = 0, location = 10} (gdb) p *((ColumnRef *)$restarget2->val)->fields $92 = {type = T_List, length = 1, head = 0x7f5ffa43d6e8, tail = 0x7f5ffa43d6e8} (gdb) p *(Node *)(((ColumnRef *)$restarget2->val)->fields)->head.data->ptr_value $93 = {type = T_String} (gdb) p *(Value *)(((ColumnRef *)$restarget2->val)->fields)->head.data->ptr_value $94 = {type = T_String, val = {ival = 140050197370352, str = 0x7f5ffa43d5f0 "b"} 查看SelectStmt的fromClause,有一个RangeVar (gdb) p *$stmt->fromClause $102 = {type = T_List, length = 1, head = 0x7f5ffa43dfe0, tail = 0x7f5ffa43dfe0} (gdb) set $fromclause=(RangeVar*)($stmt->fromClause->head.data->ptr_value) (gdb) p *$fromclause $103 = {type = T_RangeVar, catalogname = 0x0, schemaname = 0x0, relname = 0x7f5ffa43d848 "item", partitionname = 0x0, subpartitionname = 0x0, inhOpt = INH_DEFAULT, relpersistence = 112 'p', alias = 0x0, location = 17, ispartition = false, issubpartition = false, partitionKeyValuesList = 0x0, isbucket = false, buckets = 0x0, length = 0, foreignOid = 0, withVerExpr = false} 综合以上分析可以得到语法树结构 语义分析Semantic Analysis 在完成词法分析和语法分析后,parse_analyze函数会根据语法树的类型,调用transformSelectStmt将parseTree改写为查询树。 (gdb) p *result $3 = {type = T_Query, commandType = CMD_SELECT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = false, utilityStmt = 0x0, resultRelation = 0, hasAggs = false, hasWindowFuncs = false, hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false, hasForUpdate = false, hasRowSecurity = false, hasSynonyms = false, cteList = 0x0, rtable = 0x7f5ff5eb8c88, jointree = 0x7f5ff5eb9310, targetList = 0x7f5ff5eb9110,…} (gdb) p *result->targetList $13 = {type = T_List, length = 2, head = 0x7f5ff5eb90c8, tail = 0x7f5ff5eb92c8} (gdb) p *(Node *)(result->targetList->head.data->ptr_value) $8 = {type = T_TargetEntry} (gdb) p *(TargetEntry*)(result->targetList->head.data->ptr_value) $9 = {xpr = {type = T_TargetEntry, selec = 0}, expr = 0x7f5ff636ff48, resno = 1, resname = 0x7f5ff5caf330 "a", ressortgroupref = 0, resorigtbl = 24576, resorigcol = 1, resjunk = false} (gdb) p *(TargetEntry*)(result->targetList->tail.data->ptr_value) $10 = {xpr = {type = T_TargetEntry, selec = 0}, expr = 0x7f5ff5eb9178, resno = 2, resname = 0x7f5ff5caf5f0 "b", ressortgroupref = 0, resorigtbl = 24576, resorigcol = 2, resjunk = false} (gdb) (gdb) p *result->rtable $14 = {type = T_List, length = 1, head = 0x7f5ff5eb8c40, tail = 0x7f5ff5eb8c40} (gdb) p *(Node *)(result->rtable->head.data->ptr_value) $15 = {type = T_RangeTblEntry} (gdb) p *(RangeTblEntry*)(result->rtable->head.data->ptr_value) $16 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relname = 0x7f5ff636efb0 "item", partAttrNum = 0x0, relid = 24576, partitionOid = 0, isContainPartition = false, subpartitionOid = 0……} 得到的查询树结构如下: 完成词法、语法和语义分析后,SQL解析过程完成,SQL引擎开始执行查询优化。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

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

Rocky Linux

Rocky Linux

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册