查询关键字执行先后顺序
-
FROM(及 JOIN
) -
WHERE
-
GROUP BY
-
HAVING
-
SELECT
-
DISTINCT
-
ORDER BY
-
LIMIT / OFFSET
CHAR 和 VARCHAR 的区别?使用场景?
特性 | CHAR | VARCHAR |
---|---|---|
存储方式 | 定长,存储时填充空格至定义长度 | 变长,存储实际数据 + 长度前缀 |
空间占用 | 固定(可能浪费空间) | 动态(节省空间) |
读取性能 | 高(无需解析长度,直接读取固定长度) | 较低(需解析长度前缀) |
适用场景 | 长度固定的字段(如编码、枚举) | 长度不固定的文本(如描述、地址) |
MySQL窗口函数是什么
对数据集划分窗口(比如按组、按排序范围),在窗口内计算并返回每行对应的结果,不聚合数据,保留所有行
explain语句执行后生成的表重要字段含义
字段 | 含义 | 常见取值 / 说明 |
---|---|---|
type | 访问类型(效率从好到差) | system > const > eq_ref > ref > range > index > ALL |
key | 实际使用的索引 | 索引名,如 idx_amount ;NULL 表示未命中索引(全表扫描) |
rows | 优化器估算需扫描的行数 | 数值越大,意味着扫描量越大,通常要尽量降低 |
Extra | 额外操作信息 | 如 Using where 、Using index (覆盖索引)、Using filesort 、Using temporary 等 |
索引是什么?有什么好处?
-
是一种能高效获取数据的数据结构
-
可以提高数据检索效率,降低数据库的
I/O
成本 -
可以对数据进行排序,降低数据排序的成本,减少CPU的消耗
MySQL 索引失效的情况
- 模糊匹配时
%
开头
SELECT * FROM tbl WHERE name LIKE '%ohn';
- 对列进行函数运算或表达式计算
SELECT * FROM tbl WHERE DATE(created_at) = '2025-06-27';
- 字符串值不加引号,索引失效
-- phone 不加引号,索引失效
explain select * from tb_user where phone = 17799990015;
or
两边条件,一边有索引,一边无索引,索引失效
-- id 有索引、age 无索引,索引失效
explain select * from tb_user where id = 10 or age = 23;
MySQL索引使用会出现什么问题?该怎么解决?
问题:
-
索引维护成本高,影响写入性能, 解决: 减少索引数量, 批量提交写入操作,减少索引更新次数
-
索引未被使用(索引失效), 解决: 优化查询语句
-
索引占用过多磁盘空间 , 解决: 精简索引字段,清除无用索引
事务四大特性(ACID)及实现原理
特性 | 描述 | 实现原理 |
---|---|---|
原子性 | 事务要么全部成功,要么全部回滚 | 通过回滚日志(Undo Log )实现 |
一致性 | 事务执行前后数据库的完整性约束不变 | 通过持久性+原子性+隔离性实现 |
隔离性 | 并发事务之间互不干扰 | 通过锁机制和 MVCC (多版本并发控制)实现 |
持久性 | 事务提交后数据永久保存 | 通过重做日志(Redo Log )实现 |
并发事务问题
并发事务可能导致脏读、不可重复读和幻读
- 脏读是指一个事务读到了另一个事务未提交的“脏数据”
- 不可重复读是指在一个事务内多次读取同一数据,由于其他事务的修改导致数据不一致
- 幻读是指一个事务读取到了其他事务插入的“幻行”
事务隔离级别及实现原理
隔离级别 | 脏读 | 不可重复读 | 幻读 | 实现原理 |
---|---|---|---|---|
读未提交 | ✔ | ✔ | ✔ | 无锁,直接读取最新数据(包括未提交的数据) |
读已提交 | ✘ | ✔ | ✔ | MVCC:每次查询生成独立的ReadView,仅读取已提交的数据版本 |
可重复读 | ✘ | ✘ | ✔ | MVCC:事务首次查询生成ReadView,后续复用该视图(MySQL默认隔离级别 ) |
串行化 | ✘ | ✘ | ✘ | 锁机制:所有操作加锁,事务串行执行 |
事务隔离级别,每个级别会引发什么问题,MySQL 默认是哪个级别?
MySQL
默认事务隔离级别是可重复读
事务隔离级别引发的问题:
隔离级别 | 描述 | 可能出现的问题 |
---|---|---|
READ UNCOMMITTED (读未提交) | 允许读取其他事务未提交的数据。 | 脏读、不可重复读、幻读 |
READ COMMITTED (读已提交) | 只能读取其他事务已提交的数据。 | 不可重复读、幻读 |
REPEATABLE READ (可重复读) | 同一事务中多次读取的数据一致。 | 幻读 |
SERIALIZABLE (串行化) | 强制事务串行执行,完全隔离。 | 无,但性能较低,可能导致并发性差 |
MySQL 常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?
特性 | InnoDB | MyISAM | MEMORY |
---|---|---|---|
事务 | 支持 | 不支持 | 不支持 |
锁机制 | 支持行级锁, 适合高并发读写场景 | 支持表级锁,适合读多写少、简单查询场景 | 支持表级锁,适合临时高速缓存表 |
外键与完整性 | 支持外键约束 | 不支持外键 | 不支持外键 |
崩溃恢复 | 支持崩溃恢复 | 无崩溃恢复机制 | 不支持恢复 |
-
InnoDB
从MySQL 5.5
开始为默认存储引擎,综合事务处理能力和恢复性能最好。适合高并发读写、事务处理要求高的场景 -
MyISAM
适合读操作多、写操作较少, 对事务和数据完整性要求不高的场景 -
MEMORY
引擎速度最快,只作为短期缓存或临时表使用,不用于持久化业务数据
什么是聚簇索引什么是非聚簇索引?
-
聚簇索引是指数据与索引放在一起,
B+
树的叶子节点保存了整行数据,通常只有一个聚簇索引,一般是由主键构成 -
非聚簇索引则是数据与索引分开存储,B+树的叶子节点保存的是主键值,可以有多个非聚簇索引
回表查询是什么?
指的是通过二级索引找到对应的主键值,然后再通过主键值查询聚簇索引中对应的整行数据的过程
MySQL 中为什么推荐使用连接查询而不是子查询?
连接查询比子查询更高效、可读性更好, 因为连接查询不需要额外的中间临时表,但是子查询有中间临时表
什么叫覆盖索引?
-
指的是在
SELECT
查询中,返回的列都能在索引中找到 -
好处: 避免了回表查询,提高了性能。使用覆盖索引可以减少对主键索引的查询次数,提高查询效率
表的查询速度很慢,怎么解决?
-
使用
explain
分析sql
语句,找出原因 -
创建, 优化索引
-
优化数据库表,如果表数据量过大,可以拆成多张表
-
使用缓存
索引创建原则?
-
表中的数据量超过
10万
以上时考虑创建索引 -
选择查询频繁的字段作为索引,如查询条件、排序字段或分组字段
-
对于内容较长的字段使用前缀索引
-
控制索引数量,虽然索引可以提高查询速度,但会影响插入、更新的速度
-
尽量使用联合索引,覆盖
SQL
的返回值, 比如查询WHERE user_id=100 AND status=1
,创建(user_id, status)
的联合索引,比单独给两个字段建索引更能精准定位数据, 如果复合索引包含了 SELECT 语句需要返回的所有字段(如SELECT id, name FROM t WHERE user_id=100
,索引设为(user_id, id, name)
),数据库可以直接从索引中获取数据,无需再去表中查询(避免 “回表” 操作),大幅减少 IO 开销
SQL的优化手段
-
建表时选择合适的字段类型
-
使用索引,优化索引
-
编写高效的SQL语句,比如避免使用
SELECT *
,尽量使用UNION ALL
代替UNION
,以及在表关联时使用INNER JOIN
-
采用主从复制和读写分离提高性能
-
在数据量大时考虑分库分表
MySQL的binlog
- 二进制日志,记录所有数据库的写操作(
DDL/DML
) - 作用:主从复制(数据同步), 数据恢复(通过
mysqlbinlog
工具回放日志)
undo log 和 redo log 的区别是什么?
redo log
记录的是数据页的物理变化,用于服务宕机后的恢复,保证事务的持久性undo log
记录的是逻辑日志,用于事务回滚时恢复原始数据,保证事务的原子性和一致性
为什么使用B+ 树作为索引?而不用哈希表或二叉树
B+ 树
优势:
-
B + 树
的高度低, 磁盘IO
次数少 -
查询高效, 叶子节点形成有序链表,能够快速遍历
-
查询效率稳定, 所有查询路径长度相同,时间复杂度稳定为
O(log n)
对比其他结构:
-
哈希表不支持范围查询,哈希冲突影响性能
-
二叉树:树高较高,I/O次数多,可能退化为链表
日志与恢复
日志 | 作用 | 应用场景 |
---|---|---|
Redo Log | 记录事务对数据页的物理修改,保证持久性。 | 崩溃恢复时重放未刷盘的修改。 |
Undo Log | 记录事务前的数据逻辑状态,用于回滚和MVCC。 | 事务回滚、多版本读。 |
BinLog | 记录所有数据库写操作(逻辑日志),用于主从复制和数据恢复。 | 数据同步(如MySQL主从)、数据恢复。 |
事务中的隔离性是如何保证的呢?(解释下MVCC)
事务的隔离性通过锁和多版本并发控制(MVCC)来保证。MVCC 通过维护数据的多个版本来避免读写冲突。底层实现包括隐藏字段、undo log
和read view
。隐藏字段包括trx_id
和roll_pointer
。undo log
记录了不同版本的数据,通过roll_pointer
形成版本链。read view
定义了不同隔离级别下的快照读,决定了事务访问哪个版本的数据。
MySQL主从同步原理是什么?
MySQL主从复制的核心是二进制日志(Binlog)。步骤如下:
-
主库在事务提交时记录数据变更到Binlog
-
从库读取主库的Binlog并写入中继日志(Relay Log)
-
从库重做中继日志中的事件,反映到自己的数据中
执行一条SQL的流程
- 连接器:验证用户权限,建立连接
- 查询缓存:检查缓存(MySQL 8.0已移除)
- 解析器:语法分析,生成抽象语法树(AST)
- 优化器:选择最优执行计划(如索引选择、JOIN顺序)
- 执行器:调用存储引擎接口执行计划
- 存储引擎(如InnoDB):
- 从内存(Buffer Pool)或磁盘读取数据
- 写入Redo Log和Undo Log
- 返回结果:将结果返回客户端
如何在MySQL中查看慢查询?
-
开启慢查询日志
-
使用
SHOW PROCESSLIST
实时监控