GBase 8c 表结构变更前的对象依赖排查

张开发
2026/4/12 18:29:26 15 分钟阅读

分享文章

GBase 8c 表结构变更前的对象依赖排查
GBase 8c 表结构变更前的对象依赖排查我最近看 GBase 8c 资料时一个感受越来越明显很多表结构变更失败并不是 DDL 语法本身有问题而是变更前没有把对象依赖和影响面查清楚。现场里很常见的一类情况是测试库里ALTER TABLE很顺到了生产库却突然报依赖错误或者虽然语句执行成功了但后面的视图、触发器、过程、报表任务开始连锁异常。再往后查往往不是数据库“脾气古怪”而是对象之间本来就有引用关系只是平时没把这张依赖网摊开看。我自己理解下来GBase 8c 的表结构变更真正难的不是把 DDL 写出来而是回答下面这几个问题这个表现在被哪些对象引用了。这些引用是“能独立删”的还是“跟着宿主一起删”的。这次变更是纯元数据动作还是会引发表重写、空间占用和更长窗口期。catalog 里能查到的依赖和业务代码里手写的动态 SQL分别要怎么确认。所以我现在做 8c 结构变更基本都会先做一轮“对象依赖体检”再决定到底是直接改、分阶段改还是新旧对象并行切换。先把风险分层不要一上来就执行 DDL我最近整理下来觉得表结构变更至少可以分成下面几类处理思路完全不一样。变更动作现场最容易踩的点我更倾向的处理方式新增列看起来简单但默认值、非空约束可能触发额外扫描或重写先加可空列再分批回填再补约束删除列依赖视图、规则、过程删得快但空间不会立刻回来先查依赖再确认是否真要马上删修改列类型可能重写整表窗口期和磁盘占用都要重估热表优先走“新列替换”重命名表/列业务 SQL、存储过程、外部任务脚本容易漏改先扫数据库对象再扫应用脚本删除表影响范围最大CASCADE一旦用错很难止损先把依赖对象列清楚尽量不用盲删我实际排查时一般先看两件事这次变更会不会触发表重写。这张表上游下游挂了多少对象。原因很简单。前者决定变更窗口后者决定回滚难度。我会先看的几个系统对象GBase 8c 的好处是很多对象关系并不是“黑盒”系统表和系统视图里能看到相当多线索。我自己更关注下面这几组。排查入口主要用途我通常怎么看PG_TABLES看表是否有触发器、创建时间、最后 DDL 时间先确认对象近期有没有被改过PG_OBJECT看对象创建人与修改时间判断对象最近是否被二次加工过PG_DEPEND看依赖链的核心入口判断是普通依赖、自动依赖还是内部依赖PG_REWRITE视图/规则类依赖的重要线索查视图对基表的引用不能只看名字PG_VIEWS查视图定义快速做定义级确认PG_TRIGGER查表上的触发器、触发函数、是否启用结构改动前必须过一遍PG_PROC查函数/过程定义、参数和源码线索动态 SQL 场景我会二次扫源码其中我最近最常用的是PG_DEPEND、PG_OBJECT和PG_VIEWS这一组。PG_DEPEND适合做“谁依赖谁”的主干排查。PG_OBJECT适合补“这个对象最近有没有被改过”。PG_VIEWS和PG_TRIGGER适合把定义内容补齐避免只看到对象名看不到真实影响。先确认对象状态再决定要不要进维护窗口我通常不会一上来就跑改表语句而是先把对象元数据和最近 DDL 情况看一遍。SELECTschemaname,tablename,tableowner,hasindexes,hasrules,hastriggers,created,last_ddl_timeFROMpg_tablesWHEREschemanameacctANDtablenametxn_order;如果还想把对象级信息补全我会再看一次PG_OBJECT。SELECTobject_oid,object_type,creator,ctime,mtime,changecsnFROMpg_objectWHEREobject_oidacct.txn_order::regclass;我自己更关注的是last_ddl_time和mtime。因为不少现场问题不是“这张表一直没动”而是最近有人做过授权、改过索引、调过表定义只是变更单里没写出来。这个时候如果直接套旧方案很容易误判窗口大小。查视图依赖时我不会只看 PG_VIEWS很多人排查表结构影响面只会跑一句SELECTschemaname,viewnameFROMpg_viewsWHEREdefinitionILIKE%txn_order%;这句有用但我自己不会只停在这里。原因是视图在系统里对应的不只是一个名字还牵涉到重写规则。GBase 8c 的PG_REWRITE专门存这类规则信息真正做依赖定位时我更习惯把PG_REWRITE和PG_DEPEND一起看。SELECTn.nspnameASdep_schema,c.relnameASdep_view,r.rulenameASrule_name,d.deptypeFROMpg_depend dJOINpg_rewrite rONr.oidd.objidJOINpg_class cONc.oidr.ev_classJOINpg_namespace nONn.oidc.relnamespaceWHEREd.classidpg_rewrite::regclassANDd.refclassidpg_class::regclassANDd.refobjidacct.txn_order::regclassORDERBY1,2;如果这里已经能查到多个依赖视图我一般不会再考虑“直接删列”或者“直接改类型”这种一步到位的做法而是优先改成分阶段方案。触发器和过程是我更担心的隐性风险点对业务表来说触发器经常比视图更容易被漏掉。因为视图通常还能在对象清单里看见触发器往往是表侧逻辑平时不查就没存在感。我一般会先看这张表上挂了哪些触发器、触发函数是谁、当前是不是启用状态。SELECTn.nspnameASschema_name,c.relnameAStable_name,t.tgnameAStrigger_name,p.pronameAStrigger_func,t.tgenabled,t.tgisinternalFROMpg_trigger tJOINpg_class cONc.oidt.tgrelidJOINpg_namespace nONn.oidc.relnamespaceJOINpg_proc pONp.oidt.tgfoidWHEREn.nspnameacctANDc.relnametxn_orderORDERBYt.tgname;如果表结构改动涉及到触发器里使用的列名我会继续向下看函数或过程定义。SELECTn.nspname,p.proname,p.prokind,p.prosrc,p.proargsrcFROMpg_proc pJOINpg_namespace nONn.oidp.pronamespaceWHEREp.prosrcILIKE%txn_order%ORCOALESCE(p.proargsrc,)ILIKE%txn_order%ORDERBY1,2;这里我会特别小心一个问题catalog 能查到的是非常重要的一层但我不会把它当成全部结果。真正落到现场时过程里拼动态 SQL、调包内私有函数、或者脚本侧直接拼列名这些都可能绕开“显式依赖”的主链所以最后我通常还会补一次源码检索和应用侧检索。我最常拿来判断风险等级的是 deptypePG_DEPEND里最值得看的字段之一就是deptype。我最近整理下来做结构变更时可以把它先粗分成下面几类。deptype含义我对它的理解n普通依赖被引用对象通常要配合CASCADE才能删除最常见a自动依赖宿主删掉时这类对象通常会自动跟着处理i内部依赖往往是内部实现的一部分不能按普通对象随便单删eextension 依赖和扩展对象绑定处理方式要按扩展边界来ppin 依赖系统自身依赖不能碰我个人更倾向于把n看成“上线前必须人工确认”的一类把i和p看成“不要在生产直接试”的一类。因为这两种一旦误判问题通常不是一条 SQL 回滚那么简单。改列类型时我通常优先评估“重写整表”的代价这也是我最近特别在意的一点。很多人觉得改类型只是 DDL应该很快但 GBase 8c 的手册里其实把风险写得很明确改字段类型可能重写整个表。用非空默认值加列也可能重写整个表。大表场景下这类操作不仅时间长还可能临时需要更多磁盘空间。所以我的经验是场景直接ALTER COLUMN TYPE新列替换方案小表、低峰时段可以考虑不一定必须热表、长事务多风险偏高更稳妥有多个视图/过程依赖不建议硬改更容易做灰度切换回滚要求严格回滚路径不够直观新旧列并行更好退回我自己更偏向下面这种做法新增目标类型的新列。分批回填。先改视图、过程、报表口径。观察一段时间。最后再处理旧列。示意 SQL 可以像这样写ALTERTABLEacct.txn_orderADDCOLUMNsettle_ts_newtimestamp;UPDATEacct.txn_orderSETsettle_ts_newto_timestamp(settle_ts_old,YYYY-MM-DD HH24:MI:SS)WHEREsettle_ts_oldISNOTNULLANDsettle_ts_newISNULL;CREATEORREPLACEVIEWrpt.v_order_dayASSELECTorder_id,settle_ts_newASsettle_ts,amount,status_codeFROMacct.txn_order;这种方式看起来多走了几步但从落地角度看最大的好处是把“高风险瞬时变更”拆成了“可观察、可回退的多步变更”。我会把预检查结果直接落盘不靠临场记忆如果是正式变更我一般会在 gsql 里把预检查结果直接导出来避免窗口里来回复制。gsql-dfinance_core-h192.0.2.31-p5432-Uapp_dbaSQL \o ddl_precheck_txn_order_20260402.log SELECT now(); SELECT schemaname, tablename, hastriggers, created, last_ddl_time FROM pg_tables WHERE schemaname acct AND tablename txn_order; SELECT n.nspname, c.relname, r.rulename, d.deptype FROM pg_depend d JOIN pg_rewrite r ON r.oid d.objid JOIN pg_class c ON c.oid r.ev_class JOIN pg_namespace n ON n.oid c.relnamespace WHERE d.classid pg_rewrite::regclass AND d.refclassid pg_class::regclass AND d.refobjid acct.txn_order::regclass ORDER BY 1,2; SELECT n.nspname, c.relname, t.tgname, p.proname, t.tgenabled FROM pg_trigger t JOIN pg_class c ON c.oid t.tgrelid JOIN pg_namespace n ON n.oid c.relnamespace JOIN pg_proc p ON p.oid t.tgfoid WHERE n.nspname acct AND c.relname txn_order ORDER BY t.tgname; \o SQL我最近养成这个习惯以后变更复盘会轻松很多。至少出了问题时能马上回到“变更前到底查到了什么”这个基线而不是靠口头回忆。现场里最容易忽略的几个坑我自己踩过或者见过的坑主要集中在下面几类。常见坑现场表现我现在的处理习惯只查视图名不查定义以为没影响实际口径已被引用PG_VIEWS.definition必查只查表不查触发器变更后写入链路异常表级触发器固定纳入检查项看到DROP COLUMN很快就直接执行列逻辑消失了但空间没马上回来先分清“逻辑删除列”和“物理空间回收”直接CASCADE一次删掉整串对象先把依赖清单落盘再决定是否级联只看数据库对象不看外部脚本数据库没报错任务调度开始失败应用 SQL、ETL、报表脚本一起搜这里我再多说一句。DROP COLUMN在手册里的描述其实很关键它快并不代表没有后续影响。很多时候只是让这个列对 SQL 不再可见空间并不会立刻以我们直觉里的方式回到系统里。所以结构变更和空间治理最好不要混成一个动作去理解。我现在更愿意用“先摸清依赖再设计路径”的方式做 8c 变更我最近整理这一块资料时最大的变化不是学会了多少条 DDL而是把思路改了。以前更容易把结构变更理解成“执行一条 ALTER TABLE”。现在我更倾向于把它理解成三段先识别对象关系。再评估这次变更是元数据动作还是重写动作。最后才是选哪种实施路径。对 GBase 8c 来说PG_DEPEND、PG_OBJECT、PG_REWRITE、PG_VIEWS、PG_TRIGGER这些系统对象已经给了我们很好的排查抓手。只要前面这轮检查做扎实很多原本会在生产窗口里暴露的问题其实在变更前就能看出七八成。我自己现在做表结构改动最不愿意看到的不是“语法报错”而是“语法没报错但依赖对象悄悄坏了”。前者还算早发现后者往往才是最费时间的。参考资料[1] GBase 8c 开发者手册 V5_3.0.1 https://cdn.gbase.cn/products/34/Pr3MGDrcOeeWwC9kdNEjM/GBase%208c%20V5_3.0.1_%E5%BC%80%E5%8F%91%E8%80%85%E6%89%8B%E5%86%8C_V1.1_20240119.pdf [2] GBase 8c SQL 参考手册 V5_3.0.0 https://cdn.gbase.cn/products/34/G8QzAUyKb3PKYGC96G5dV/GBase%208c%20V5_3.0.0_SQL%E6%89%8B%E5%86%8C_V2.7_20231112.pdf [3] GBase 8c 工具与命令参考手册 V5_5.0.0 https://cdn.gbase.cn/products/34/AVjQWS062Dsa1uUe_zdaG/GBase%208c%20V5_5.0.0_%E5%B7%A5%E5%85%B7%E4%B8%8E%E5%91%BD%E4%BB%A4%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C_V1.0_20230417.pdf

更多文章