配音

数据存储与建模

课程简介

关系型、NoSQL、数据湖等存储方案的选择与建模。

🎬 本课程视频:Data Engineering — 数据工程基础


数据存储与建模:从选型到实践的完整指南

一、存储选型就是在做什么决策?

选择数据存储系统,本质上是在四个维度之间做权衡:一致性、可用性、扩展性、查询模式。没有一个存储系统能在所有维度上都做到最好。你需要根据业务需求找到最适合的平衡点。这就是 CAP 定理和 PACELC 定理的核心真理。

二、三大存储家族的深度剖析

2.1 关系型数据库(RDBMS)

代表:PostgreSQL、MySQL、SQL Server、Oracle。

核心优势是 ACID 事务——原子性、一致性、隔离性、持久性。金融场景中转账操作必须保证原子性——扣钱和加钱要么都成功要么都失败,只有 RDBMS 能保证。此外 SQL 和 JOIN 操作灵活,生态成熟。

局限:水平扩展困难(分库分表工程复杂),Schema 变更代价高(ALTER TABLE 在大表上锁表),灵活度有限。

适合需要强事务保证的场景:金融系统、订单系统、ERP、CRM。

2.2 NoSQL 数据库

文档型(MongoDB、Couchbase):Schema 灵活,JSON 文档直接存储,适合内容管理、用户画像、产品目录。优势是开发效率高,劣势是不支持复杂跨文档事务。

键值型(Redis、DynamoDB):最简单的数据模型——通过 Key 精确查找 Value。性能极高,Redis 单机支持 10 万+ QPS 的读写。适合缓存、会话存储、计数器、分布式锁。劣势是查询模式单一。

宽表型(Cassandra、HBase):按列族组织数据,适合稀疏矩阵。写入吞吐量极高(每秒百万级),适合时序数据、IoT、日志。劣势是查询需根据 Row Key 设计。

图数据库(Neo4j、ArangoDB):用节点和边存储关系密集型数据。社交网络的多跳查询在 RDBMS 中需多次 JOIN(性能极差),在图数据库中是一步操作。适合社交网络、知识图谱、欺诈检测。

2.3 数据湖(Data Lake)

代表:S3 + Iceberg/Delta Lake/Hudi。

数据湖是一种存储范式:把原始数据以任意格式(JSON、CSV、Parquet、Avro、图片、视频)存储在低成本对象存储上,用表格式层在数据之上提供事务和查询能力。

与数据仓库对比:数据类型任意 vs 结构化,存储成本低 vs 高,查询性能较慢 vs 很快。适合数据探索、AI 训练、原始数据存档。

三、存储选型的实用框架

三个问题:是否需要事务?查询模式固定还是灵活?数据量有多大?

四、数据建模的核心原则

RDBMS:规范化(3NF)+ 索引设计 + 星型模型/雪花模型(事实表+维度表)。
MongoDB:内嵌 vs 引用,反规范化提升性能。
宽表:Row Key 设计决定查询效率,列族将经常一起查询的列放在一起。

五、实战:电商数据存储架构

订单系统→PostgreSQL(事务保证),商品目录→MongoDB(灵活 Schema 应对多变属性),用户会话→Redis(高并发),用户行为日志→S3+Iceberg(海量数据),商品推荐关系→Neo4j(多跳查询)。各系统通过 Kafka 数据同步。

六、总结

没有最好的存储,只有最合适的存储。技术栈不是越统一越好,成熟的数据架构往往是多存储混合的。

七、聚簇索引与非聚簇索引的实战指南

索引是关系型数据库性能调优最重要的手段。但索引不是越多越好——每个索引都会增加写入开销和存储空间。

聚簇索引(Clustered Index)决定了数据在磁盘上的物理排序。一个表只能有一个聚簇索引。InnoDB 的主键就是聚簇索引,所以主键的选择直接影响插入性能——用自增整数做主键比用 UUID 快得多,因为新数据总是追加写入而非随机插入。

