Skip to content

数据库核心概念

无论你选择 MySQL、PostgreSQL 还是 MongoDB,数据库的底层逻辑是共通的。这篇文档把索引、事务、锁这三个最核心的概念讲透——不讲具体语法的细节,而是帮助你建立跨数据库的通用心智模型

索引:数据库为什么要建索引?

一句话讲清楚

索引就是数据库的目录。没有索引,数据库查询就像从头翻一本没有目录的书——每一页都要看(全表扫描)。有了索引,数据库直接跳到对应章节(索引查找)。

为什么索引能加速查询?

索引在磁盘上是一个有序的数据结构(最常见的是 B-Tree)。查找一条记录,不需要遍历所有行,而是像查字典一样:先翻到中间,判断目标在左边还是右边,对半缩小范围——这就是二分查找,时间复杂度从 O(n) 降到 O(log n)。

有索引:查找 id=500 → 读 3~4 个索引页 → 定位 1 个数据页 → 完成
无索引:查找 id=500 → 扫描全部 10000 页 → 找到 id=500 → 完成

索引不是免费的

索引加速了查询,但每次 INSERT / UPDATE / DELETE 时,索引也要同步更新。一张表上的索引越多,写入越慢。这就是为什么"不要给每个字段都建索引"——索引是时间换空间的权衡艺术

关系型 vs 非关系型的索引差异

维度关系型(MySQL/PG)非关系型(MongoDB)
默认结构B-TreeB-Tree
独有类型PG 有 GIN/GiST/BRIN地理空间、TTL 自动过期、文本索引
复合索引规则最左前缀原则ESR 规则(等值→排序→范围)
索引对写入的影响较大较小(因为 Schema 灵活)

记住:MySQL/PG 的复合索引按"最左前缀"使用;MongoDB 按 ESR 顺序。在你现在的学习阶段,能把一个关系型的 B-Tree 索引原理彻底搞懂,其他数据库的索引一通百通。

事务:数据库的"保险机制"

一句话讲清楚

事务 = 一组操作要么全部成功,要么全部撤销。转账就是一个天然的事务——A 扣钱、B 加钱,如果扣完钱系统崩了、B 没加钱,数据库必须能回退。

ACID 四特性

特性含义违反的例子
Atomicity 原子性全部成功或全部撤销转账中途崩溃,钱扣了没到账
Consistency 一致性数据约束在事务前后始终成立余额变成负数
Isolation 隔离性并发事务互不干扰同时读到一个正在修改的中间状态
Durability 持久性提交后就永久保存数据库重启后数据丢失

关系型的事务 vs 非关系型的事务

这是初学者最容易混淆的地方:

关系型数据库(MySQL/PG/SQLite)

  • 事务是天生的默认的。每一句 SQL 在没有显式 BEGIN 时也是隐式事务。
  • ACID 特性经过了数十年的打磨,非常成熟。你基本不用怀疑它的事务能力。
  • MySQL InnoDB 的默认隔离级别是 REPEATABLE READ;PG 是 READ COMMITTED(这也是为什么 PG 在高并发下性能更优的一个原因)。

MongoDB

  • 4.0 之前不支持多文档事务——这是 MongoDB 历史上被批评最多的一点。
  • 4.0+ 支持了,但性能开销比关系型大。官方文档明确建议:能用嵌套文档解决的,不要用多文档事务。
  • MongoDB 的设计哲学是"通过数据建模避免事务",而不是"用事务保证一致性"。这就是为什么它强调嵌套文档——一次更新一个文档天然就是原子的。

Redis

  • 没有传统意义的多键事务。它的事务(MULTI/EXEC)只能保证一组命令原子执行,不会中途插入其他客户端的命令——但如果中间某条命令失败了,前面的不会回滚。
  • 真正需要原子性的场景用 Lua 脚本——整个脚本在 Redis 中原子执行。

一句话总结:你的事务需求越强,越应该用关系型数据库。MongoDB 和 Redis 解决的是不同的问题。

锁:多个人同时操作怎么办?

一句话讲清楚

锁 = 并发控制的机制。两个请求同时想修改同一条数据,数据库用锁来排队和保护。

锁的层次:从粗到细

数据库级锁  →  表级锁  →  页级锁  →  行级锁
(很少用)       (MyISAM)   (少见)     (InnoDB/PG/MongoDB)

行锁是当前所有主流数据库的默认选择(MySQL InnoDB、PG、MongoDB WiredTiger)。它让并发操作互不干扰——A 改第 1 行、B 改第 2 行,互不影响。

但行锁有一个关键前提:WHERE 条件必须走索引。如果查询条件没命中索引,会发生全表扫描 → 锁全表。这也是为什么索引不仅仅关乎查询速度,还关乎并发能力。

乐观锁 vs 悲观锁

悲观锁乐观锁
思路"肯定有人跟我抢,先锁住""大概没人跟我抢,改了再说,冲突了重试"
实现SELECT ... FOR UPDATE版本号/时间戳
适合冲突多的场景(秒杀扣库存)冲突少的场景(编辑个人信息)
代表MySQL FOR UPDATE几乎所有数据库都可以在应用层实现

中级后端工程师的核心能力之一,就是在"读多写少用乐观锁,写冲突多用悲观锁"之间做判断。你现在不需要精通,但心里要有这个概念。

新手如何高效学习数据库?

你现在遇到的问题很典型:工作中暂时用不上,学完容易忘。下面是我推荐的策略:

1. 先通后专,建立骨架

不要一上来就深入研究 MySQL 的 InnoDB 锁机制。先通读一个数据库的"基础篇 + 进阶篇"形成骨架,知道大概有哪些话题,然后再在自己感兴趣的领域深挖。

推荐顺序:MySQL 基础 → MySQL 进阶 → 挑一个你感兴趣的专题深挖(索引原理、事务隔离、慢查询优化三选一)。

2. 用可视化工具辅助记忆

你现在已经在用的 MySQL Workbench / DB Browser / Compass / pgAdmin / RedisInsight 不要只当"执行 SQL 的工具"。用它们的 Table Inspector、Schema 分析、Explain Plan 等功能可视化地看索引结构、查询计划和数据分布——人脑对图形化的记忆远强于纯文本。

3. 做小型项目,在项目中记住

单纯对着文档敲 SQL 很快就会忘。建一个小项目——哪怕是一个命令行工具、一个本地 TODO 应用——让 CRUD、索引、事务有"真实的场景"。比如:

  • 做一个本地记账工具(SQLite),每次记账是一笔事务
  • 做一个 URL 短链接服务(Redis 做缓存),实现访问计数
  • 做一个博客搜索(ES),把文章导入后用全文搜索查

在"需要"中学,比在"应该"中学效率高 10 倍。

4. 面试驱动复习

当你需要一个"复习清单"时,打开这个文档系列的"进阶篇"末尾的 checklist——那是面试的常考点。把它们一条条过一遍,看能不能用自己的话讲清楚"这是干什么的、为什么要用、不用会怎样"。

5. 建立知识触达机制

大脑遗忘是正常的。你需要的是"快速唤醒"的能力。建立你自己的 TL;DR 速查表(比如记住"索引=目录、事务=保险、锁=排队"这三句话),忘了的时候 30 秒即可恢复上下文。