第二章:数据模型与查询语言
1. 数据模型的作用与选择
数据模型决定了系统如何表达现实世界,也决定了查询能力、扩展路径与演进成本。关系模型、文档模型、图模型并非互斥关系,工程上常采用 混合持久化(Polyglot Persistence)。
2. 关系模型与文档模型
2.1 关系模型的核心价值
关系模型通过表、行、外键和声明式查询(SQL)把“数据表示”与“访问路径”解耦。开发者描述“要什么”,优化器决定“怎么做”,这使得索引调整和执行策略优化可以在不改业务代码的情况下持续演进。
2.2 NoSQL 兴起的动因
NoSQL 的核心诉求不是否定 SQL,而是补足场景:
- 高写入吞吐与横向扩展。
- 灵活结构与快速迭代。
- 特定查询模型(文档、图、时间序列、键值)。
- 成本与运维模型差异。
2.3 对象关系失配
应用层对象通常是嵌套结构,关系库是规范化表结构。ORM 能降低样板代码,但无法消除模型差异,尤其在复杂聚合读取与跨对象事务场景中更明显。
2.4 文档模型的优势与边界
文档模型适合“一对多嵌套”且经常整体读取的聚合对象,优势是局部性好、结构贴近应用对象。
局限在于:
- 多对多关系表达与跨文档一致性成本较高。
- 复杂连接查询通常需要应用层补偿。
- 文档过大时,局部字段访问会带来读放大。
2.5 Schema-on-Read 与 Schema-on-Write
Schema-on-Write(关系库常见):写入前校验,结构强约束,适合高一致性场景。Schema-on-Read(文档库常见):读取时解释结构,适合异构与快速变化数据。
两者本质是“约束施加时机”不同,而不是“有无 schema”。
2.6 关系与文档的融合趋势
主流关系库支持 JSON 字段与索引;文档库也在增强聚合和关联能力。架构设计应按查询模式和一致性需求选型,而非二选一。
3. 查询语言:声明式优先
3.1 声明式与命令式
声明式查询(SQL、Cypher)能让优化器选择更优执行计划,更利于并行化与跨版本优化。命令式流程可控性高,但容易把执行细节固化进业务代码。
3.2 MapReduce 的定位
MapReduce 介于声明式与命令式之间:框架负责并行、容错与数据重分布,开发者提供 map / reduce 逻辑。现代系统更多使用声明式聚合接口来降低复杂度。
SELECT user_id, COUNT(*) AS event_cnt
FROM user_events
WHERE event_date = '2026-02-16'
GROUP BY user_id;
4. 图数据模型
4.1 何时使用图模型
当多对多关系密集且查询以“关系遍历”为主(社交网络、风控关系网、知识图谱),图模型通常比关系表与文档嵌套更自然。
4.2 属性图与三元组模型
- 属性图(Property Graph):顶点和边都可带属性,适合业务实体关系建模。
- 三元组(RDF):
(subject, predicate, object),更偏语义互联与知识表示。
4.3 图查询语言
Cypher:模式匹配直观,适合路径查询。SPARQL:面向RDF生态。- 递归
SQL/Datalog:可表达图遍历,但可读性与优化复杂度更高。
WITH RECURSIVE reach(src, dst) AS (
SELECT from_id, to_id FROM edges
UNION ALL
SELECT r.src, e.to_id
FROM reach r
JOIN edges e ON r.dst = e.from_id
)
SELECT * FROM reach;
5. 选型建议
- 以查询模式为第一约束,以一致性需求为第二约束。
- 高频关联查询优先考虑关系或图模型。
- 聚合对象整体读写优先考虑文档模型。
- 复杂系统可采用多模型协同,但要明确“单一事实来源(Source of Truth)”。