数据库面试题基础知识全解析

深入理解关系型数据库(MySQL/PostgreSQL)与NoSQL核心机制,掌握高并发场景下的设计原则与优化策略。

一、 数据库基础概念与范式

1.1 什么是数据库?

数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。它产生的目的是方便独立于应用程序进行操作的数据集合。在现代互联网架构中,数据库是核心组件,负责持久化存储用户数据、业务状态及日志信息。

1.2 关系型 vs 非关系型

关系型数据库(RDBMS)如MySQL、Oracle,基于表格结构,支持SQL语言,强调ACID事务特性,适合结构化数据。非关系型数据库(NoSQL)如Redis、MongoDB,数据结构灵活(键值、文档、列族、图),强调高可用和高扩展性,适合海量非结构化数据。

1.3 数据库范式

范式是设计关系数据库时的规范准则。
第一范式(1NF):列不可再分,确保原子性。
第二范式(2NF):在1NF基础上,非主键列必须完全依赖于主键。
第三范式(3NF):在2NF基础上,消除传递依赖。


【面试官追问】:为什么实际开发中经常违反第三范式?
解答:为了提高查询性能。通过适当的冗余字段(反范式化),可以减少表连接(Join)操作,从而降低I/O开销和CPU计算量,这是典型的“空间换时间”策略。

二、 SQL性能优化核心策略

SQL优化是面试中的高频考点,主要关注执行计划、索引命中及查询语句编写规范。

常见慢查询场景
执行计划分析
优化器原理

2.1 避免全表扫描与隐式类型转换

全表扫描是性能杀手。当WHERE条件中的字段未建立索引,或数据类型不匹配时,数据库引擎会放弃索引进行全表扫描。

-- ❌ 错误示例:对索引字段进行函数运算,导致索引失效
SELECT  FROM users WHERE YEAR(create_time) = 2023;
-- ✅ 正确示例:使用范围查询,利用索引有序性
SELECT  FROM users WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01';

2.2 深分页问题优化

当使用 LIMIT 1000000, 10 时,MySQL需要扫描前100万条记录并丢弃,效率极低。

-- 优化方案:利用覆盖索引回表
SELECT  FROM users
WHERE id >= (SELECT id FROM users LIMIT 1000000, 1)
LIMIT 10;

2.3 EXPLAIN 关键字解读

使用 EXPLAIN 可以查看SQL的执行计划。重点关注以下字段:

  • type:访问类型。性能从好到坏:system > const > eq_ref > ref > range > index > ALL。
  • key:实际使用的索引。
  • rows:预估扫描行数。
  • Extra:额外信息。出现 Using filesort 表示需要额外排序,出现 Using temporary 表示使用了临时表,均需要优化。

2.4 查询重写与索引下推

MySQL 5.6引入了索引下推(ICP, Index Condition Pushdown)优化。在传统索引扫描中,存储引擎遍历索引后回表查数据,再在Server层过滤。ICP允许在存储引擎层利用索引中包含的字段信息过滤数据,减少回表次数。

三、 B+树与索引底层原理

3.1 为什么选择B+树?

相比于B树和红黑树,B+树更适合数据库索引。原因如下:
1. 磁盘IO次数少:B+树高度通常为2-4层,一次查询仅需2-4次磁盘IO。
2. 查询效率稳定:所有数据都在叶子节点,范围查询只需遍历链表。
3. 磁盘利用率极高:非叶子节点只存索引,单个节点可容纳更多键值。

3.2 聚簇索引 vs 非聚簇索引

聚簇索引:叶子节点存储完整的数据行。InnoDB表必须有且只有一个聚簇索引(通常是主键)。
非聚簇索引(二级索引):叶子节点存储的是主键ID。查询时需要先查二级索引得到主键ID,再查聚簇索引得到数据,称为“回表”。

3.3 最左前缀法则

联合索引 (a, b, c) 遵循最左前缀匹配。查询条件必须包含索引的最左边列才会走索引。例如:

  • WHERE a=1 AND b=1 → 走索引
  • WHERE b=1 AND c=1 → 不走索引
  • WHERE a=1 AND c=1 → 只使用a列索引

