Skip to main content

概览

无论是关系型数据库(MySQL、PostgreSQL)还是非关系型数据库(MongoDB、Redis),在系统设计和全栈面试中,有一些通用理论和架构思想是所有数据库通用的。

本文作为数据库篇章的概览,主要梳理那些脱离具体工具的通用核心考点。

范式与反范式设计

在设计表结构时,如何权衡数据的冗余和查询的性能?

三大范式 (Normal Form)

  • 第一范式 (1NF):确保每一列都保持原子性,不可再分。(例如:地址字段不要把省、市、区混写在一起)。
  • 第二范式 (2NF):在 1NF 基础上,非主键列必须完全依赖于主键,而不是部分依赖。(例如:订单表里不要存商品名称,商品名称只依赖于商品 ID,不完全依赖于订单 ID)。
  • 第三范式 (3NF):在 2NF 基础上,非主键列必须直接依赖于主键,不能存在传递依赖。(即不能存在 A 依赖 B,B 依赖主键的情况)。

面试题:实际开发中一定要遵循三大范式吗?什么是反范式设计?

回答要点: 范式的目的是为了消除数据冗余、防止更新异常。但在实际的高并发和大数据量业务中,完全遵循范式会导致极其复杂的跨表 JOIN,性能极差。

反范式设计(Denormalization):为了提升查询性能,刻意增加数据冗余,用空间换时间。 例如:在“订单表”中直接冗余“用户名”和“商品快照”,这样查询订单列表时就不需要去 JOIN 用户表和商品表,大大提高了读性能。

CAP 定理与 BASE 理论

这是分布式数据库和分布式系统的基石理论。

CAP 定理

在分布式系统中,以下三个特性不可能同时满足,最多只能同时满足其中两个:

  • C (Consistency,一致性):所有节点在同一时间的数据完全一致。
  • A (Availability,可用性):服务一直可用,每次请求都能获得非报错的响应(但不保证是最新数据)。
  • P (Partition tolerance,分区容错性):即使节点之间的网络通信出现故障(分区),系统仍能继续运行。

由于网络分区(P)是分布式系统的客观事实,因此系统设计通常在 CPAP 之间做权衡:

  • CP 架构:如 Redis Cluster(严格模式)、Zookeeper。当网络故障时,为了保证数据一致,节点会拒绝服务。
  • AP 架构:如 Eureka、Cassandra、高可用配置的 MySQL 主从。网络故障时,各节点返回本地数据(可能是旧数据),保证服务可用。

BASE 理论

BASE 是对 CAP 中 AP 架构的延伸:

  • BA (Basically Available,基本可用):允许损失部分可用性(如响应时间变长、非核心功能降级)。
  • S (Soft State,软状态):允许系统存在中间状态,即不同节点间的数据副本同步存在延时。
  • E (Eventually Consistent,最终一致性):不强求实时一致,但经过一段时间后,数据最终会达到一致状态。(这是现代互联网高并发架构的核心思想)。

数据库连接池 (Connection Pool)

面试题:为什么后端应用连接数据库都要使用“连接池”?

回答要点

  1. TCP 握手开销:数据库连接是基于 TCP 的,如果每次查询都去新建连接(三次握手、身份验证等),然后在查询结束后销毁连接(四次挥手),网络和时间开销非常巨大。
  2. 连接池复用:连接池在应用启动时预先建立一定数量的数据库长连接,放入内存中维护。业务代码需要查库时,从池子里“借”一个连接,用完后“还”给池子,避免了频繁创建销毁。
  3. 资源保护:数据库服务器能承受的最大连接数是有限的,连接池可以限制最大并发连接数,防止流量洪峰把数据库打挂。

在 Node.js 中,像 mysql2/promisecreatePool,或者 Prisma 内部内置的连接池引擎,都是为了解决这个问题。

ORM 的优势与争议

在全栈开发中,如何与数据库交互一直是个经典话题:纯手写 SQL vs Query Builder(如 Knex) vs ORM(如 Prisma, TypeORM)。

面试题:为什么要用 ORM?ORM 有什么缺点?

优势

  1. 开发效率高:以面向对象(或类型安全)的方式操作数据库,屏蔽了不同数据库方言的差异。
  2. 代码可维护性:结构清晰,天然防 SQL 注入(参数化查询)。
  3. 类型安全:现代 ORM(如 Prisma)能在编译阶段发现查询错误,提供完美的 TypeScript 自动补全。

争议 / 缺点

  1. 性能损耗与“黑盒”:ORM 自动生成的 SQL 有时非常臃肿,对于复杂的多表统计、分组查询,性能远不如手写优化的 SQL。
  2. N+1 问题:如果不熟悉 ORM 机制,很容易在循环里查关联数据,导致疯狂发起大量查询(现代 ORM 通常提供 Eager Loading / Populate 预加载,或 DataLoader 批处理来解决)。
  3. 学习成本:不仅要懂 SQL 原理,还要额外学习 ORM 庞大的 API。

在实际项目中,通常是“二八定律”:80% 的常规 CRUD 用 ORM 提升效率,20% 的复杂报表、高频核心接口使用原生 SQL(或 Raw Query)来极致优化性能。