7078 字
19 分钟
SQLsql base
数据库 & SQL 八股:MySQL 常见问题速记

用面试题的方式复盘数据库基础:范式、约束、事务、隔离级别、MVCC、锁、日志、索引、慢查询、主从复制和分库分表。

准备八股一方面是为了面试,另一方面也是用"刷题"思维检查自己到底有没有掌握概念。数据库八股尤其适合这样学,因为很多问题不是孤立的:事务会连到 ACID,隔离级别会连到 MVCC 和锁,索引会连到执行计划和慢查询,主从复制又会连到 binlog。

这篇先以 MySQL / InnoDB 为主线整理。答案尽量写成"能直接说出口"的版本,但也保留一点理解层次,避免只背关键词。

一、基础概念#

Q1:数据库的三范式是什么?#

三范式是关系型数据库设计中减少数据冗余、避免更新异常的基本规范。

范式核心要求直觉
第一范式 1NF字段不可再分一列只存一个原子值
第二范式 2NF非主属性完全依赖主键联合主键场景里,字段不能只依赖主键的一部分
第三范式 3NF非主属性不能传递依赖主键字段只描述当前实体,不要绕一层依赖

举个直觉例子:订单表里不要反复存用户邮箱。订单只存 user_id,用户邮箱放在用户表里。否则用户改邮箱时,要更新很多订单行,容易不一致。

但真实业务不一定越范式化越好。为了查询性能,有时会做反范式设计,比如订单表冗余一份下单时的商品名称、价格快照。

1NF是数据库最低要求,2NF、3NF依次更规范,范式越高数据冗余越少,但查询可能更复杂。1NF比较容易理解,就是一列存一个值;2NF主要出现在"联合主键场景",比如在 (order_id, product_id) 中,product_name 就不适合放在这里,因为它只依赖于其中之一的主键 product_id,quantity适合放在这里,因为即使同样的product_id,不同批次的 order_id 也可能质量不同;3NF主要是防止依赖传递,比如主键是user_id,传递链:user_id -> department_id -> department_name,department_name实际依赖的是 department_id,那么更好的设计就是分表,一张表只描述一种实体。

Q2:超键、候选键、主键、外键分别是什么?#

  • 超键:能唯一标识一行的字段集合。
  • 候选键:最小的超键,去掉任意字段后就不能唯一标识。
  • 主键:从候选键里选出来作为主要标识的键。
  • 外键:一张表里的字段引用另一张表的主键或唯一键,用来表达和约束关系。

比如用户表:

users(id, email, name)

如果 id 唯一,email 也唯一,那么 {id}{email} 都可能是候选键。实际常用 id 做主键,因为它稳定、无业务含义;订单表里的 user_id 就可以作为外键引用 users.id

Q3:主键用自增 ID 还是 UUID?#

常见答案是:大多数单体或普通业务系统用自增 ID 更简单;分布式系统、离线生成 ID、跨库合并数据时可能使用 UUID、雪花 ID 等。

自增 ID 优点:

  • 短,存储和索引成本低。
  • 有序,适合 InnoDB 聚簇索引插入。
  • 排查问题时更直观。

自增 ID 缺点:

  • 分布式多库生成时容易冲突。
  • 容易暴露数据规模。

UUID 优点:

  • 全局唯一,适合分布式生成。
  • 不依赖数据库自增。

UUID 缺点:

  • 长,索引占用更大。
  • 随机 UUID 插入可能导致索引页分裂,影响写入性能。

所以一句话:能用稳定短 ID 就先用;分布式场景再考虑 UUID、雪花 ID、ULID 这类方案。

Q4:SQL 约束有哪几种?#

常见约束有:

约束含义
PRIMARY KEY主键,唯一且非空
FOREIGN KEY外键,保证引用关系合法
UNIQUE唯一约束,可以防止重复
NOT NULL非空约束
DEFAULT默认值
CHECK检查约束,如金额不能小于 0

约束的意义是让数据库参与保护数据质量,不要把所有规则都只放在应用代码里。

Q5:varcharchar 有什么区别?#

char 是定长字符串,varchar 是变长字符串。

类型特点适合场景
char(n)固定长度,不足可能补空格固定长度编码,如性别、状态码、MD5
varchar(n)按实际长度存储用户名、邮箱、标题等变长文本

实际业务中,变长字段通常用 varcharchar 更适合长度天然固定的字段。

Q6:inexists 有什么区别?#

IN 更像"值是否在集合里",EXISTS 更像"子查询是否存在结果"。

