如何正确存储大量用户自定义命名的键值对设置数据?
选型结论
直接选支持原生JSON类型的数据库JSON字段存储方案即可,既不要用你提到的Key-Value行存储(EAV模型),也不要用MediumText存纯JSON字符串,你的业务规模下这个方案完全能覆盖便捷遍历、高效对比的需求,且维护成本最低。
现有两个方案的硬伤
1. Key-Value单参数单条存储(EAV模型)
这个方案的查询成本会高到难以接受:
- 查单份完整配置需要聚合50条记录,批量拉取多份配置时会产生大量冗余行扫描,IO浪费极其严重。
- 做配置对比时需要反复自连接,比如对比两份配置的所有项差异,SQL复杂度会非常高,数据量稍大就会出现慢查询。
- 你算的年增180万条记录看似不多,但只要涉及批量统计、多配置对比的场景,性能衰减速度会远快于单条记录存整份配置的方案。
- 唯一的优势是可以直接给Key、Value加索引,但为了这个优势付出的查询复杂度、维护成本完全得不偿失。
2. MediumText存JSON字符串
这个方案比EAV模型好一点,至少单份配置只存1条记录,取全量配置不需要聚合,但硬伤同样明显:
- 数据库无法解析文本里的JSON结构,所有按配置项筛选、内容对比的操作都必须把整段文本拉到应用层解析,没法在数据库层做过滤,批量遍历分析的时候IO压力会非常大,灵活性极差。
最优实现方案
用数据库原生JSON类型字段存整份配置,基础表结构参考:
CREATE TABLE `setting_record` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `file_source` VARCHAR(64) NOT NULL COMMENT '配置文件来源/上传标识', `upload_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `setting_data` JSON NOT NULL COMMENT '结构化存储的全量配置' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
这个方案刚好匹配你的需求:
- 天然适配配置项动态自定义的场景:不需要提前预置表字段,不管用户生成什么命名规则的配置项,都可以直接存入JSON字段,不需要做表结构变更。
- 遍历效率极高:单条记录对应一份完整配置,扫表时每读一行就能拿到一份全量配置,IO效率比EAV模型高几十倍。
- 查询灵活:原生JSON类型会被数据库做结构化解析,你可以直接通过JSON路径表达式查询特定配置项的值,不需要把全量数据拉到应用层。比如要筛选所有
setting1 = true的配置,直接加条件JSON_EXTRACT(setting_data, '$.setting1') = true即可,支持给高频查询的JSON路径建函数索引,性能和普通预定义字段没有明显差距。 - 对比分析方便:单条记录存整份配置,不管是两份配置做逐键差异对比,还是批量提取多份配置的指定项做统计,都不需要做多行拼接,直接取字段内容做处理即可,不管是在数据库层用JSON函数处理,还是拉到应用层解析,实现成本都很低。
- 数据量完全没压力:按你估算的业务规模,年增也就180多万条记录,单份配置就算按2KB算,一年总数据量也就3G多,远没到单库单表的性能瓶颈,不需要做额外的分库分表、架构拆分。
可选优化点
- 如果后续有固定几个配置项需要高频筛选、统计,可以基于这些配置项的JSON路径建生成列,给生成列加普通索引,查询效率和预先定义的表字段完全一致。
- 除非你后续有单配置项级别的高频增删改需求,否则完全不需要把配置拆成Key-Value子表存储,徒增复杂度。
内容的提问来源于stack exchange,提问作者Sonny Hansen
相关产品推荐
相关产品推荐

