Mysql 面试题
01 Mysql 概述
MySQL 是一款开源免费、生态成熟、功能完善,并且能够支持高并发场景的关系型数据库。
02 Mysql 字段类型
1. 常见字段类型
- 数值类型:
INT、BIGINT、DECIMAL、FLOAT、DOUBLE - 字符串类型:
CHAR、VARCHAR、TEXT - 日期时间类型:
DATE、DATETIME、TIMESTAMP - 二进制类型:
BLOB - 布尔类型:MySQL 通常使用
TINYINT(1)表示布尔值
2. UNSIGNED 有什么作用?
UNSIGNED 表示无符号,只能存储非负数。它可以去掉负数范围,使正数可表示范围扩大一倍。
CREATE TABLE test_unsigned (
id INT AUTO_INCREMENT PRIMARY KEY,
val_signed TINYINT, -- 有符号:-128 到 127
val_unsigned TINYINT UNSIGNED -- 无符号:0 到 255
);
3. CHAR 和 VARCHAR 的区别是什么?⭐
CHAR:定长字符串,适合长度固定的数据,例如身份证号、状态码。VARCHAR:变长字符串,按实际长度存储,适合长度不固定的数据,例如用户名、地址。VARCHAR会额外占用 1~2 字节记录长度。
4. DECIMAL 和 FLOAT/DOUBLE 的区别是什么? ⭐⭐⭐
DECIMAL:定点数,精度准确,适合金额、账务等场景。FLOAT/DOUBLE:浮点数,存储和计算效率较高,但可能存在精度误差。
涉及金额时通常使用 DECIMAL,不要使用 FLOAT 或 DOUBLE。
5. 为什么不推荐使用 TEXT 和 BLOB?
TEXT 和 BLOB 适合存储较大的文本或二进制数据,但通常存在以下问题:
- 不方便设置默认值
- 索引需要指定前缀长度
- 查询和更新成本较高
- 可能增加磁盘和网络 I/O
如果字段长度可控,优先使用 VARCHAR;图片、视频等大文件通常放在对象存储中,数据库只保存访问地址。
6. DATETIME 和 TIMESTAMP 的区别是什么?如何选择?⭐️
-DATETIME 就像录像机,你存入什么时间,它就永远显示什么时间,与时区无关。它空间占用大(8 字节),但范围广(可到 9999 年),适合存储出生日期、历史记录等静态时间。
TIMESTAMP 则是真正的时间戳,它存的是格林威治时间(UTC),读取时会根据当前服务器时区自动转换。它空间利用率高(4 字节),但有‘2038年危机’,适合记录订单创建、数据更新等与系统时间强相关的日志。
- 首选
DATETIME:现在磁盘空间不值钱,MySQL 5.6 以后DATETIME的空间也优化到了 5 字节,且能避免 2038 年失效的问题。 - 特殊情况选
TIMESTAMP:如果你的业务是全球化的,或者需要频繁利用ON UPDATE CURRENT_TIMESTAMP自动更新修改时间。
7. NULL 和 '' 的区别是什么?
NULL:表示未知、缺失或不存在的值。'':表示一个长度为 0 的字符串。
注意,判断为 null,必须使用:
8. Boolean 类型如何表示?⭐️⭐️
MySQL 中没有专门的布尔类型,而是用 TINYINT(1) 类型来表示布尔值。TINYINT(1) 类型可以存储 0 或 1,分别对应 false 或 true。
-- 1. 创建表,使用三种写法:BOOLEAN, BOOL, TINYINT(1)
CREATE TABLE test_bool (
id INT AUTO_INCREMENT PRIMARY KEY,
is_active BOOLEAN, -- 写法一
is_deleted BOOL, -- 写法二
is_valid TINYINT(1) -- 写法三(MySQL 最终的形式)
);
-- 2. 查看表结构,你会发现所有类型都变成了 tinyint(1)
DESC test_bool;
-- 也可以看建表语句
SHOW CREATE TABLE test_bool;
TINYINT(1) 中的 1 不是存储长度,也不会限制只能存储 0 和 1,它主要是历史上的显示宽度。因此业务上最好通过约束保证字段只有 0 和 1。
9. 手机号存储用 INT 还是 VARCHAR? ⭐️⭐️⭐️
手机号应该使用 VARCHAR,而不是 INT 或 BIGINT,因为:
- 可能包含开头的
0 - 可能包含国家区号、
+、横杠等字符 - 手机号本质上是标识符,不需要进行数学运算
- 加密后也通常是字符串
常见的长度选择:
如果存储的是加密后的手机号,则应根据加密结果设置更大的长度,例如 VARCHAR(128)。
03 Mysql 的基础架构
从来没人问过,但是理解这个也有点用用处吧
MySQL 的整体架构分为三层:连接层、服务层(Server 层)、存储引擎层。
- 连接层:负责客户端连接、身份认证和权限校验。
-
Server 层:负责 SQL 的解析、优化和执行,主要包括:
- 解析器:进行词法分析和语法分析。
- 优化器:生成执行计划,例如选择索引和表连接顺序。
- 执行器:根据执行计划调用存储引擎接口。
-
存储引擎层:负责数据的实际读写,不同存储引擎有不同的实现方式,常用的是 InnoDB。
- 文件系统:存储引擎最终将数据、索引和日志保存为操作系统中的文件。
04 Mysql 存储引擎
这里也几乎没人问,但是稍微了解一些吧
01 Mysql 支持哪些存储引擎呢?⭐⭐⭐
在 Mysql 中,我们可以通过 show engines 来查看支持的存储引擎,
默认的存储引擎是 InnoDB,并且它也是唯一支持 ACID 级别事务的存储引擎。还支持 MyIsam,Memory 等,具体可以通过 show engines 来查看
02 常见存储引擎以及它们的区别?
- InnoDB:MySQL 默认存储引擎,支持事务、行级锁、MVCC、外键和崩溃恢复,适合绝大多数业务。
- MyISAM:不支持事务和行级锁,适合读多写少的非事务场景,但现在已经很少作为首选。
- Memory:数据存储在内存中,读写速度快,但服务重启后数据会丢失,通常用于临时表或临时数据。
03 Mysql 存储引擎架构了解吗?
MySQL 使用插件式存储引擎架构,存储引擎是基于表的,同一个数据库中的不同表可以使用不同的存储引擎。
04 MyISAM 和 InnoDB 有什么区别?⭐⭐⭐
- MyISAM 不支持行级锁,而 InnoDB 支持行级锁,因此InnoDB的并发性能更好!
- MyISAM 不支持事务,而 InnoDB 支持 ACID 级别的事务
- MyISAM 不支持外键,而 InnoDB 支持。
- MyISAM 不支持数据库异常崩溃后的安全恢复,而
InnoDB支持,这个恢复过程依赖于redo log - InnoDB 引擎中,其数据文件本身就是索引文件。相比 MyISAM,索引文件和数据文件是分离的,InnoDB 表数据文件本身就是按 B+Tree 组织的一个索引结构,树的叶节点 data 域保存了完整的数据记录。
05 Mysql 索引 ⭐️⭐️⭐️
这里全篇都是重点,在我之前的后端面试过程中,每次面试,只要问到八股,那这里大概率会被问到。
1. 索引是什么?
索引实际上就是一种用于快速查询和检索数据的数据结构,在 Mysql,索引其实就是把在磁盘上的数据按照某种数据结构组织起来,从而减少每次查询数据的磁盘 IO 数,因为相比在内存中,一次磁盘读写可是太慢了。
这里可以提一嘴,内存比固态大概快 \(1e^3\) 倍,比机械盘快了 \(1e^6\)
- 极大的减少了磁盘的 IO 数,从 \(O(n)\) 优化到了 \(O(logn)\)
- 可以通过唯一索引保证数据的唯一性,比如主键id,邮箱等等。
- 索引也可以加速排序和分组
但是索引需要占用存储空间,维护索引也需要时间代价
2. 用了索引就一定提升查询性能吗?
大多数情况下,合理使用索引确实比全表扫描快得多。但也有例外:
- 数据量太小:如果表里的数据非常少(比如就几百条),全表扫描可能比通过索引查找更快,因为走索引本身也有开销。
- 查询结果集占比过大:如果要查询的数据占了整张表的大部分(比如超过 20%-30%),优化器可能会认为全表扫描更划算,因为通过索引多次回表(随机 I/O)的成本可能高于一次顺序的全表扫描。
3. 为什么 InnoDB 没有使用哈希作为索引的数据结构?
哈希索引的底层是哈希表。它的优点是,在进行精确的等值查询时,理论上时间复杂度是 O(1) ,速度极快。比如 WHERE id = 123。
但是,它有几个对于通用数据库来说是致命的缺点:
- 不支持范围查询: 这是最主要的原因。哈希函数的一个特点是它会把相邻的输入值(比如
id=100和id=101)映射到哈希表中完全不相邻的位置。这种顺序的破坏,使得我们无法处理像WHERE age > 30或BETWEEN 100 AND 200这样的范围查询。要完成这种查询,哈希索引只能退化为全表扫描。 - 不支持排序: 同理,因为哈希值是无序的,所以我们无法利用哈希索引来优化
ORDER BY子句。 - 不支持部分索引键查询: 对于联合索引,比如
(col1, col2),哈希索引必须使用所有索引列进行查询,它无法单独利用col1来加速查询。
4. 为什么 InnoDB 没有使用 B 树作为索引的数据结构?
我们从本质出发去解答这个问题,首先索引的核心目的是提高查询效率,虽然它们都是性能比较优秀的多路平衡搜索树,但是 B 树会有下面的问题:
1、由于 b 树的非叶子节点不仅仅存指针,还要存数据,所以每个节点能存储的指针数量就会变少,这就会导致树的高度比 B+ 树要高一些。又因为磁盘 io 次数正比于树高,所以 b 树平均的磁盘 io 是大于 b+ 树的。
2、其次,由于数据会存放在非叶子节点,所以它就没法像 b+ 树那样将所有数据组织成一个双向链表,所以对于范围查询,b树的效率不算高,而 b+ 树则对范围查询非常友好,我们只需要定位到起点,之后就可以通过遍历双向链表去完成范围查询了。
3、还是因为 B 树的数据会存放到非叶子节点,所以它的查询性能是不稳定的,而我们的 B+ 树的所有数据都在叶子节点,所以查询性能非常稳定。
5. 什么是覆盖索引
如果一个非聚簇索引包含类本次要查询的所有字段,那么就称之为 覆盖索引(Covering Index)。在 InnoDB 引擎中,只有主键索引的叶子节点会存放完整记录,其他二级索引只会存 主键id + 索引字段
6. 什么是联合索引,什么是最左前缀匹配?
用表中的多个字段创建索引,就是 联合索引,也叫 组合索引 或 复合索引。
最左前缀原则是指:使用联合索引时,查询条件需要从索引最左侧的字段开始匹配。
7. Select * 会导致索引失效吗?
SELECT * 不会直接导致索引失效(如果不走索引大概率是因为 where 查询范围过大导致的),但它可能会导致回表,从而提升了走索引的开销,当查询的数据很多时,Mysql 优化器就可能选择全表扫描。
8. 哪些字段适合创建索引?⭐️
- 频繁被查询的字段
- 区分度高,不为 null 的字段
- 频繁出现在 where、order by、group by 关键字后面的字段
- 作为被驱动表,常被用来做关联的字段
9. 索引失效的常见原因⭐️
- 在查询条件中,联合索引的使用没有遵循最左前缀匹配原则
- 在索引列上进行了计算,函数,类型转换等操作(索引树记录的是字段的原始值)
- 做了左模糊查询 (like "%xx")
- 查询条件中使用 OR,且 OR 的前后条件中有一个列没有索引,涉及的索引都不会被使用到;
- IN 的取值范围较大或者 where 条件查询的结果过大时会导致索引失效,走全表扫描(NOT IN 和 IN 的失效场景相同);
10. Mysql 查询缓存⭐️⭐️
MySQL 查询缓存会将 SQL 语句作为 key,将查询结果作为 value 保存。下次执行完全相同的 SQL 时,可以直接返回缓存结果。
但是,这种缓存机制非常鸡肋,如果 sql 语句有一点点变化,或者结果集有一点点变化,都会导致无法命中缓存,因此,现在的性能担当是存储引擎层的 Buffer Pool(缓冲池) 机制。而是“把热点磁盘数据搬到内存里”。
11. Buffer Pool 机制⭐️
存储单位:它不存 SQL 语句,而是存 数据页 (Page)。磁盘上的一页默认为 16KB,读到内存里也是 16KB。
读操作:当你查询某行数据时,InnoDB 先看 Buffer Pool 里有没有该行所在的“页”。如果有,直接内存读取(微秒级);如果没有,再去磁盘读(毫秒级),并顺便把这个页缓存在 Buffer Pool 里。
写操作:当你修改数据时,先修改 Buffer Pool 里的页(此时叫脏页),并记录日志。后台线程会找时机把脏页刷回磁盘。
06 Mysql 事务 ⭐️⭐️⭐
全部都是重点!!
1. 什么是事务
何为事务? 一言蔽之,事务是一组操作的集合。
2. 什么是数据库事务?
数据库事务其实就是多条 sql 语句构成的一个集合,这些 sql 语句要么全部执行成功,要么全部执行失败。
3. ACID 特性
- 原子性(
Atomicity):事务是最小的执行单位,不允许分割。事务内的操作要么全部执行成功,要么读不执行。 - 一致性(
Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的; - 隔离性(
Isolation):并发执行的各个事务是相互独立的,互不干扰的! - 持久性(
Durability):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
4. 字节一面:Mysql 原子性的原理是什么?
在 MySQL 的 InnoDB 引擎中,实现原子性的核心机制是 undo log(回滚日志)。
当你执行任何修改操作(INSERT、UPDATE、DELETE)时,InnoDB 都会在修改数据之前,先记录一条对应的“相反”的日志 。
当事务运行过程中出现意外(比如服务器宕机、断电)或者你手动执行了 ROLLBACK 命令时,MySQL 就会利用这些 undo log 将数据“撤销”到事务开始之前的样子。
- 主动回滚:当用户执行
ROLLBACK时,InnoDB 会根据事务 ID 找到对应的所有 undo log 记录,按照从后往前的顺序执行逆向操作,从而恢复原始数据。 - 崩溃恢复(Crash Recovery):如果数据库在事务提交前宕机,重启后 InnoDB 会扫描事务状态。发现某些事务只有“开始”标识而没有“提交”标识,就会利用 undo log 自动进行回滚。
5. 什么是 undo log
Undo Log 是用于事务回滚和 MVCC 的日志,主要记录数据修改前的状态或相应的反向操作。undo log 是为了向后退和读取旧版本数据。
6. 什么是 redo log
Redo Log 是用于崩溃恢复的日志,记录数据页发生的物理修改。数据库发生崩溃并重启后,InnoDB 可以根据 Redo Log 重新执行未写入磁盘的数据修改,从而保证已提交事务的数据不会丢失。
7. undo log 与 redo log 的区别?
简单来说:redo log 是为了放心的“向前走”(保证提交了就不丢),undo log 是为了向后退和读取旧版本数据。
8. 为什么 undo log 是逻辑的,而 redo log 必须是物理的?”
undo log 必须是逻辑的:因为回滚时,数据库可能已经发生了其他并发事务。如果 undo log 是物理的(记录某个位置的二进制),直接覆盖回去可能会破坏其他事务已经改好的数据。所以它必须记录“逻辑操作”,通过执行反向 SQL 的方式来恢复,这样更安全。
redo log 必须是物理的:因为物理日志的恢复速度极快。在数据库崩溃恢复(Crash Recovery)时,MySQL 只需要按照物理日志在对应的内存位置“重填”数据即可,不需要像逻辑日志那样重新执行一遍 SQL 的解析、优化和执行过程。
9. 字节一面:为什么断电后重启,任然能通过 undo log 日志实现未提交事务的回滚!?⭐️⭐️⭐️
MySQL 使用 Redo Log + Undo Log 进行崩溃恢复:
- Redo Log 恢复数据页:重启后,MySQL 会将已经记录在 Redo Log、但尚未写入数据页的修改补写进去,恢复断电前的数据状态。
- Undo Log 回滚未提交事务:MySQL 找出断电前未提交的事务,再根据 Undo Log 中记录的旧值或反向操作,将这些事务的修改撤销。
10. 并发事务带来的问题
并发事务带来的问题主要有:脏读、不可重复读、幻读等问题。
脏读
一个事务读取了另一个事务尚未提交的数据,随后另一个事务回滚,导致前一个事务读到了无效数据。
不可重复读
同一事务内多次读取同一数据结果不一致,这是因为会有其他事物对当前记录做修改。
幻读
同一个事务中,两次相同的查询,返回的记录数量不同,因为另一个事务插入或删除了符合条件的记录。
11. 并发事务的控制方法有哪些?
MySQL 中并发事务的控制方式无非就两种:锁 和 MVCC。锁可以看作是悲观控制的模式,多版本并发控制(MVCC,Multiversion concurrency control)可以看作是乐观控制的模。
12. 锁机制
- 行级锁(Row Lock):只锁定指定记录,并发度较高,但管理成本较高,可能发生死锁。
- 表级锁(Table Lock):锁定整张表,开销较小,但并发能力较差。
- 意向锁(Intention Lock):表级锁,用于表示事务打算对表中的某些记录加行锁,方便快速判断表中是否存在行锁。
- 共享锁(S 锁/读锁):用于读数据,多个事务可以同时持有共享锁,但会阻塞其他事务加排他锁。
- 排他锁(X 锁/写锁):用于修改数据,持有排他锁时,其他事务不能再加与之冲突的锁。
13. MVCC 是什么?
MVCC 就是:为同一条数据保存多个历史版本,让不同事务读取自己可见的版本。
- 隐藏列:每行数据都有两个隐藏字段:
DB_TRX_ID(最后修改该行的事务 ID)和DB_ROLL_PTR(回滚指针)。 - Undo Log(回滚日志):存储数据的历史版本,并通过回滚指针连接成版本链。
- ReadView(一致性视图):事务启动时创建一个快照,根据一套可见性算法判断:版本链中的哪个版本是当前事务可见的。
14. MVCC 实现两种隔离级别的原理
MVCC 主要通过 ReadView、Undo Log 和版本链 实现不同的事务隔离级别。
读视图
读视图主要是用来去控制对于当前读视图的创建者,数据的那些版本是可见的,哪些版本是不可见的。主要字段有:
- creator_trx_id:创建该 ReadView 的事务 ID
- m_ids:创建 ReadView 时,系统中尚未提交的事务 ID 列表
- m_up_limit_id:
m_ids中最小的事务 ID - m_low_limit_id:创建 ReadView 时,系统将要分配的下一个事务 ID
m_up_limit_id划定了活跃事务的下界,m_low_limit_id划定了未来事务的上界,m_ids用来记录当前仍未提交的事务。
可见性判断
假设当前数据版本的事务 ID 为 trx_id:
trx_id < m_up_limit_id:说明该版本由较早的事务生成,通常已经提交,对当前事务可见。trx_id >= m_low_limit_id:说明该版本由 ReadView 创建之后的事务生成,对当前事务不可见。-
m_up_limit_id <= trx_id < m_low_limit_id- 如果
trx_id在m_ids中,说明生成该版本的事务当时尚未提交,不可见。 - 如果
trx_id不在m_ids中,说明该事务在创建 ReadView 前已经提交,可见。
读已提交原理
- 如果
每次执行一致性读之前都会创建新的 ReadView。
可重复读原理
事务第一次执行一致性读时创建 ReadView,之后复用同一个 ReadView。
15. 事务的隔离级别
SQL 标准定义了四种事务隔离级别。隔离级别越高,数据一致性越好,但并发性能通常越低。
- READ UNCOMMITTED(读未提交):可以读取其他事务未提交的数据,可能出现脏读、不可重复读和幻读。
- READ COMMITTED(读已提交):只能读取已提交的数据,可以避免脏读,但仍可能出现不可重复读和幻读。
- REPEATABLE READ(可重复读):同一事务内多次读取同一数据结果一致,可以避免脏读和不可重复读。MySQL InnoDB 默认使用该级别,并通过 MVCC 和 Next-Key Lock 在很大程度上避免幻读。
- SERIALIZABLE(可串行化):强制事务串行执行,可以避免脏读、不可重复读和幻读,但并发性能最低。
07 Mysql 锁⭐️⭐️
InnoDB 的锁通常是边扫描边加锁的。执行更新或删除时,MySQL 会根据执行计划和索引访问路径,对扫描到的记录或间隙加锁。
1. 表级锁和行级锁是什么?有什么区别
- 表级锁:锁定整张表,实现简单,开销较小,但并发性能较差。
- 行级锁:只锁定符合条件的记录或范围,并发性能较高,但管理成本更高,也可能发生死锁。
InnoDB 的行锁实际上是加在索引记录上的,而不是直接加在数据行上。如果 WHERE 条件没有合适的索引,MySQL 可能扫描大量索引记录并加锁,最终表现得接近锁表。因此,执行 UPDATE 和 DELETE 时应尽量确保查询条件能够使用合适的索引。
2. InnoDB 有哪几类行锁?
- 记录锁(Record Lock):锁定单条索引记录。
- 间隙锁(Gap Lock):锁定索引记录之间的间隙,不锁定记录本身,主要用于阻止其他事务插入数据。
- 临键锁(Next-Key Lock):记录锁和间隙锁的组合,锁定一个左开右闭的索引区间。
在 RR 隔离级别下,范围查询可能使用 Next-Key Lock 来防止其他事务插入符合条件的记录,从而减少当前读中的幻读。
3. Next-Key Lock 什么时候退化?
使用唯一索引或主键进行等值查询,并且能够准确定位到存在的记录时,Next-Key Lock 通常会退化为记录锁。
因为主键具有唯一性,不可能再插入一条 id = 10 的记录,所以不需要额外锁住相邻间隙。
4. 共享锁和排他锁?
- 共享锁(S 锁):多个事务可以同时持有,但会阻止其他事务获取排他锁。
- 排他锁(X 锁):获取后会阻止其他事务获取冲突的共享锁或排他锁,通常用于修改数据。
普通 SELECT 通常是快照读,不加锁。需要锁定读取时,可以使用:
5. 意向锁有什么作用呢?
意向锁是表级锁,用来表示事务准备对表中的记录加行锁。
- 准备加行级共享锁时,先加意向共享锁(IS)
- 准备加行级排他锁时,先加意向排他锁(IX)
它的作用是让表锁和行锁能够快速判断是否冲突。加表锁时,MySQL 只需要检查表上的意向锁,不必逐行检查整张表。
6. 当前读和快照读?
快照读就是最普通的 SELECT 语句,不加锁,而是基于 MVCC 实现读写互不影响的,MVCC 可以实现读已提交和可重复读**两种隔离级别!
当前读读取数据的最新版本,并且通常会加锁:
UPDATE、DELETE 和 INSERT 等修改操作也属于当前读范畴。
7. 字节一面:Mysql 有哪些隐式锁呢?
隐式锁是 InnoDB 在执行事务操作时自动产生的锁,不需要显式执行 LOCK 语句。常见的自动加锁行为包括:
- 行锁:增删改时,或者 selete + for update 自动添加
SELECT ... FOR UPDATE自动加排他锁SELECT ... FOR SHARE自动加共享锁- RR 隔离级别下的范围操作可能加间隙锁或 Next-Key Lock
- 插入意向锁:INSERT 前自动加,保证并发插入安全
08 Mysql 性能优化⭐️
1. 如何分析 SQL 性能
我们可以使用 EXPLAIN 命令来分析 SQL 的 执行计划 。执行计划是指一条 SQL 语句在经过 MySQL 查询优化器的优化会后,具体的执行方式。
2. 如何优化 MySQL 性能
先定位问题,再优化 SQL 和索引,最后考虑架构和硬件。
1. 抓住核心:慢 SQL 定位与分析
- 开启慢查询日志,用
mysqldumpslow分析高频慢 SQL
-- 开启慢查询日志开关
SET GLOBAL slow_query_log = 'ON';
-- 设置慢查询阈值(例如超过 1 秒就算慢查询)
SET GLOBAL long_query_time = 1;
-- (可选)记录没有使用索引的 SQL
SET GLOBAL log_queries_not_using_indexes = 'ON';
# 查看执行时间最慢的前 10 条 SQL(最常用)
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# 查看执行次数最多的前 10 条高频慢 SQL
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
- 用
EXPLAIN查看执行计划,重点关注type(是否全表扫描)和Extra(是否 Using filesort)
2. 索引、表结构和 SQL 优化
- 加索引:遵循最左前缀原则,覆盖索引减少回表,避免索引失效场景
- 表结构:字段尽量
NOT NULL,避免冗余列,大字段拆分 - SQL 写法:只
SELECT需要的列,避免SELECT *,IN替换OR
3. 进阶方案:架构优化
- 读写分离:主库写,从库读,通过中间件(ShardingSphere)分发请求
- 分库分表:单表超 500 万行时水平拆分,降低单表数据量
- 引入缓存:热点数据前置到 Redis,减少数据库直接压力
4. 其他优化手段
- 合理设置 Buffer Pool 大小
- 优化磁盘、内存和 CPU 等硬件资源