SELECT *
FROM users
WHERE id IN (
SELECT user_id
FROM orders
);
SELECT *
FROM users u
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.user_id = u.id
);

一般来说,IN 适合子查询结果集较小、语义上是集合匹配的场景;EXISTS 适合相关子查询,只关心是否存在。现代 MySQL 优化器会做很多改写,实际性能要看执行计划,不能只背"谁一定更快"。

Q7:dropdeletetruncate 有什么区别?#

命令作用是否删表结构是否可带 WHERE常见特点
DELETE删除行数据可以DML,可按条件删,通常记录 undo/redo
TRUNCATE清空整表不可以DDL,速度快,通常重置自增
DROP删除表不可以表结构和数据都没了

简单记:DELETE 删数据行,TRUNCATE 清空表,DROP 删除表本身。

DML:Data Manipulation Language,数据操作语言;DDL:Data Definition Language,数据定义语言。

Q8:什么是存储过程?优缺点是什么?#

存储过程是保存在数据库里的 SQL 程序,可以封装多条 SQL、条件判断、循环等逻辑。

优点:

  • 减少应用和数据库之间的多次往返。
  • 可以复用复杂数据库逻辑。
  • 权限可以集中控制。

缺点:

  • 逻辑沉到数据库里,版本管理和测试不如应用代码方便。
  • 可移植性差,不同数据库语法不同。
  • 业务逻辑分散,排查问题可能更麻烦。

现在很多互联网业务更倾向把业务逻辑放在应用层,存储过程更多用于历史系统、报表、批处理、强数据库中心化的场景。

Q9:MySQL 支持哪些存储引擎?#

常见存储引擎有 InnoDB、MyISAM、Memory、Archive 等。

引擎特点
InnoDB默认引擎,支持事务、行锁、外键、MVCC
MyISAM不支持事务,表锁,读多写少的老场景
Memory数据在内存里,重启丢失
Archive适合归档写入,查询能力较弱

现在最常用的是 InnoDB,因为它支持事务、崩溃恢复、行级锁和 MVCC,更适合通用业务系统。

存储引擎可以理解成:数据库真正负责"怎么把数据存到磁盘、怎么读出来、怎么加锁、怎么保证事务"的底层模块。MySQL 本身像一个"数据库外壳",负责:连接、权限、SQL 解析、SQL 优化、执行器;但真正到了"拿数据"的时候,执行器会去调用存储引擎。

二、事务、隔离级别与 MVCC#

Q10:什么是数据库事务?#

事务是一组数据库操作组成的逻辑单元,要么全部成功,要么全部失败。

比如下单:

  1. 创建订单。
  2. 扣库存。
  3. 写支付流水。

这些操作不能只成功一部分。事务就是用来保证这种"整体性"的。

Q11:事务的 ACID 是什么?#

特性含义直觉
Atomicity 原子性要么全成功,要么全失败不做半截
Consistency 一致性事务前后数据满足约束不破坏规则
Isolation 隔离性并发事务互不随便干扰不乱串
Durability 持久性提交后数据可靠保存不丢结果

面试里可以用转账举例:A 扣钱和 B 加钱必须一起成功,不能 A 扣了钱 B 没收到。

Q12:MySQL 的四种隔离级别是什么?#

从低到高:

隔离级别脏读不可重复读幻读
Read Uncommitted可能可能可能
Read Committed避免可能可能
Repeatable Read避免避免InnoDB 大多可避免
Serializable避免避免避免

MySQL InnoDB 默认隔离级别是 Repeatable Read

Read Uncommitted:别人没提交我也能看见;Read Committed:别人提交后我才能看见;Repeatable Read:我事务开始后,看到的快照尽量不变;Serializable:大家排队来,最安全也最慢;MySQL InnoDB 默认是 Repeatable Read,Oracle、PostgreSQL 默认一般是 Read Committed。

Q13:脏读、不可重复读、幻读是什么?#

脏读:读到了其他事务还没提交的数据。对方回滚后,你读到的就是脏数据。

不可重复读:同一个事务里,两次读取同一行,结果不一样。通常是因为别的事务提交了更新。

幻读:同一个事务里,两次按同一条件查询,结果行数变了。通常是因为别的事务插入或删除了符合条件的行。

直觉区分:

  • 不可重复读关注"同一行变了"。
  • 幻读关注"符合条件的行变多或变少了"。

Q14:事务的实现原理是什么?#

