SuperAPI AI 工具集

scalable-data-schema

数据与分析

查看项目

更新于 10-16 05:36

技能介绍

用途

可扩展数据 Schema 设计技能用于帮助开发者设计随应用成长而扩展的数据库结构——从原型阶段一直支撑到数百万用户。当出现以下情况时可使用该技能:启动新项目并设计初始数据模型;现有 Schema 引发性能问题;规划从数千条记录扩展到数百万条记录;在不同数据库系统之间迁移;数据模型需要在不产生破坏性变更的前提下演进。

核心原则

1. 从简单起步,为复杂预留

原型阶段(少于 1 万条记录):以开发速度优先,为便利而反规范化,使用简单索引,单一数据库实例。

增长阶段(1 万至 100 万条记录):通过规范化减少冗余,添加战略性索引,引入只读副本,监控查询性能。

扩展阶段(超过 100 万条记录):对大表进行分区,按逻辑边界分片,增加缓存层,考虑多语言持久化(polyglot persistence)。

2. 查询模式驱动 Schema

反模式:先设计 Schema,再写查询。 最佳实践:先识别查询,再设计 Schema。工作流程为:列出最频繁的前 10 个查询;列出最昂贵的前 5 个查询;设计索引以同时支持两者;用真实数据量进行基准测试。

3. 为演进做规划

Schema 版本化策略:仅做增量变更(新增列、新增表);弃用旧字段而非直接删除;使用数据库迁移工具(Flyway、Liquibase、Alembic);在 git 中对 Schema 进行版本管理。

设计模式

模式 1:事件溯源用于审计追踪

适用场景:需要完整的变更历史。反模式是就地更新,会丢失先前值、变更人和变更时间。更好的做法是创建事件日志表。文档给出 user_events 表结构,包含 id、user_id、event_type、event_data(JSONB)、created_at、created_by 字段,并为 user_id 和 created_at 建立索引,同时通过视图从事件推导当前状态。权衡:获得完整审计轨迹与时间旅行查询能力,代价是占用更多存储、查询更复杂。

模式 2:软删除用于恢复

适用场景:数据有价值或删除操作罕见。文档给出 products 表,包含 deleted_at 和 deleted_by 字段,用部分索引仅索引活跃记录。权衡:便于恢复、满足审计合规,但每个查询都需要 WHERE deleted_at IS NULL,唯一约束也更复杂。

模式 3:多态关联

适用场景:多个实体类型共享同一种关系。反模式是使用可空外键(post_id、photo_id、video_id)。更好的做法是使用带类型的多态设计,即 commentable_type + commentable_id,并通过 CHECK 约束确保类型有效。权衡:灵活可扩展,但无法使用外键约束、连接更复杂;若各类型字段差异很大则应使用独立表。

模式 4:层级数据

邻接列表(简单、常见):用 parent_id 引用同表;获取直接子节点很快,获取所有后代需递归 CTE(较慢)。嵌套集(读快写慢):用 lft、rgt 边界;获取所有后代和到根的路径都很快,给出相应 SQL 示例。选择建议:频繁更新、层级较浅用邻接列表;以读取为主、层级较深用嵌套集;材质化路径(materialized path,将路径存为字符串如 /1/5/12/)可兼顾两者。

模式 5:时序数据分区

适用场景:数据随时间持续增长。文档给出 metrics 表,包含 metric_name、value、recorded_at、tags,主键为 (id, recorded_at),按 recorded_at 范围分区,示例按月创建分区表并建立索引,查询会自动使用正确分区。优势包括:只查询相关分区(分区裁剪);轻松删除旧分区(瞬时删除);跨分区并行查询;按分区管理存储。

索引策略

何时建索引:列频繁用于 WHERE 子句、用于 JOIN 条件、用于 ORDER BY 时,以及外键(即使数据库不自动创建)。

不建索引的场景:表很小(少于 1000 行)、列基数低、列频繁更新、索引会比表还大。

索引类型:B-Tree(默认,最常用,适用于 =、<、>、<=、>=、BETWEEN、IN、LIKE 'prefix%');Hash(仅精确匹配);GIN(用于数组/JSONB);部分索引(索引行的子集);复合索引(多列,顺序很重要,并说明能支持和不能支持的查询情形)。

索引维护部分给出查找未使用索引、查找重复索引、重建膨胀索引的 PostgreSQL 查询语句。

Schema 演进

仅增量的迁移:安全(零停机)操作包括添加带默认值的新列、创建新表、并发创建新索引;有风险(需停机或仔细规划)操作包括删除列、重命名列、修改列类型。

安全迁移模式(三步部署):第一步添加新列并部署,代码忽略它;第二步回填并双写;第三步切换,代码仅使用新列,然后删除旧列并重命名。

版本化 Schema:通过 schema_migrations 表跟踪迁移版本,文档给出示例迁移文件结构并在事务中执行。

数据库选型指南

SQL(关系型):PostgreSQL 适合复杂查询、ACID 事务、JSONB,具备全文搜索、地理空间(PostGIS)等高级特性,适用于需要强一致性和丰富查询能力时;MySQL/MariaDB 适合读密集型负载、复制,生态成熟,适用于需要简单复制或受托管限制时;SQLite 适合嵌入式数据库、单用户应用。

NoSQL:MongoDB(文档型)适合灵活 Schema、快速迭代、层级数据;Redis(键值)适合缓存、会话、发布订阅;DynamoDB(键值)适合 Serverless、可预测性能,适用于 AWS 生态和按请求计费;Cassandra(宽列)适合时序、写密集型负载,适用于多数据中心和超大规模。

还给出决策矩阵,列出用户账户与事务用 PostgreSQL(ACID、关系)、产品目录用 PostgreSQL、会话存储用 Redis、活动流用 Cassandra、分析事件用 ClickHouse(列式、OLAP)、文档存储用 MongoDB、地理空间查询用 PostgreSQL + PostGIS。

性能优化

查询分析:使用 EXPLAIN ANALYZE 查看查询计划,关注大表上的“Seq Scan”(需加索引)、使用“Hash Join”而非“Nested Loop”、较高的“actual time”。

常见修复:大表 JOIN 慢——给外键和状态列加索引;大表 COUNT(*) 慢——大表使用估算值(pg_class 的 reltuples)或维护计数器表;N+1 查询——用 JOIN 或 IN 做预加载。

应避免的反模式

文档列出反模式与更佳方案对照:列类型中使用 ENUM(难改,改用查找表外键);将数组存为字符串(无法高效查询,改用数组列或连接表);用 GUID/UUID 作主键(索引碎片、16 字节,改用 BIGSERIAL,8 字节且顺序);过早优化(无收益的增加复杂度,应从简开始按需优化);缺少外键(数据完整性问题,始终使用 FK 约束);没有 created_at/updated_at(无法审计或调试,所有表都应添加);过度规范化(连接过多,为读模式反规范化);规范化不足(数据重复、更新异常,规范化到 3NF 再有策略地反规范化)。

输出格式

协助 Schema 设计时按以下结构输出:Schema 分析、当前痛点、推荐 Schema(SQL DDL)、索引(附理由)、迁移策略、权衡(优劣)、预期性能影响(读、写、存储的变化)。

集成

该技能可与 database-schema(初始 Schema 设计)、api-design(使 Schema 与 API 需求对齐)、systems-decompose(特性驱动的 Schema 设计)、data-infrastructure-at-scale(规模化 Schema 的基础设施)配合使用。