非聚簇索引(Non-Clustered Index)是独立的排序结构,指向实际数据行。一个表可以有多个非聚簇索引。覆盖索引(Covering Index)包含了查询需要的所有列,可以避免回表查询,性能提升显著。

索引设计原则:
1. 为 WHERE 条件中的列建立索引
2. 为 ORDER BY 和 GROUP BY 的列建立索引
3. 为 JOIN 关联列建立索引
4. 选择性高的列(不同值占比高)先建
5. 避免在索引列上使用函数(会导致索引失效)
6. 复合索引遵循最左前缀原则

八、NoSQL 的分布式策略

NoSQL 数据库能够水平扩展的核心机制是分片(Sharding)和复制(Replication)。

分片策略:
- 范围分片:按 Key 的范围分布到不同节点。实现简单但可能产生数据倾斜。
- 哈希分片:对 Key 做哈希计算后分布。数据分布均匀但范围查询低效。
- 一致性哈希:分布式系统中经典的分片策略。节点增减只影响少量数据。

复制策略:
- 主从复制(Leader-Follower):一个主节点处理写入,多个从节点同步。适合读多写少。
- 多主复制(Multi-Leader):多个节点都可写。适合多数据中心场景。
- 无主复制(Leaderless):每个副本都可写。DynamoDB、Cassandra 使用此策略。

九、Lakehouse 架构

Lakehouse 是近年来最热门的架构趋势之一——结合数据湖的灵活性和数据仓库的性能。核心思路是:在低成本的对象存储上,通过事务性表格式(Apache Iceberg、Delta Lake、Apache Hudi)提供 ACID 事务、Schema 演变和时间旅行等数仓级能力。

Iceberg 的核心特性:
- 快照隔离:每个读写操作看到的是一致的数据快照
- Schema 演变:可以安全地增加、删除、重命名列
- 分区演化:分区策略可以随时更改而无需重写历史数据
- 时间旅行:查询历史上的任何数据版本

选型建议:如果数据量小于 10TB,建议直接使用云数据仓库(Snowflake、BigQuery、Redshift)。超过 10TB 且有自建需求,才考虑 Lakehouse。

十、存储选型的实战决策树

这里提供一个实用的存储选型决策树:

Q1:需要 ACID 事务吗?
└─ 是 → RDBMS (PostgreSQL/MySQL)
└─ 否 → Q2

Q2:查询模式固定还是灵活?
└─ 固定(按 Key 查)→ Q3
└─ 灵活(各种条件组合)→ Q4

Q3:需要什么样的键值访问?
└─ 高性能缓存 → Redis / Memcached
└─ 大规模文档 → DynamoDB / MongoDB
└─ 时序数据 → Cassandra / InfluxDB

Q4:数据量大吗?
└─ 小于 10TB → 云数据仓库 (Snowflake/BigQuery/Redshift)
└─ 大于 10TB → 数据湖 (S3 + Iceberg/Delta Lake)

Q5:数据之间关系复杂吗?
└─ 多跳关系查询 → 图数据库 (Neo4j)
└─ 全文搜索 → Elasticsearch
└─ 简单关系 → RDBMS 即可

十一、数据建模的反模式

  1. 过度规范化:一个简单的用户表拆成七八个表,每次查询都做五六个 JOIN——影响查询性能且难以理解

  2. 忽视索引:表数据量增长后没有建立合适的索引——查询性能从毫秒级退化到秒级甚至分钟级

  3. Schema 设计不考虑未来变化:电商的订单状态最初只有"待支付、已支付、已发货、已完成"四个状态,后来加了"已退款、部分退款、待审核"——没有设计可扩展的状态机,导致大量代码修改

  4. 忽视数据生命周期:表越建越大但没有数据归档策略——查询越来越慢,存储成本越来越高

  5. 直接在生产数据库上跑分析查询:分析查询通常涉及全表扫描和复杂聚合,会严重影响生产数据库的 OLTP 性能。使用只读副本或数仓做分析。

