dbaplus社群 18小时前
亿级数据的核心表,如何优雅扩展字段不出bug?
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

亿级数据表新增字段面临锁表、页分裂、索引衰减等问题。文章介绍了两种方案:扩展字段和扩展表,并分析了各自的优缺点。最终提出了一种基于数据管理、数据存储、数据检索三部分解耦的方案,实现只需简单配置即可实现字段的动态扩展。

🔍扩展字段方案:使用JSON格式存储扩展数据,优点是简单易行,缺点是不可索引、并发覆盖、重复工作、数据膨胀、维护黑洞等问题。

📈扩展表方案:将扩展字段拆分成独立表存储,解决了扩展字段无法索引和并发覆盖的问题,但也引入了行数增加的问题。

🔄当前方案:将系统拆分为数据管理、数据存储、数据检索三部分,通过数据管理后台进行配置上线,实现数据的存储、传递、检索能力,全程无需开发介入。

王帅 2025-07-23 07:15 广东

只需简单配置,即可实现字段的动态扩展。

目录

一、导语

二、背景

三、扩展字段

四、扩展表

五、现在的方案

六、结语


一、导语

亿级数据的核心表新增一个字段,远不止一句简单的“ALTER TABLE”,锁表风险、页分裂、索引性能衰减……每一个问题都可能引发线上事故。如何在不影响业务的前提下,只需简单的配置,即可实现字段的动态扩展?本文将带你揭秘中台团队的实战解决方案。


二、背景

软件行业中,唯一不变的因素就是“变化”。一个新项目上线后,业务需要对现有功能做一些改动或升级,而实现这个功能必须要新增字段。新增字段乍一看无所谓,但如果加上一些前提条件,这张表是一张数亿级数据的表,而且是公司的核心热点表,你还能随心所欲地加么。抛开加字段过程中的锁表问题不说,后续随着字段和数据的不断增多,还会引发MySQL的页分裂、碎片化、索引性能衰减等一系列问题。

如何处理这个问题呢?我们最直接能想到的就是两种方式,扩展字段和扩展表。当然也有人可能会想到用非关系型数据库解决。而数据库选型往往是在项目初期时考虑,如果是老项目,实现起来就有不小的难度和风险,并且非关系型数据库也有自己无能为力的方面。所以其他方式我们暂且先按下不表,下面我们主要讨论怎么基于现有条件更优雅地解决这个问题。


三、扩展字段

扩展字段是最容易想到的解决方案,在表中增加一个扩展字段,以JSON格式存储数据。这也是我们之前一直采用的方式,我们的使用方式是这样的:

表结构:


order_id

extend

111

{"uid":1,"name":"张三"}

222

{"uid":2,"name":"李四"}

...

...

伪代码:

public class Order {
    private Long orderId;
    private String extend;
    
    /**
     * 为扩展字段extend建一个内部类
     */
    @Data
    public static class ExtendObj implements Serializable {
        private Long uId;
        private String name;
        ...
    }
    
    /**
     * 扩展字段的get、set方法
     */
    public void setExtendObj(ExtendObj extendObj) {
        // 为展示方便,省略判空等逻辑
        this.extend = JSON.toJSONString(extendObj);
    }
    public ExtendObj getExtendObj() {
        // 为展示方便,省略判空等逻辑
        return JSON.parseObject(extend, ExtendObj.class);
    }
}

如代码所示,为了便于管理字段,我们为扩展字段创建了内部类,并实现get、set方法,以便于使用。如果你是独立部门,你的数据存储只服务于自己的系统,在表设计之初可以根据经验预留一些备用字段,再配合扩展字段,基本上可以做到很少添加字段了。但这个方案也存在一些问题:

如果你是中台部门,除了上面的硬伤,还有一些更伤脑筋的问题在等着你:


四、扩展表

另一种方案是扩展表。扩展表将扩展字段中的每个字段转成一行,存储到另外一张表中:


order_id

key

value

111

uId

1

111

name

张三

222

uId

2

222

name

李四

如果后续新增了age属性,数据就变为:


order_id

key

value

111

uId

1

111

name

张三

222

uId

2

222

name

李四

111

age

26

222

age

38

扩展表解决了扩展字段无法索引的问题,由于把字段拆开了存,也很大程度上缓解了并发问题。同时,由于扩展数据不在主表存储了,也释放了主表的压力,让加字段更从容一些。但也引进来一个新问题:本来一条记录的许多属性,变成了多条记录,行数成倍增加了。为解决这个问题,我们基于主表现有的分库分表逻辑,对扩展表也进行了分库和分表。

扩展表方案貌似解决了扩展字段方案的大部分问题,可索引、没有并发覆盖问题、不影响主表性能。但还是没有解决字段维护问题,你还是不知道哪些字段场景在用什么字段,哪些字段可以下线。并且在实践中,我们还归纳出其他一些使用场景:

场景1:有些业务期望将数据存储在订单中台后,在订单的后续某个节点传递给下游服务。

场景2:有些业务期望扩展字段中的某些字段与主表上的某些字段一起进行检索。

这两个场景实现起来比较机械,我们也不希望每次都去开发。


五、现在的方案

为了满足上面两种使用场景,并且实现只需简单的配置,即可实现字段的动态扩展的愿景,最终,我们将整个系统拆分为三部分:数据管理、数据存储、数据检索。数据管理部分用于管理动态字段准入、接口透传信息、检索要求、归属以及其他基本信息,数据存储部分核心还是采用扩展表的方案,数据检索采用ES集群及自研ES管理系统ECP。


现在,我们来看看当前的系统能做什么:

至此,业务方再提出新增字段诉求,只需要在数据管理后台进行配置上线,使用者即可通过指定接口,或接口的指定参数将数据传入,实现数据的存储、传递、检索能力,全程无需开发介入。


六、结语

在大数据量表上的动态扩展字段,本质上是灵活性与稳定性的博弈,既要支撑业务快速迭代,又要规避“野蛮生长”的技术风险。基于分治思想,我们将核心数据与扩展数据分离;在系统设计上,对数据管理、数据存储、数据检索三部分进行解耦,把问题拆解,降低每一部分的设计难度;而在具体实践上,我们也将整个系统功能进行了封装,以便其他有同样困境的系统能够快速扩展该项能力。


作者丨王帅 转转交易中台研发工程师

来源丨公众号:转转技术(ID:zhuanzhuantech)

dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

亿级数据 动态扩展 扩展字段 扩展表 数据管理
相关文章