InnoDB 事务主要依赖:

  • undo log:用于回滚,也用于 MVCC 读取历史版本。
  • redo log:用于崩溃恢复,保证提交后的修改不丢。
  • 锁:控制并发修改。
  • MVCC:在不加锁读的情况下提供一致性读。

可以粗略理解:undo log 保证能撤回,redo log 保证能恢复,锁和 MVCC 保证并发下读写有秩序。

Q15:redo log、undo log、binlog 分别是什么?#

日志属于作用
undo logInnoDB回滚、MVCC 历史版本
redo logInnoDB崩溃恢复,保证持久性
binlogMySQL Server 层主从复制、时间点恢复

redo log 是物理日志,记录页级别修改;binlog 更偏逻辑日志,记录 SQL 或行变化。事务提交时,InnoDB redo log 和 MySQL binlog 要通过两阶段提交保证一致。

Q16:什么是 MVCC?#

MVCC 是多版本并发控制。它的目标是:读不阻塞写,写也尽量不阻塞读。

InnoDB 会为行记录维护隐藏字段和 undo log 版本链。普通 SELECT 在一致性读时,不一定读最新版本,而是根据 ReadView 判断哪个版本对当前事务可见。

所以 MVCC 的核心是:

  • 一行数据可能有多个历史版本。
  • 事务读数据时,根据可见性规则选择一个版本。
  • 这样可以减少读写冲突。

可见性规则就是 MVCC 用来判断"当前事务能不能看到某个数据版本"的规则。

Q17:MVCC 的实现原理是什么?#

InnoDB MVCC 主要依赖:

  • 隐藏事务 ID:记录最后修改该行的事务。
  • 回滚指针:指向 undo log 中的旧版本。
  • undo log:保存旧版本数据。
  • ReadView:判断哪些事务版本可见。

Repeatable Read 下,一个事务第一次一致性读时生成 ReadView,后续复用它,所以同一事务里多次查询结果更稳定。

Read Committed 下,每次一致性读都会生成新的 ReadView,所以能读到其他事务已经提交的新版本。

一致性读,可以理解成:事务读取数据时,不一定读取数据库"此刻最新"的数据,而是读取某个时间点上的一致快照。

三、锁与并发#

Q18:为什么要加锁?#

锁是为了解决并发读写冲突,保证数据正确性。

比如两个事务同时扣同一件商品库存。如果没有锁,都读到库存是 1,然后都扣成 0,就可能超卖。锁可以让修改同一行的事务排队。

Q19:按粒度分,数据库锁有哪些?#

常见有:

  • 表锁:锁整张表,粒度大,并发低。
  • 行锁:锁具体行,粒度小,并发高。
  • 页锁:锁数据页,介于表锁和行锁之间,MySQL InnoDB 较少直接强调。

InnoDB 支持行锁,这是它适合高并发业务的重要原因之一。

Q20:MySQL 里常见锁类型有哪些?#

按锁模式:

  • 共享锁 S Lock:读锁,多个事务可以同时持有。
  • 排他锁 X Lock:写锁,其他事务不能同时写,也通常不能加读锁。

按 InnoDB 行锁算法:

  • Record Lock:锁单条索引记录。
  • Gap Lock:锁索引记录之间的间隙。
  • Next-Key Lock:Record Lock + Gap Lock,用来避免幻读。

Q21:乐观锁和悲观锁是什么?#

悲观锁:假设冲突经常发生,操作前先加锁。

SELECT stock
FROM products
WHERE id = 1
FOR UPDATE;

FOR UPDATE 就是告诉数据库我现在读这行,不只是看看。我接下来大概率要改它,所以你先帮我把它锁住,别让别的事务同时改;等到这个事务用过了COMMIT之后,别的事务才能继续读。

乐观锁:假设冲突不多,更新时检查版本号或条件。

UPDATE products
SET stock = stock - 1,
version = version + 1
WHERE id = 1
AND version = 3
AND stock > 0;

影响行数为 0 就说明更新失败,需要重试或返回失败。

读数据的同时读出版本号,修改时检查我读到的版本号是否仍然有效。乐观锁就是更新时带上"我以为的数据状态",如果状态没变就更新,变了就失败。

Q22:InnoDB 的行锁是怎么实现的?#

InnoDB 的行锁是加在索引上的。查询条件如果命中索引,就锁对应索引记录;如果没有合适索引,可能扫描更多记录,导致锁范围扩大。

所以行锁不是"天然只锁一行"。写更新语句时,合适的索引非常重要。