十二、NewSQL:融合 RDBMS 和 NoSQL 优势的新一代数据库

NewSQL 是数据库领域的一个重要发展方向——既保持 RDBMS 的 ACID 事务和 SQL 接口,又实现 NoSQL 级的水平扩展能力。

代表性产品:
- CockroachDB:兼容 PostgreSQL 协议的分布式 SQL 数据库。数据自动分片、多区域部署、强一致性。适合需要全球部署的 OLTP 应用。
- TiDB:兼容 MySQL 协议的分布式 HTAP 数据库。行存 + 列存双引擎,OLTP 和 OLAP 统一处理。
- Spanner(Google 内部):全球分布式数据库,TrueTime API 提供外部一致性。Google 广告、搜索、Gmail 等核心业务都在 Spanner 上运行。

选型场景:当你的业务需要强一致性事务,同时数据量和访问量已经超出了单机 RDBMS 的处理能力——这时候 NewSQL 是比 NoSQL 更合适的选择,因为它不需要你为了扩展性而牺牲事务能力。

十三、Elasticsearch:全文搜索与分析引擎

Elasticsearch 是一个基于 Lucene 的分布式搜索和分析引擎,在现代数据架构中扮演着独特角色——它既不是传统的关系型数据库,也不是 NoSQL 键值存储,而是专门为搜索和分析场景设计的。

核心概念
- 倒排索引:Elasticsearch 的核心数据结构。与传统 B+ 树不同,倒排索引记录的是「词条 → 文档」的映射关系,这使得全文搜索可以在毫秒级完成。
- 分片与副本:索引被分为多个分片(Shard),分布在集群的不同节点上。副本(Replica)提供高可用和查询吞吐量。
- 近实时搜索:文档写入后约 1 秒即可被搜索到——通过 refresh interval 控制。

典型应用场景
- 日志分析(ELK Stack):Elasticsearch + Logstash + Kibana 是最经典的日志分析方案
- 应用搜索:商品搜索、文档搜索、知识库搜索
- 可观测性:APM 数据、指标数据的存储和聚合分析
- 向量搜索:最新版本支持密集向量索引,可用于语义搜索

选型考量:Elasticsearch 不适合作为主数据库——它的事务支持有限,不支持跨文档的 ACID 事务。它的强项是搜索和分析——当你的应用需要快速搜索大量文本数据、进行聚合分析时,Elasticsearch 是很好的选择。可以和 RDBMS 搭配使用——RDBMS 负责事务处理,Elasticsearch 负责搜索分析。

十四、Redis:缓存与实时数据处理

Redis 是一个高性能的键值存储系统,广泛应用于缓存、会话管理和实时数据处理。

五种核心数据结构:String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Sorted Set(有序集合)。每种数据结构都有对应的原子操作——INCR 做计数器、LPUSH/RPOP 做消息队列、ZRANGE 做排行榜。

持久化方案:RDB(快照)——定期将数据 dump 到磁盘,适合备份和灾难恢复;AOF(追加文件)——记录每次写操作,数据安全更高但文件较大。生产环境常两者结合使用。

应用场景:缓存加速(最常见)、分布式锁(SETNX)、限流器(滑动窗口计数)、实时排行榜(Sorted Set)、消息队列(Pub/Sub 或 Stream)、会话管理。

集群方案:Redis Cluster——数据自动分片到多个节点,支持横向扩展和自动故障转移。Codis 和 Twemproxy 是第三方代理方案。

选型注意事项:Redis 的数据通常存储在内存中——这意味着存储成本较高,不适合存储大量冷数据。对于需要持久化存储的场景,Redis 通常和 RDBMS 搭配使用——缓存热点数据(前端)配合持久化数据库(后端)。

延伸阅读