3.4 覆盖索引与回表优化

覆盖索引是指查询的列恰好是索引列,无需回表查询主键索引。例如:

-- 假设 idx_name 是 name 的索引
SELECT name FROM users WHERE name = 'Alice';
-- 此查询直接通过 idx_name 获取数据,无需回表,性能极高。

四、 事务ACID与锁机制

特性 说明 实现机制
原子性 (Atomicity) 事务是一个不可分割的工作单位,要么全做,要么全不做。 Undo Log:记录数据的反向操作,用于回滚。
一致性 (Consistency) 事务前后,数据的完整性约束没有被破坏。 结合ACID其他三个特性共同实现。
隔离性 (Isolation) 多个事务并发执行时,互不干扰。 锁机制 + MVCC(多版本并发控制)。
持久性 (Durability) 事务一旦提交,对数据的修改是永久的。 Redo Log:记录物理修改,用于崩溃恢复。

4.1 隔离级别与问题

4.2 MVCC(多版本并发控制)

InnoDB通过MVCC实现高并发下的非阻塞读。它利用隐藏列(trx_id, roll_pointer)、Undo Log版本链和Read View来实现快照读。

Read View是事务读数据时生成的可见性规则。在RR级别下,第一次查询生成Read View,后续查询复用;在RC级别下,每次查询都生成新的Read View。

五、 NoSQL与MySQL选型对比

在微服务架构中,数据库选型至关重要。以下是常见NoSQL数据库的特性对比:

Redis (键值型)

优势:极速读写(内存数据库),支持复杂数据结构(String, List, Set, Hash, ZSet)。

场景:缓存、计数器、排行榜、分布式锁。

注意:数据量受内存限制,需考虑持久化(RDB/AOF)及集群方案。

MongoDB (文档型)

优势:JSON格式存储,模式灵活,支持地理空间索引。

场景:内容管理系统(CMS)、日志存储、物联网数据。

注意:事务支持较弱,聚合查询性能不如关系型数据库。

Elasticsearch (搜索型)

优势:基于倒排索引,全文检索能力极强,支持海量数据分析。

场景:日志分析、商品搜索、复杂条件筛选。

注意:集群维护复杂,数据一致性不如MySQL。

六、 网友还关心:高频实战问题解答

以下整理了近期求职者反馈最多的实战问题,结合真实业务场景进行深度解析。

Q1: 缓存穿透、缓存击穿、缓存雪崩区别?

缓存穿透:查询不存在的数据,请求直达数据库。对策:布隆过滤器、缓存空对象。
缓存击穿:热点Key过期,大量请求瞬间打到DB。对策:互斥锁、逻辑过期。
缓存雪崩:大量Key同时过期或Redis宕机。对策:随机过期时间、Redis集群高可用。

Q2: 如何设计百万级数据的分页查询?

除了上述提到的延迟关联,还可以采用游标法(基于上次查询的最大ID)或搜索引擎法(ES分页)。避免使用大偏移量 LIMIT。

Q3: 主从同步延迟怎么解决?

MySQL主从异步复制存在延迟。解决策略:1. 强一致性场景强制读主库;2. 增加从库数量;3. 使用半同步复制(Semi-sync)牺牲部分性能换取安全性。

Q4: 分库分表方案有哪些?

当单表数据超过500万或单库超过100GB时需分片。策略:
1. 垂直拆分:按业务模块拆分库。
2. 水平拆分:按哈希(Hash)或范围(Range)拆分表。
中间件:ShardingSphere、MyCat。

📚 拓展阅读:数据库架构演进之路

从单体数据库到分布式数据库,技术选型随业务增长而演变:

  1. 阶段一:单一MySQL实例,满足初创期需求。
  2. 阶段二:主从复制 + 读写分离,提升读性能。
  3. 阶段三:引入Redis缓存层,降低DB压力。
  4. 阶段四:分库分表,解决写入瓶颈。
  5. 阶段五:分布式数据库(如TiDB、OceanBase),实现水平扩展与高可用一体化。