一家公司上了主数据平台,开了三次评审会,产出一份四十多页的编码规范:客户码十六位,前四位大区,中间八位日期,末四位流水;商品码用品类加规格;供应商码沿用统一社会信用代码后九位。文档发下去的时候,所有人都签字了。
半年后抽查,销售系统里同一个客户在企业微信侧是手机号建档,在 ERP 侧是合同编号建档,在客服工单系统里是邮箱;同一个 SKU 在商城、仓储、核算三个系统各自有一套主键;供应商换了一次主体,采购系统和财务系统各自改了一半。规范文档一条都没被违反——因为文档只规定了"码长什么样",从来没规定"谁有权发这个码",更没有规定"违反了会怎样"。
这件事真正的破口不在编码形态上。同一个号是新发还是复用、谁有权创建新对象、改名之后要不要通知下游、两个对象合并以后旧的单据还能不能查——这四个问题没有一个被回答,写再细的编码规则都只是格式说明。拉锯式的扯皮之所以会拖半年,是因为每个系统都能给出自洽的理由:它按手机号建档是为了客服能直接拨号,它按合同编号建档是为了收款有据可依,它的理由在它自己的业务闭环里完全成立。
所以本文要讲的不是"编码该怎么设计",而是编码不一致这件事到底在哪些位置产生代价、这些代价有多大、以及按什么顺序下手。一句话概括全文的立场:编码不一致不是抽象的数据质量问题,它会在集成、对账、报表三个具体位置产生可量化的代价;治理的抓手不是先上主数据平台,而是先定死四件事——发码权归谁、主键用什么、变更怎么传播、历史怎么保留——然后按"被引用系统数 × 变更频率 × 出错代价"排优先级,只治理值得治理的对象。
编码冲突看上去千奇百怪,落到结构上只有三种形态。区分清楚是有用的,因为这三种形态对应的修补动作完全不同。
第一种是一物多码:同一个对象在不同系统里拿到了不同的主键。上文那个客户就是典型——CRM 里是 C000123,订单系统里是身份证号,客服系统里是邮箱,财务应收里是合同签约主体编号。四个码指向同一个人,但没有任何一个系统知道另外三个存在。形成原因是结构性的:每个系统在建设时都需要一个主键,而当时没有任何一个"权威源"可以问,于是各自造了一个。这不是哪个团队不负责任,是缺少发码方造成的结果。
第二种是一码多物:同一个码在不同时期或不同系统里指向不同对象。常见的触发场景有两种。一种是主键复用:某个供应商编码在供应商被停用后被重新分配给了新供应商,三年后查旧凭证,查出来的是现在这家;SKU 编码在换季清档后被分配给另一个商品,历史订单的商品详情就整体错位了。另一种是同名不同实:集团内部"A 分公司"这个编码在华东系统和华南系统里各指一个实体,谁都没错,但聚合到一起就是翻倍。
第三种是码随系统走:对象本身没变,主键在系统间传递时被反复重写。ERP 里的 EMP-0091 同步到工单系统后变成 W-2026-0091,前端从工单系统取数又自己生成了一套展示 ID。每过一个环节换一次码,链路越长,回溯时要在多少个映射里跳就越难搞清。这种形态最容易被忽视,因为每一跳单独看都"实现了功能",只有故障排查时才会暴露:运维拿着前端的 ID 去问数据库,中间要过四道翻译。
这三种形态的共同成因是同一个缺口:没有定义对象的权威来源,也没有定义跨系统引用时的取值规范。修补动作因此也不同——一物多码要靠映射表和身份识别来收敛;一码多物要靠"主键永不复用"这条硬规则来杜绝新增,靠审计来清理存量;码随系统走要靠"下游只引用不生成"这条纪律来止住扩散。
很多人觉得编码不一致是"数据质量问题",是技术债,是以后慢慢还的东西。这个判断之所以长期不被重视,是因为没有把代价落到具体位置上。它其实只在三个位置炸开,每个位置的代价类型完全不同。
第一个位置是集成接口。两个系统的码对不上,最直接的做法是写一张映射表。两个系统一张表,三个系统两两互连就要三张,五个系统就是十张——映射表的数量随系统数近似按平方增长。每新增一个系统,要补的映射不是一张,是与现存所有系统的那一组。更麻烦的是这些映射的语义会漂移:当初建表时两边约定"客户"指的是签约主体,两年后其中一方改成了指付款方,映射表不会自己报错,它只是安静地继续翻译。
这里真正的成本不是写第一张表的那两天,而是此后每一张表的维护、每一次系统升级时的回归验证、以及每个新来的工程师理解"为什么这里要多查一次"的学习成本。它是一次性的投入、持续性的支出。
第二个位置是对账。对账要求两边的聚合口径完全一致。左边按客户主体聚合应收,右边按合同签约主体聚合收款,遇到母子公司签约、子公司付款的情况,两边的数字各自自洽,算出来的差额既不能用汇率解释,也不能用时间差解释,只能通过人工逐笔穿透去追。这类问题的特征是:它不会因为查一次就永远解决,它会每个月、每天,甚至每批次重复出现。
对账环节的代价可以直接折算成人力乘以发生频率,这也是三个位置里最容易量化的一处。如果一次追差额要两个人天,一个月追四次,一年的成本是一个能让人停下来想一想的数字。而且这笔支出不可省略——财务口径对不上是不能"先不做"的。
第三个位置是报表。同一个指标在两套系统里跑出两个结果,而且两边都"有道理":一个是按下单时间、按客户主码统计的 GMV,一个是按收款确认、按合同主体统计的收入。业务部门各自从自己最熟的系统取数,开会时先花半小时争论哪个数是对的,再花一周有人私下建 Excel 中间层做 reconcile。半年后没人说得清哪个是权威口径。
报表位置的代价最难量化,但往往是三个位置里最贵的:它不表现为账单,表现为决策被推迟、指标失去约束力、管理层对数据失去信任。一旦信任被消耗,后续任何数据项目的推进成本都会变高。
把这三个位置放在一起看,就能理解为什么不能用一把尺子量所有的编码冲突:集成位置的代价是工程人力,一次性但重复发生;对账位置的代价是财务与运营人力,周期性且不可省略;报表位置的代价是决策延迟,不可计量但常常最大。这个差别直接决定了优先级该怎么排——不是哪个对象"数据量大"就先治哪个,而是哪个对象出错后落在最贵、最高频的那个环节。
回到开篇那份编码规范。它失败的原因不是规则写得不好,是它回答了一个不太重要的问题。格式是否统一、是否带业务含义、长度是否一致——这些是关于"码长什么样"的问题,它们影响可读性和存储效率,但不影响一致性。真正决定一致性的只有一个问题:谁有权为这个对象创建主键。
把发码权说清楚,包含三件具体的事:谁能创建(唯一的发码方)、谁能引用(其他系统只能持有这个码,不允许自造替代品)、谁能作废(只有发码方能置失效,且作废不等于删除)。这三件事定义了对象生命周期的所有权,缺任何一件都会重新长出一物多码。
这里有一个常见的误解:以为确定发码权等于把所有对象的发码都集中到一个系统或一个平台上。实际上不需要,也不应该。正确形态是每个对象类别有且只有一个发码方,但这个发码方分布在不同系统里——客户主体由 CRM 发,商品 SKU 由商品中台或 PLM 发,供应商由采购系统发,库位由 WMS 发,组织和岗位由人力系统发。集中的是"唯一性",不是"物理位置"。强行把所有对象的发码收进一套平台,往往会造出一个离业务最远、因此信息最滞后的发码方。
那么怎么判断某个对象该由谁发?有两个比较硬的判据。一是谁最先接触这个对象的生命周期起点——客户第一次出现是在销售线索里,那么客户码的产生应该在 CRM 而不是在财务;商品第一次被定义是在选品或研发环节,那么 SKU 码应该在商品主档而不是在商城。二是谁承担这个对象变更的第一手责任——如果客户的合并需要谁来做决定、为合并后的后果负责,谁就更适合发码。这两条通常指向同一个系统,指向不同系统时,取第一条。
还有一个必须写死的条款是违反之后怎样。技术上,接口层应该能拒绝没有来源主键的对象,或者至少打上标记并告警;流程上,需要有一个具体的人(不是委员会)有权说"你这个字典没有来源码,不能上线"。规范文档最常缺的就是这一条——它约定了应该怎么做,却没有任何东西阻止别人不这么做。没有后果的规范,执行力等于零。
发码权落地的最小形态,是一个可以被调用、有唯一性校验、有幂等保证的发码服务,加一份写明每类对象发码方的清单。它可以是主数据平台的一个模块,也可以是某套已有系统开放的一个接口。先有这个机制,再谈平台,顺序反了的话,平台只是把尚未达成的共识固化进了数据库。
主键类型的选择是编码体系里少有的、一旦定错就很难回头的技术决策。两类选项都很常见,各自的代价落在完全不同的环节。
自然键是业务上有含义的标识:手机号、邮箱、统一社会信用代码、身份证号、车牌号、SKU 的业务组合码。它最大的优势是人可以直接读懂。客服接到电话时,客户报出手机号就能查到全部信息,不需要翻译;财务核对手工凭证时,对面的编码和合同上的一致;两个部门吵架时,双方喊出来的名字是同一个东西。这在协同成本上省下来的量相当可观。
但自然键的代价是硬的。其一,它会变化。手机号会换,邮箱会作废,企业名称变更后登记证照上的信息也会随之更新,国家统一推行的社会组织信用代码虽然相对稳定,也存在换证重发的情况。一个会变的东西做外键,意味着每次变化都要级联更新所有引用它的表。其二,它可能缺失或出错。早期客户可能只留了一个姓名和一个座机,录入时客服把两个数字打颠倒了也没人发现。其三,格式不统一。长短不一、含中英文混合、含特殊字符的自然键做索引时占用大、比较慢,而且很容易在不同系统里出现同一对象的多种写法。其四,它无法表达合并。当两个自然人对象被认定为同一家企业时,没有任何自然键能表示"A 和 B 现在都指向 C"这个中间状态。
代理键是没有业务含义、由权威源统一发放的标识:自增整数、雪花 ID、UUID 等。它的优势正好对准自然键的痛点:稳定不变、格式统一、长度可控、适合做外键和索引、可以表达任意复杂的合并与拆分关系。合并两个客户时,只需要把两个旧代理键映射到同一个新代理键,历史数据一行不用改。
代理键的代价也很具体。任何被人看到的场景都要翻译:客服不能直接问号码,得先查映射;运维排查时拿着代理键要在映射表里跳几跳才认得出对象;跨系统的日志追踪链路随之变长。另一项代价是前提性:代理键必须由权威源统一发放,否则每个系统各发各的 UUID,只是把一物多码从"有意义的多码"变成了"无意义的多码",反而更难人工识别。换句话说,代理键天然依赖前一个抓手——没有定发码权就上代理键,等于制造灾难。
实务上最常见的可行形态是混合策略:内部以代理键作为主键与外键,承担所有跨表跨系统的引用;同时为对象保留一个或多个自然键作为唯一性约束和查询入口。自然键可空、可多个(手机号和邮箱可以并存),但一旦有值就要做唯一性校验——这条校验正是防止一物多码自动产生的那道闸。
判据是这样的:如果这个对象会被人在对话、邮件、电话、纸质单据里直接引用,那么至少要有一条可查询的自然键;如果它只存在于机器链路里、从不被人口述,那么纯代理键完全可以接受,而且更省事。商品 SKU 通常需要一条可查的业务码(因为仓管要念出来),而一次接口调用的请求流水号不需要。
编码体系不是定完规则就完事,它每天都要应对变更。把所有变更笼统地叫"同步"是很多项目失败的原因——这五类变更的难度差了不止一个数量级,用同一条管道处理必然出问题。
新增是最简单的一类。发码方创建、发注册号、下游订阅或拉取即可,操作幂等、可以重放、出问题可以重来。它的难点其实在发码之前:怎么判定这个对象是否已经存在。判重规则要在发码服务里先定义清楚——是按证件号唯一、还是按名称加地址组合、还是按企业全称加统一社会信用代码。这一步做不好,新增操作本身就在持续制造新的一物多码,而且新制造的比存量更难清理,因为没人知道它是新的重复。
改名是对象身份没变、只有一个属性变了。理论处理最简单:更新描述字段,下游刷新缓存。它的风险在两处:一是把改名误判成新增(因为名称不同,判重规则失效),从而产生重复;二是下游把名称当业务键在用——这是自然键的残留形态,一旦存在,改名就会变成一件"要改好几张表"的事。所以改名的处理难度不取决于改名本身,取决于下游对名称的依赖程度。
合并是五类里最难的一类。两个对象被判定为同一个,需要保留旧码 A、旧码 B 到新主键的映射,并且历史凭证必须能同时按 A 和按 B 查到。它的回滚几乎不可能:一旦下游已经把 A 名下的所有业务数据迁移到了 B,要把它们拆回去,数据本身的归属已经被改写,剩下的只有反向映射这一层皮。因此合并必须做成带人工确认的低频流程,确认项至少包括:谁发起、谁复核、合并后主叫什么、旧码是否停止新接业务、历史单据是否保留原样。常见的错误是允许业务人员自助合并客户、且没有审计日志。
拆分比合并略容易,因为数据不需要重归属到同一个地方,只需要按时间点切开。它的难点在于拆分点之后的新增数据归谁,以及拆分点之前的历史数据全部落在其中一边时怎么表达。实务上拆分通常要指定一个"承接方",未明确归属的历史单据继续挂在承接方名下,同时在备注里记录原始对象。
失效是被误用最多的一类。对象不再使用了,很多系统直接删记录,这在编码治理里是严重错误:删除是不可追溯的物理动作,失效是可查询的状态。只要世界上还有一张历史凭证引用了它,这个编码就必须存在。正确做法是把 enabled 布尔列换成生效时间戳与失效时间戳的区间表达,这样"截至某个时点有效的对象集合"可以被精确回答,而布尔值做不到这一点。
把五类放在一起,可以得到一条很有用的工程排序:新增和改名是幂等可重试的,失效是幂等但要求所有下游都理解这个状态位,合并和拆分是有副作用且难以回滚的。所以一个可行的推进顺序是先做通新增、改名、失效这三类,把管道、订阅、重试、幂等这些机制跑顺;合并与拆分做成低频的、带人工确认的专项流程,不进主链路。回滚难度的差别,是排优先级时要额外乘上的一个因子。
历史保留这一项最容易被跳过,因为它不产生即时收益。但它是唯一一项"现在不做、以后补不回来"的抓手——数据一旦物理删除,再多的钱也买不回来。
旧码要保留多久,答案不在技术上,在业务追溯周期上。至少要覆盖四类最长周期:财务凭证的法定保存年限、合同的履约与追诉周期、售后与质保承诺期、以及内外部审计的抽查年限。取其中最长的一个。实务上更简单的判据是:只要还有任何一张历史单据在引用它,就不能删。这条规则的好处是不需要争论年限,只需要判断引用是否存在。
但"保留"和"参与查询"是两件事,可以分开处理。一种策略是旧码保留在映射表里、但不建立新的查询入口——用户不会在新系统里看到它,但历史数据仍能正确解析;另一种策略是允许按旧码查询,但返回结果要显式提示"该编码已合并至 XXX",避免操作者误以为自己在操作一个仍然有效的对象。后者体验更好,代价是每个查询入口都要多做一层。选择哪一种取决于这个对象是否经常被人拿旧码来查。
由此可以得出三条具体的主键设计要求:第一,主键永不复用。已经分配过的码永远不再分配给新对象,这是防止一码多物的唯一硬防线。第二,有效期用区间而不是布尔。生效时间与失效时间两个字段能回答"某个历史时点的有效集合",布尔值只能回答"现在",而历史查询问的永远不是"现在"。第三,历史单据要冗余存储当时的描述字段。订单里不但要存商品外键,还要把下单当时的商品名称、规格、单价快照一份。否则查一张三年前的订单,显示的商品名称是今天改过的名字,业务人员会认为系统算错了。
最后一条尤其值得单独强调:"能查历史订单"这件事,对主键设计提出了明确要求——主键必须是稳定的、不随业务含义漂移的;凡是会随时间变化的东西,一律放进描述表并按时间做版本。如果把一个会变的字段选作了主键,那么每一张引用它的历史单据都会在未来的某次业务逻辑变更中被静默改写,而没有任何人会收到通知。
到这一步为止讲的都是"该定什么规则"。但现实中没人有时间一下子把所有对象都治完,所以必须回答取舍问题。可用的判据是把三个因子相乘:
优先级 ≈ 被引用系统数 × 变更频率 × 出错后暴露环节的代价。
第一个因子,被多少个下游系统引用,决定改一次要通知几家、桥接成本是多少。被五个系统引用的对象,每次变更带来的协调工作是被引用一个系统的对象的若干倍,且映射链式断裂的风险点也更多。
第二个因子,变更频率,决定这套规则多久要被执行一次。高频治理对象(每天都有新增和改名的 SKU)哪怕单次成本低,累积起来也很可观;而一年改两次的对象,即便规则笨一点、手工一点,也完全扛得住。
第三个因子,出错后最先暴露在哪一环,决定这个错误的严重程度。落在履约环节的错误(库存对不上、发货地址错)会当场中断业务,代价最高;落在对账环节的错误会形成持续的周期性人力支出;落在报表环节的错误最隐蔽但会侵蚀决策信任。
三个因子相乘,可以得到几条判断逻辑:值得优先治理的是——被三个以上下游引用、变更按月甚至按周发生、且出错会直接暴露在履约或对账环节的对象。典型是客户主体、商品 SKU、供应商与合同主体这三类。可以不治的是——只被一两个内部系统引用、基本不变更、错了也只是报表口径差异的对象。典型是内部运营标签、临时活动分组、一次性项目编号、只有自己用的操作流水号。
还需要一条反向判据:如果两个系统之间已经存在一张稳定的、有人负责的映射表,而且一年改不了两次,那么引入新治理机制的收益很可能小于它带来的维护成本。这种情况理性的选择就是什么都不做,只把这张表登记在册,标明它的负责人和适用边界。治理本身是有成本的,"不治理"是一个完全合法且经常正确的结论。
还有一点关于顺序:先治理的对象应该同时也是最好治理的。理想的第一批治理对象满足——边界清晰、有明确的业务责任人、下游系统愿意配合、出错不致命。用第一批把流程跑顺、把工具磨出来,再上难度。这就像第五节说的,把合并和拆分这种难回滚的操作留到后期,而不要一开始就挑集团公司与客户合并这种最硬的骨头啃。
这四条失败路径在大量项目里反复出现,值得单独列出来,因为它们每一个在实施时都显得很合理。
第一条:先买平台,后定规则。主数据平台的作用是把已经达成的规则固化下来并执行。规则还没定时上平台,等于把尚未达成共识的部分也固化了进去,而且多付一次迁移成本。更糟的是平台自带一套默认数据模型,团队往往直接套用它,于是"平台厂商的理解"悄悄替代了"我们自己定的规则"。正确顺序是先定发码权归属和五类变更的处理办法,最好用一张纸写清楚,然后再选工具把这个纸上的东西固化。
第二条:先把历史数据全部回刷一遍,再谈增量。这条路的问题不止是工作量大。全量回刷本身要占用大量磁盘 I/O,往往伴随锁等待和主从复制延迟,可能直接影响在线业务;而回刷过程中新发生的数据又会产生新的不一致,回刷结束后还得再补一次增量——目标一直在后退。更可行的顺序是先保证增量正确:从某个时点起,所有新发生的创建和变更都按统一规则走,历史数据则按需迁移。而且多数情况下,历史数据并不需要物理回刷,只需要在查询时做翻译——读取时把旧码映射成新码——成本远低于写入时重写。
第三条:把统一编码等同于统一系统。这是最昂贵的一个误解。这两件事只在极少数情况下重合:系统不统一完全可以有统一编码(各系统引用同一个权威主键即可,这正是本文主张的形态);反过来,所有业务跑在同一套 ERP 里、但每个模块各发各的码,照样对不上。正确的目标应该表述为"所有引用同一对象的系统持有同一个主键",而不是"所有业务跑在一套系统里"。前者是数据层面的目标,成本可控;后者是应用架构层面的重构,周期以年计,而且往往失败。
第四条:把映射表当长期方案,却没人维护它。映射表是为过渡而生的,但过渡期可能长达数年,这没问题——问题在于没有 owner。一张没有明确负责人、没有核对周期的映射表,通常在三个月后开始出现错误映射。错误的映射比对不上更危险:对不上会触发告警或者至少报错,错误的映射会静默地把 A 的数据翻译成 B,直到某个季度的报表明显异常才被发现,而那时错误已经扩散到多个下游。如果决定长期使用映射表,至少要明确三件事:谁负责维护、多久核对一次、新对象的登记由哪边触发。
前面的讨论都是逻辑层面的,但治理方案里每一项"多查一次""多写一遍""多同步一路",最后都实实在在落在服务器的内存、磁盘 I/O 和数据库连接数上。这一段讲这些资源账的结构,不讲具体配置数字——因为这类任务的资源占用随数据规模、表结构、索引数量、同步窗口的差异极大,给任何通用数字都是误导,必须按实际数据量单独核算。
映射表自身会成为新的热点。这是最常被低估的一项。映射表的记录数可能只有几十万条,看上去很小,但它会被放在最热的查询路径上:几乎每一次跨系统读取都要先翻译一次。这意味着它承受的读写次数远远超过它记录的对象数量——一个对象每天可能变更零次,却被调用几十次。所以映射表应当按高频缓存层来对待,而不是按一张普通配置表来对待。由此产生的取舍是:集中成一张大映射表实现简单、维护点少,但会成为一个集中的热点和单点,出问题会同时影响所有对象;按对象类别拆分成多张,可以把热点分散、也便于按对象做容量规划,代价是维护多套结构和多份加载逻辑。选哪种取决于对象分布是否均匀、以及是否有某一类对象的调用量远超其他。
全量回刷的账在磁盘 I/O 和锁上。回刷本质是一次大规模的数据重写操作,它的开销不在 CPU 而在存储子系统:大量的随机写入、大量的日志生成、索引同步维护,以及由此引发的锁等待。在带只读副本的架构里,回刷还会显著拉大主从延迟——主库写完,从库要过好一会儿才能读到,这段时间内所有走从库的查询读到的都是旧数据。这些现象在服务器层面的表现就是磁盘吞吐、IOPS 与复制延迟这几个指标同时吃紧。因此在回刷之前,需要先把当前存储子系统的余量测一遍,再决定分批大小、限速阈值和错峰窗口;而不是简单地拿业务库的现有规格去跑一个性质完全不同的任务。分批、限速、错峰是常规做法,前提是先知道余量在哪。
同步任务的账在并发和连接数上。跨系统同步天然不可能实时,必然存在一个延迟窗口,这个窗口的大小决定了业务侧要准备多厚重的兜底。在窗口内做的所有决策都必须有最终一致的兜底方案:可以是在读取时做二次校验,可以是写入前的确认式重试,也可以是把"结果可能变化"直接写进业务规则(例如允许超卖、但明确规定超卖后的处理流程)。把延迟目标设成零是不现实的,正确的做法是测量真实延迟的分布——注意要看尾部的分布而不是平均值——然后据此设计兜底。
同时,同步任务本身要占用数据库连接。多个同步链路叠加时,连接池可能被后台任务挤占,导致在线业务拿不到连接。连接数是有限资源,这一点在设计同步架构时经常被忽略,直到高峰期出现排队。因此同步任务的并发度要根据在线业务的连接水位来定,而不是根据"想让数据多快同步到位"来定。
把这几项放在一起看,结论是一致的:承载映射表、承担回刷任务、运行跨系统同步的那一层服务器,其资源画像与普通业务服务器并不相同——它更依赖内存与磁盘 I/O,对连接数的需求也更偏向持续占用而非突发。这类资源的取值取决于数据量级和同步窗口两个变量,给不出通用数字,只能按实际规模单独核算。
前面用了很长的篇幅讲怎么做,但更有价值的结论往往是"先别做"。至少有三种情况下,启动编码治理是负收益的。
第一种:核心系统不超过两三个,而且它们原本就在读写同一份数据。这时候根本不存在跨系统引用,也就无所谓编码冲突。所谓冲突的前提是"同一个对象在两个以上地方被独立建档",只有少数几套系统且共用数据库时,这个前提不成立。此时引入主数据治理,只会给团队增加一套流程和一张没人维护的表。
第二种:某个对象的下游只有一个。它被创建、被消费,全在同一个系统里完成,没有别的系统在引用它。这种情况下编码不一致只可能是明天的问题,不是今天的。为明天的可能付今天的成本,除非这个"明天"已经排进了明确的建设计划——比如明年确定要上供应链系统,那么客户和商品这两类可以提前半年准备,而不是提前两年。
第三种:业务本身还在快速变化。主体划分方式每半年改一次、商品分类体系每季重排、组织形态随着融资轮次反复调整——这时候强行把编码规则定死,等于把今天的临时结构固化成明天的历史包袱。这种情况下更划算的做法不是把规则定死,而是把"能改"这件事做扎实:主键稳定不变且不复用、支持合并与拆分、有映射表兜底、有效期用区间表达。做到这几条,结构怎么变都不至于翻车。
还有一条最难写进文档但最致命的:还没有人愿意为这件事负责。编码治理的产物是一套需要长期执行的约束,不是一次上线的功能。如果没有一个具体的、有权力对别人说"不行"的人来持有它,那么结果一定是产出一份没人执行的文档——也就是开篇那家公司半年后的样子。
需要先划清楚边界,避免读者带着错误预期读到这里。
本文不是数据库选型文章。不涉及某一种数据库在哪些方面更适合做主数据存储,也不讨论用什么类型的数据库可以减少编码问题的发生。编码冲突的成因在系统间的权力分配与流程约定,不在数据库的类型。
本文不讲数据同步工具或 ETL 产品的选择。不涉及链路怎么搭、哪种同步组件性能更好、CDC 与定时抽取怎么选。文中提到的同步延迟与连接占用是客观存在的资源约束,但它们是关于"要预留多少资源"的判断依据,不是产品选型建议。
本文也不是数据仓库建模文章。不涉及维度表与事实表怎么设计、缓慢变化维怎么处理、指标口径怎么在数据仓库层统一管理。虽然报表口径冲突与数仓建模高度相关,但本文讨论的是编码体系本身的治理顺序与判据,即在数仓之前、在业务系统之间存在的主键不一致问题。
文中不点名推荐任何具体产品。涉及资源评估的部分只讲结构与取舍关系,不给具体配置数字。
| 治理对象 | 通常被几个下游系统引用 | 变更频率 | 出错后最先暴露在哪一环 | 是否值得优先治理 |
|---|---|---|---|---|
| 客户与会员 | 订单、客服工单、财务应收、营销触达等,通常在四个以上 | 中等。联系方式与开票信息按月变动,主体合并偶发但难回滚 | 对账与催收环节。应收按主体聚合时无法定位差额 | 值得,且通常排在最前面。引用面最广并直接咬住财务口径,先把发码权与合并流程定死即可见效 |
| 商品与 SKU | 商城、订单、仓储、采购、成本核算等,通常在四到六个之间 | 高。新品上架与规格调整按周发生,季节性品种更快 | 履约环节。同一件货在两个系统的可用数量对不上,会当场卡住发货 | 最值得优先治理的一类。变更频率最高且出错立即暴露在最贵的环节,投资收益比最好 |
| 供应商与合同主体 | 采购、应付、合同归档、税务开票等,通常三到四个 | 低。但一旦发生多是主体变更或合并,回滚难度极大 | 结算环节。发票主体与付款对象不一致会直接卡住付款流程 | 值得。频率虽低但单次代价高,重点不在提高更新速度,而在把失效和合并的流程做对 |
| 组织与门店 | 人力、财务核算、绩效考核、门店运营等,通常三到五个 | 中低。平时稳定,随组织架构调整出现批量变动 | 报表环节。同一笔销售的归属出现两套算法,会拖慢经营决策 | 视依赖程度而定。若绩效考核口径依赖它则值得排进第一梯队,若仅用于内部信息展示可明确延后 |
| 仓库与库位 | 仓储管理、订单履约、库存核算等,通常两到四个 | 高。库区调整、临时库位与盘点差异时有发生 | 履约与盘点环节。错码会让分拣失败或盘点差额扩大 | 多数情况下不必上升到全公司层面。若这几个系统属于同一个业务域,在域内统一下发即可,无需纳入企业级治理范围 |
| 设备与资产编号 | 资产台账、监控告警、运维工单、财务折旧等,通常三到四个 | 低。以新增与报废为主,几乎不发生合并 | 盘点与折旧报表。错配不会阻断业务,但会让账实核对反复返工 | 边界清晰且出错不致命,适合作为第一批练手对象用来验证流程能否跑通,而不是作为高优先级目标 |
问题一:直接上主数据管理平台能不能解决?
取决于上之前有没有把规则定清楚。平台的作用是执行规则,不是生成规则。已有明确发码方、已定义五类变更的处理路径、已有唯一性判据的情况下,平台可以显著降低手工维护成本并保证约束力;这几样都还没有的时候,上平台只是把分歧固化进系统,并且额外付一次迁移成本。判断标准很简单:把平台厂商的产品文档拿掉,你们能不能自己写出一张纸说清"客户的码由谁发、合并时怎么办"。写不出来就先别买。
问题二:用名称或者手机号当主键行不行?
作为查询入口完全可以而且很必要,作为主键则要谨慎。名称会变、会重名、会有多种写法;手机号会换号、可以一人多个、早期可能根本没留。它们适合作为自然键承担"被人查询"和"辅助判重"两个职责,而主键本身交给稳定的代理键。混合形态是实务中最稳的:代理键做主键与外键,一个或多个自然键做唯一性约束与查询入口。如果数据量很小、协同范围只有一两个系统,纯自然键也能撑住,但要想清楚将来多一个系统时的改造路径。
问题三:历史数据要不要一次性回刷?
通常不建议。回刷占用大量磁盘 I/O、引发锁等待与复制延迟,而回刷期间新产生的数据又会制造新的不一致,目标在后退。更稳的顺序是先保证增量正确——从某个时点起所有创建与变更都按统一规则执行——历史数据则按需处理,多数场景在查询时翻译就够了,代价远低于写入时重写。只有那些会被高频查询、且翻译开销已经明显影响响应的历史表,才值得考虑分批回刷,并且要限速、错峰、分批。
问题四:映射表放在哪一层更合适?
看它的读写特征。映射表的记录数不大但读写次数极高,会被放在最热的查询路径上,因此应按高频缓存层对待。放在应用侧的本地缓存里响应最快,代价是一致性维护和每个应用重复实现;放在独立的服务或多级缓存中可以减少重复实现,代价是多一跳网络开销与一个新的依赖组件。放在关系库里当普通配置表是最省事的做法,但如果调用量上来后没有缓存层兜住,它会先于业务表成为瓶颈。无论放哪一层,都要先明确它的负责人和核对周期。
问题五:编码规则里要不要带业务含义?
倾向不带,或者就算带了也不要让系统依赖它。带业务含义的编码(大区加品类加日期)在早期很方便:看号码就知道归属,报表不用关联。但业务含义会变——大区会重划、品类会重构、组织会改名——一旦承载了含义,编码就必须跟着变,而它是主键,改主键的代价前文已经说过。折中做法是把可变的业务含义放进独立的属性或层级字段,编码本身保持无含义。如果出于人工识别的考虑一定要带,至少要让读写双方都约定:任何人不得依赖编码的某一截去做业务判断。
问题六:两个系统的码都"有道理"时以谁为准?
不要用"谁更有道理"来决定,这个标准没法执行。用一个可判定的标准:谁最先接触这个对象的生命周期起点,谁就是发码方;其次看谁承担这个对象变更的第一手责任。客户以线索系统为准而不是财务系统,商品以商品主档为准而不是商城。如果按这条仍然判不出来,说明这两边的"客户"其实在指不同的东西——很可能一个是签约主体、一个是付款方——那要做的是把这两个概念拆成两个不同的对象并各自定义关系,而不是强行让它们共用一个码。
问题七:治理到什么程度可以停手?
有一个比较明确的停止线:每一类治理对象都有唯一发码方;新增与变更走同一定义好的管道;合并拆分有人工确认和审计日志;失效与重复使用被区分开;所有还活着的历史编码都能被正确解析。做到这几条就可以停了,剩下的交给日常运维。不必追求"全公司所有字典共用一套编码",也不必追求映射表清零。治理的终点是可控,不是整齐。继续投入的边际收益会迅速下降,而维持一套过度治理体系本身的开销会变成新的负担。
问题八:合并之后旧码还要不要保留?
要,而且原则上永久保留。因为旧单据、历史凭证、已归档的审计材料都在引用它,一旦删除,这些就永远解析不出来了。保留的形式可以是映射表里的旧码到新主键的记录,要不要参与前台查询可以另行决定——可以仅在后台解析历史数据时使用,也可以允许前台查询但明确提示"该编码已合并至 XXX"。需要禁止的只有一件事:把旧码重新分配给新对象。这是防止一码多物的底线。
回到开头的那家公司。它缺的不是一份更详细的编码规范,也不是一套更贵的主数据平台,而是四个至今没有被回答的问题:这个对象的码由谁发、主键用自然键还是代理键、变更怎么传播到下游、旧码留多久。这四个问题决定了后面所有技术动作的形态,也决定了花多少钱是必要的、花多少钱是浪费的。
把这四件事写在一张纸上、指定每个对象的发码方和一个有权说"不行"的人,之后真正需要动的技术改造往往比想象中少得多——多数时候是一张已有系统的发码接口、一份带唯一性校验的登记表、一条重试点到为止的同步链路。反过来,这四个问题还悬着就启动平台采购,投入的增加只会让问题推迟暴露,不会让它变小。
一万网络深耕 IDC 行业 19 年(成立于 2007 年),在华南、华东、华北及中国香港、海外多地整合自营节点与 BGP 多线资源,提供服务器租用、机柜托管与带宽接入的一体化交付;具体机型、带宽与报价以官网实时信息或咨询确认为准。承载映射表、回刷任务与跨系统同步的服务器,其内存、磁盘 I/O 与连接数需求应按数据规模与同步窗口单独核算,具体机型与配置需结合业务量确认。
本文讨论的是跨系统编码不一致的成因、代价位置与治理顺序,核心判断是:先定死发码权、主键类型、变更传播、历史保留这四件事,再按"被引用系统数 × 变更频率 × 出错代价"决定治理范围。文中的优先级排序、对象分类与分级判断,均基于通用的系统集成与财务对账逻辑,不构成对任何具体组织架构或特定业务形态的建议。
涉及资源评估的部分——映射表的读写热点、回刷任务的磁盘 I/O 与锁、同步任务的并发与连接占用——描述的是结构性的因果关系与取舍方向,不对应任何具体机型、具体配置数值或具体性能指标。真实占用取决于数据量级、表结构与索引设计、同步窗口要求、以及主从架构等多个变量,需要按实际业务规模单独核算,通用数字在这些问题上没有参考价值。
文中不点名推荐任何具体产品,不涉及数据库选型、同步工具选型与数据仓库建模。六种治理对象的优先级判断适用于多系统集成的通用情形,具体到一个组织内部时,还需要结合其实际的系统数量、组织权责与业务稳定性重新评估。
本文的分析框架来自系统集成、财务对账与主数据管理领域的通行工程实践,包括主键不可复用原则、代理键与自然键的混合使用、合并与拆分等生命周期事件的处理方式、以及"失效"与"删除"的区分。这些属于行业内的一般性方法,具体落地形式在不同组织间差异较大。
文中未引用任何实测数据、客户案例或统计数字。所举的场景均为用于说明因果关系的典型部署思路,并非特指某一真实客户或某一实际发生的项目;所有关于系统数量、变更频率与出错环节的描述,均为定性判断而非量化统计。
价格与配置口径:本文涉及到承载这类任务的服务器资源评估,以官网实时报价为准,或向服务商咨询确认。此类资源需求主要随数据量级、读写比例、同步窗口与并发占用而变化,不存在适用于所有场景的通用配置;具体机型、带宽与防护能力以官网实时信息或咨询确认为准。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品