有些 SQL 锁的不是"某个已经存在的值",而是"这个查询条件对应的范围"。如果精确找到,确实是锁精确值。但是如果是没找到,要锁应该出现的位置,比如BETWEEN AND,就要防止在这个范围内插入。

Q23:什么是死锁?怎么解决?#

死锁是多个事务互相等待对方释放锁,形成循环等待。

比如:

事务 A 锁住 user:1,等待 user:2
事务 B 锁住 user:2,等待 user:1

解决思路:

  • 保持固定的加锁顺序。
  • 事务尽量短,少做无关操作。
  • 给查询条件加合适索引,减少锁范围。
  • 捕获死锁异常后重试。
  • 避免大事务。

Q24:隔离级别和锁有什么关系?#

隔离级别越高,对并发异常限制越强,通常需要更多锁或更严格的可见性规则。

InnoDB 在 Repeatable Read 下通过 MVCC 解决一致性读,通过 Next-Key Lock 等机制处理当前读中的幻读问题。

普通 SELECT 多数是快照读,不加锁;SELECT ... FOR UPDATEUPDATEDELETE 属于当前读,会读取最新数据并加锁。

四、索引与 SQL 优化#

Q25:索引的分类方式有哪些?#

常见分类:

  • 按数据结构:B+ 树索引、Hash 索引、全文索引、空间索引。
  • 按字段数量:单列索引、联合索引。
  • 按唯一性:普通索引、唯一索引。
  • 按物理组织:聚簇索引、二级索引。

MySQL InnoDB 最常见的是 B+ 树索引。

Q26:聚簇索引和非聚簇索引有什么区别?#

InnoDB 中,聚簇索引就是按主键组织整行数据的索引。叶子节点存的是完整行数据。

二级索引,也叫非聚簇索引,叶子节点存的是索引列和主键值。通过二级索引找到主键后,如果还需要其他列,就要回到聚簇索引查整行,这叫回表。

所以:

  • 主键查询通常很快。
  • 二级索引如果覆盖了查询所需列,就可以避免回表。

如果 InnoDB 表没有显式主键,它会选择一个唯一非空索引作为聚簇索引;如果还没有,就生成隐藏的 row id 作为聚簇索引。所以,聚簇索引不一定永远等于你声明的主键索引。但是一般都会建主键,所以InnoDB中聚簇索引 ≈ 主键索引 / 一级索引,非聚簇索引 ≈ 二级索引 / 辅助索引

Q27:B+ 树有什么特点?为什么 MySQL 用 B+ 树?#

B+ 树是多叉平衡搜索树,特点是:

  • 树高低,减少磁盘 IO。
  • 数据都在叶子节点。
  • 叶子节点之间有链表,适合范围查询。
  • 节点有序,适合排序和范围扫描。

相比二叉树,B+ 树更"矮胖",更适合磁盘页读取。相比 Hash,B+ 树不仅能等值查询,还能范围查询和排序。

Q28:创建联合索引要注意什么?#

联合索引要注意最左前缀原则。

比如:

CREATE INDEX idx_user_status_time ON orders(user_id, status, created_at);

通常适合:

WHERE user_id = 1
WHERE user_id = 1 AND status = 'paid'
WHERE user_id = 1 AND status = 'paid' ORDER BY created_at

但不太适合只按 status 查询,因为跳过了最左边的 user_id

设计联合索引时,要看真实查询条件,不是字段越多越好。

Q29:什么是索引失效?#

索引失效是指明明建了索引,但查询没有有效使用它。

常见原因:

  • 对索引列使用函数:LOWER(email) = ...
  • 隐式类型转换:字符串字段拿数字比较。
  • 左模糊匹配:LIKE '%abc'
  • 联合索引不满足最左前缀。
  • OR 条件中有列没有索引。
  • 查询返回大量数据,优化器认为全表扫描更划算。

解决思路是看 EXPLAIN,确认访问类型、使用索引、扫描行数,再调整 SQL 或索引。

Q30:如何定位和优化慢 SQL?#

常见流程:

  1. 开启慢查询日志,找到慢 SQL。
  2. EXPLAIN 看执行计划。
  3. 看是否全表扫描、是否走错索引、扫描行数是否过大。
  4. 优化索引、改写 SQL、减少返回列和返回行。
  5. 必要时做分页优化、归档冷热数据、分库分表。
  6. 重新压测或观察指标。

不要只凭感觉加索引。索引要服务具体查询。

EXPLAIN 里可以重点看这几个字段:

字段重点看什么
type访问类型,常见从好到差大致是 constrefrangeindexALL
possible_keys理论上可能用到哪些索引
key实际用了哪个索引
rows预计扫描多少行
Extra是否出现 Using filesortUsing temporaryUsing index 等信息

如果看到 type = ALLrows 很大、Extra 里有 Using filesortUsing temporary,就要重点检查查询条件、排序字段和索引设计。

Q31:大表查询怎么优化?#

常见方向:

  • 建合适索引。
  • 避免 SELECT *
  • 加时间范围或业务范围,减少扫描。
  • 分页避免深 offset。
  • 归档历史数据,做冷热分离。
  • 用汇总表、物化视图或定时统计减少实时聚合。
  • 必要时分库分表。

核心是减少扫描行数、减少回表、减少排序临时表。

Q32:超大分页怎么处理?#

普通分页:

LIMIT 1000000, 20

会跳过大量行,越往后越慢。

优化方式:

  1. 游标分页:
SELECT *
FROM orders
WHERE id > 1000000
ORDER BY id
LIMIT 20;
  1. 延迟关联:
SELECT o.*
FROM orders o
JOIN (
SELECT id
FROM orders
ORDER BY id
LIMIT 1000000, 20
) t ON o.id = t.id;
  1. 产品上限制深分页,只允许按条件筛选。

Q33:什么是覆盖索引?#

如果一个查询需要的列都在同一个索引里,数据库不用回表,这就是覆盖索引。

比如有索引:

CREATE INDEX idx_users_email_name ON users(email, name);

查询:

SELECT email, name
FROM users
WHERE email = 'owen@example.com';

只需要读索引就能得到结果,不必再回到聚簇索引取整行。

Q34:count(*)count(1)count(column) 有什么区别?#

  • count(*):统计行数,包括所有行。
  • count(1):也是统计行数,现代数据库里通常和 count(*) 差别不大。
  • count(column):统计该列非 NULL 的行数。

面试里可以说:MySQL 中一般推荐用 count(*) 表达统计行数,语义最清楚,优化器也会处理。

五、查询执行与 SQL 语义#

Q35:MySQL 执行查询的大致过程是什么?#

大致流程:

  1. 客户端发送 SQL。
  2. 连接器处理连接和权限。
  3. 解析器做词法、语法分析。
  4. 预处理器检查表、字段、权限。
  5. 优化器选择执行计划。
  6. 执行器调用存储引擎接口读取数据。
  7. 返回结果。

现在 MySQL 8 已经没有老版本的查询缓存作为主路径了,回答时不要把 query cache 当成核心流程。

Q36:WHEREHAVING 的区别?#

WHERE 在分组前过滤原始行,HAVING 在分组后过滤聚合结果。

SELECT user_id, COUNT(*) AS order_count
FROM orders
WHERE status = 'paid'
GROUP BY user_id
HAVING COUNT(*) > 3;

这里先用 WHERE 过滤已支付订单,再按用户分组,最后用 HAVING 找订单数大于 3 的用户。

Q37:JOINONWHERE 有什么区别?#

ON 是连接条件,WHERE 是对连接后的结果继续过滤。

INNER JOIN 中,有些条件放 ONWHERE 结果可能一样;但在 LEFT JOIN 中差别很大。

SELECT u.id, o.id
FROM users u
LEFT JOIN orders o
ON u.id = o.user_id
AND o.status = 'paid';

这会保留没有支付订单的用户。

如果写成:

SELECT u.id, o.id
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.status = 'paid';

就会把没有匹配订单的用户过滤掉,效果接近内连接。

补充:SQL 注入是什么?怎么防?#

SQL 注入是把用户输入当成 SQL 语句的一部分拼接执行,导致查询逻辑被恶意改变。

危险写法:

SELECT *
FROM users
WHERE email = '${email}' AND password = '${password}';

如果用户输入里包含特殊 SQL 片段,就可能绕过条件或执行危险操作。

正确思路是使用参数化查询,也就是让 SQL 模板和参数分离:

SELECT *
FROM users
WHERE email = ? AND password = ?;

应用代码把 emailpassword 作为参数传给数据库驱动,不直接拼接进 SQL 字符串。这样数据库会把它们当成值,而不是当成 SQL 语法。

六、主从复制与高可用#

Q38:什么是 MySQL 主从复制?#

主从复制是把主库的数据变更同步到从库。主库负责写入,从库复制主库的 binlog 并重放。

人话就是一台数据库负责写,另一台或多台数据库跟着复制它的数据。

常见用途:

  • 读写分离。
  • 数据备份。
  • 故障切换。
  • 报表查询隔离。

Q39:MySQL 主从复制流程是什么?#

简化流程:

  1. 主库提交事务,写 binlog。
  2. 从库 IO 线程拉取主库 binlog,写入 relay log。
  3. 从库 SQL 线程或 worker 线程读取 relay log 并重放。
  4. 从库数据逐步追上主库。

MySQL 复制可以是异步、半同步,也可以配置 GTID 方便故障切换和定位。

Q40:主从延迟怎么解决?#

主从延迟原因可能是:

  • 主库写入压力大。
  • 从库机器性能弱。
  • 大事务重放慢。
  • 网络延迟。
  • 从库并行复制能力不足。

解决思路:

  • 避免大事务,拆批处理。
  • 提升从库配置。
  • 开启并行复制。
  • 读写分离时,对强一致读走主库。
  • 业务上接受最终一致,做延迟提示或重试。
  • 监控复制延迟。

Q41:如何实现读写分离?#

常见做法:

  • 写请求走主库。
  • 普通读请求走从库。
  • 强一致读、刚写完马上读的请求走主库。
  • 通过中间件、代理层或应用代码做路由。

要注意主从延迟。不是所有读都适合走从库。

七、分库分表#

Q42:为什么要分库分表?#

当单库单表在容量、并发、维护成本上扛不住时,可以考虑分库分表。

常见原因:

  • 单表数据量太大,索引和查询变慢。
  • 单库连接数、CPU、IO 压力太高。
  • 数据增长过快,备份和 DDL 成本高。
  • 希望按业务或租户拆分。

分库分表不是银弹,会增加复杂度。能通过索引、归档、缓存、读写分离解决的问题,不一定要立刻分库分表。

Q43:垂直拆分和水平拆分有什么区别?#

垂直拆分:按业务或字段拆。

  • 垂直分库:用户库、订单库、支付库。
  • 垂直分表:把大字段、低频字段拆到扩展表。

水平拆分:按行拆,把同一张表的数据分散到多个表或库。

比如订单按 user_id 取模:

orders_0
orders_1
orders_2
orders_3

垂直拆分解决业务耦合和单表字段过宽,水平拆分解决单表数据量和单库压力。

Q44:分库分表会带来哪些问题?#

常见问题:

  • 跨库 JOIN 变困难。
  • 分布式事务复杂。
  • 全局唯一 ID 需要单独设计。
  • 跨分片分页、排序、聚合成本高。
  • 扩容和数据迁移复杂。
  • SQL 兼容性受中间件限制。

所以分库分表要谨慎,最好先确认瓶颈和增长趋势。

Q45:常见分库分表中间件有哪些?#

常见有 ShardingSphere-JDBC、Mycat、TDDL、Atlas、Cobar 等。

现在更常见的回答可以重点说 ShardingSphere:

  • ShardingSphere-JDBC:轻量,作为 Java JDBC 增强层接入,应用内路由。
  • Mycat:代理式中间件,对应用透明一些,但多一层代理。

不同方案主要差别在接入方式、SQL 支持度、运维复杂度和生态活跃度。

八、面试回答策略#

Q46:实际发现查询很慢,有哪些解决方案?#

可以按这个顺序答:

  1. 先确认慢在哪里:慢查询日志、监控、执行时间。
  2. EXPLAIN 看执行计划。
  3. 看是否全表扫描、索引失效、扫描行数过大、排序临时表过大。
  4. 优化 SQL:减少列、减少行、避免函数包索引列、避免深分页。
  5. 优化索引:单列、联合、覆盖索引。
  6. 优化表结构:冷热分离、归档、冗余汇总。
  7. 优化架构:缓存、读写分离、分库分表。

这样回答比较完整,不会一上来只说"加索引"。

Q47:数据库知识怎么串起来?#

可以用一条主线串:

表结构设计
-> 约束保证数据合法
-> 事务保证一组修改可靠
-> 隔离级别 / MVCC / 锁解决并发
-> 索引和执行计划解决查询性能
-> 日志保证恢复和复制
-> 主从 / 分库分表解决规模问题

面试题看起来很多,但它们其实都围绕一个核心问题:数据库如何在正确性、性能和可扩展性之间做平衡。

专题阅读

SQL

这篇文章属于同一条阅读链。你可以直接在这里切换,不用再回到列表页重新找。

当前进度10 / 10

阅读导航

文章目录

当前阅读位置将在这里显示

0 节