MySQL 高频面试要点梳理

MySQL 基础概念

1. 何谓MySQL?其具备哪些特性?

MySQL是一款开源的关系型数据库管理系统,由瑞典的MySQL AB公司研发,如今归属于Oracle公司。

其主要特性如下:
- 开源且免费(社区版)
- 运行性能出色,速度较快
- 支持多用户、多线程操作
- 可跨平台运行(涵盖Windows、Linux、Mac等系统)
- 能与多种编程语言进行接口适配
- 遵循标准的SQL数据语言规范
- 提供事务支持以及外键约束功能
- 可应对大型数据库的存储需求
- 具备多种存储引擎可供选择
- 安全性与连接性良好

2. MySQL中的存储引擎有哪些?它们存在何种区别?

常见的存储引擎包括:
- InnoDB:支持事务、行级锁和外键约束,是MySQL 5.5版本以后的默认存储引擎
- MyISAM:不支持事务和行级锁,但查询速度较快
- MEMORY:数据存储于内存中,速度快但关机后数据会丢失
- ARCHIVE:适用于存储大量归档数据
- CSV:以CSV格式存储数据
- BLACKHOLE:接收数据却不进行存储

它们的对比情况如下:

特性 InnoDB MyISAM MEMORY
事务支持
锁机制 行级锁 表级锁 表级锁
外键支持
崩溃恢复
全文索引 是(5.6+)
存储限制 64TB 256TB 内存大小

3. InnoDB与MyISAM的主要区别是什么?

  • 事务支持:InnoDB支持ACID事务,MyISAM不支持事务。
  • 锁级别:InnoDB采用行级锁,MyISAM采用表级锁。
  • 外键约束:InnoDB支持外键,MyISAM不支持外键。
  • 崩溃恢复:InnoDB崩溃后有安全恢复能力,MyISAM崩溃后数据易损坏。
  • 性能特点:InnoDB写操作性能较好,MyISAM读操作性能较好。
  • 存储结构:InnoDB是聚簇索引,MyISAM是非聚簇索引。

4. 什么是事务?MySQL如何支持事务?

事务定义:事务是一组原子性的SQL查询,要么全部执行成功,要么全部失败回滚。

MySQL对事务的支持:通过InnoDB等支持事务的存储引擎来实现。默认处于自动提交(auto-commit)模式,可使用 SET autocommit=0 来关闭自动提交。其操作示例如下:

START TRANSACTION;
-- 此处放置SQL语句
COMMIT;  -- 提交事务
-- 或者
ROLLBACK; -- 回滚事务

ACID原则详解

ACID原则是事务的四个基本特性:

1. Atomicity(原子性)

事务是不可分割的工作单元,事务中的操作要么全部完成,要么全部不完成,失败时会自动回滚所有操作。

2. Consistency(一致性)

事务执行前后,数据库从一个一致状态转变为另一个一致状态,不会破坏数据库的完整性约束,例如转账前后总金额保持不变。

3. Isolation(隔离性)

多个事务并发执行时互不干扰,通过隔离级别来控制,隔离级别包括读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)、串行化(Serializable),防止出现脏读、不可重复读和幻读问题。

4. Durability(持久性)

事务提交后,修改将永久保存,即使系统崩溃,数据也不会丢失,通过事务日志和恢复机制来保证。

MySQL 数据库设计

1. 主键、外键和索引分别是什么?

主键(Primary Key)
  • 定义:是唯一标识表中每行记录的列或列组合,不允许NULL值,每个表只能有一个主键。
  • 特点:保证实体完整性,自动创建聚集索引(在InnoDB中),常用自增整数(AUTO_INCREMENT)作为主键。
外键(Foreign Key)
  • 定义:是建立两个表数据之间关联的字段,引用另一个表的主键,保证引用完整性。
  • 特点:防止无效数据插入,可设置级联操作(CASCADE),InnoDB支持,MyISAM不支持。
索引(Index)
  • 定义:是提高查询性能的数据结构,类似书籍的目录。
  • 类型:包括普通索引、唯一索引、主键索引、组合索引、全文索引等。

2. 数据库范式是什么?通常设计到第几范式?

数据库范式定义:是规范化数据库设计的指导原则,用于减少数据冗余,提高数据一致性。

主要范式
- 1NF:属性具有原子性,无重复组,需消除重复列。
- 2NF:满足1NF,且非主属性完全依赖主键,需消除部分依赖。
- 3NF:满足2NF,且消除传递依赖,需消除非主属性间的依赖。
- BCNF:是更强的3NF,需消除主属性对候选键的部分依赖。

设计建议:通常设计到第三范式(3NF),根据实际性能需求考虑反范式化,关联查询多的场景可适当降低范式级别。

3. 如何优化数据库表结构设计?

结构优化
- 选择合适的数据类型,比如用INT存储数字,用DATETIME/TIMESTAMP存储时间。
- 进行规范化设计,遵循适当的范式级别,合理拆分大表。
- 保持命名规范,使用有意义的表名和字段名,保持命名风格一致。

索引优化
- 为常用查询条件创建索引,避免过度索引(影响写性能),使用组合索引时注意最左前缀原则。

其他优化
- 适当使用垂直/水平分表,考虑使用分区表,为常用查询创建视图。

4. 什么是反范式化设计?何时使用它?

反范式化设计定义:是故意增加冗余数据的设计方法,违反范式原则以提高查询性能。

使用场景
- 读密集场景,如报表系统、数据分析应用。
- 性能关键路径,如高频查询的表、需要快速响应的核心业务。
- 特定技术需求,如数据仓库、OLAP系统。

实现方式:增加冗余字段、使用预计算字段、创建汇总表。

注意事项:需要额外维护数据一致性,适合读多写少的场景,需权衡查询性能与数据一致性。

MySQL SQL查询

1. 解释SELECT语句的执行顺序

SQL查询逻辑执行顺序
1. FROM和JOIN:确定数据来源表。
2. WHERE:筛选符合条件的行。
3. GROUP BY:对数据进行分组。
4. HAVING:筛选分组后的数据。
5. SELECT:选择要返回的列。
6. DISTINCT:去除重复行。
7. ORDER BY:对结果排序。
8. LIMIT/OFFSET:限制返回行数。

实际示例

SELECT DISTINCT column1, COUNT(*) 
FROM table1
JOIN table2 ON table1.id = table2.id
WHERE condition = 'value'
GROUP BY column1
HAVING COUNT(*) > 1
ORDER BY column1
LIMIT 10;

2. JOIN有哪些类型?它们有什么区别?

JOIN类型 语法 描述 结果
INNER JOIN A INNER JOIN B ON A.id=B.id 只返回两表中匹配的行 两表的交集
LEFT JOIN A LEFT JOIN B ON A.id=B.id 返回左表所有行+匹配的右表行 左表全集+匹配部分
RIGHT JOIN A RIGHT JOIN B ON A.id=B.id 返回右表所有行+匹配的左表行 右表全集+匹配部分
FULL JOIN A FULL JOIN B ON A.id=B.id 返回两表所有行(MySQL用UNION实现) 两表的并集
CROSS JOIN A CROSS JOIN B 返回两表的笛卡尔积 所有可能的组合

3. 什么是子查询?有哪些类型的子查询?

子查询定义:嵌套在另一个查询中的SELECT语句。

子查询类型
- WHERE子句中的子查询

sql
SELECT * FROM products
WHERE price > (SELECT AVG(price) FROM products)

  • FROM子句中的子查询(派生表)

sql
SELECT * FROM
(SELECT user_id, COUNT(*) as order_count FROM orders GROUP BY user_id) as user_orders
WHERE order_count > 5

  • SELECT子句中的子查询(标量子查询)

sql
SELECT product_name,
(SELECT COUNT(*) FROM orders WHERE product_id = p.id) as order_count
FROM products p

  • EXISTS/NOT EXISTS子查询

sql
SELECT * FROM customers c
WHERE EXISTS (SELECT 1 FROM orders WHERE customer_id = c.id)

  • IN/NOT IN子查询

sql
SELECT * FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE location = 'NY')

4. 如何优化SQL查询性能?

索引优化
- 合理创建索引,为WHERE、JOIN、ORDER BY字段建立索引,组合索引字段顺序遵循高频查询字段在前、高选择性字段在前的原则。

sql
-- 创建组合索引示例
CREATE INDEX idx_user_status ON users(status, register_date);

  • 避免索引失效场景,如避免对索引列使用函数或运算、避免使用!=或<>操作符、避免使用前导通配符LIKE查询等。

```sql
-- 索引失效的反例
SELECT * FROM users WHERE DATE(create_time) = '2023-01-01';

-- 优化后的正例
SELECT * FROM users WHERE create_time >= '2023-01-01' AND create_time < '2023-01-02';
```

查询优化
- 避免全表扫描,使用LIMIT限制返回行数,避免SELECT *,只查询需要的列。

```sql
-- 全表扫描的反例
SELECT * FROM order_details;

-- 优化后的正例
SELECT order_id, product_id, quantity FROM order_details WHERE order_id = 1001;
```

  • JOIN优化,确保JOIN字段有索引,遵循小表驱动大表的原则。

sql
-- JOIN优化示例
SELECT * FROM small_table s JOIN large_table l ON s.id = l.id;

分页优化

```sql
-- 低效的分页查询
SELECT * FROM large_table LIMIT 100000, 10;

-- 高效的分页查询(使用覆盖索引)
SELECT * FROM large_table WHERE id > 100000 ORDER BY id LIMIT 10;
```

5. EXPLAIN命令是做什么的?如何使用它?

EXPLAIN命令作用:分析SQL查询的执行计划,查看MySQL如何使用索引,识别查询性能瓶颈。

基本使用方法

```sql
-- 基本语法
EXPLAIN SELECT * FROM users WHERE id = 1;

-- 查看详细执行计划(MySQL 8.0+)
EXPLAIN ANALYZE SELECT * FROM orders WHERE amount > 100;
```

关键输出字段
- type:访问类型,从好到差依次为system > const > eq_ref > ref > range > index > ALL。
- key:实际使用的索引。
- rows:预估需要检查的行数。
- Extra:额外信息,如Using index表示使用覆盖索引,Using temporary表示使用临时表,Using filesort表示需要额外排序。

使用案例

```sql
-- 分析查询执行计划
EXPLAIN SELECT u.name, o.order_no
FROM users u JOIN orders o ON u.id = o.user_id
WHERE u.status = 1 AND o.amount > 1000
ORDER BY o.create_time DESC;

-- 优化后添加索引
ALTER TABLE orders ADD INDEX idx_user_amount (user_id, amount);
ALTER TABLE users ADD INDEX idx_status (status);
```

MySQL索引

1. MySQL中有哪些类型的索引?

主要索引类型包括:
- 普通索引:最基本的索引类型,无唯一性限制。
- 唯一索引:索引列的值必须唯一,允许NULL值。
- 主键索引:特殊的唯一索引,不允许NULL值。
- 组合索引:多个列组合创建的索引。
- 全文索引:用于全文搜索。
- 空间索引:用于地理空间数据类型。
- 前缀索引:对字符串前几个字符建立的索引。

sql
-- 创建各类索引示例
CREATE INDEX idx_name ON users(name); -- 普通索引
CREATE UNIQUE INDEX idx_email ON users(email); -- 唯一索引
ALTER TABLE users ADD PRIMARY KEY (id); -- 主键索引
CREATE INDEX idx_name_age ON users(name, age); -- 组合索引

2. 什么是聚簇索引和非聚簇索引?

聚簇索引(Clustered Index)
- 索引和数据存储在一起。
- InnoDB的主键索引就是聚簇索引。
- 一个表只能有一个聚簇索引。
- 物理存储顺序与索引顺序一致。

非聚簇索引(Non-clustered Index)
- 索引和数据分开存储。
- MyISAM使用的都是非聚簇索引。
- 一个表可以有多个非聚簇索引。
- 通过指针指向实际数据位置。

3. 如何创建高效的索引?

高效索引创建原则
- 选择区分度高的列建立索引。
- 频繁作为查询条件的列应建立索引。
- 组合索引遵循最左前缀原则。
- 避免创建过多索引(影响写性能)。
- 尽量使用数据量小的数据类型作为索引。

```sql
-- 高效组合索引示例
CREATE INDEX idx_status_created ON orders(status, created_at);

-- 低效索引示例(区分度低)
CREATE INDEX idx_gender ON users(gender);
```

4. 什么情况下索引会失效?

索引失效常见场景
- 对索引列使用函数或运算。
- 使用!=或<>操作符。
- 使用前导通配符的LIKE查询。
- 隐式类型转换。
- OR条件未全部使用索引。
- 不符合最左前缀原则的组合索引。

sql
-- 索引失效示例
SELECT * FROM users WHERE YEAR(create_time) = 2023; -- 使用函数
SELECT * FROM products WHERE name LIKE '%apple%'; -- 前导通配符
SELECT * FROM orders WHERE amount+100 > 500; -- 对列运算

5. 什么是覆盖索引?

覆盖索引(Covering Index)
- 查询的列都包含在索引中。
- 不需要回表查询数据行。
- 显著提高查询性能。

```sql
-- 覆盖索引示例
CREATE INDEX idx_user_order ON orders(user_id, order_date, amount);

-- 使用覆盖索引的查询
SELECT user_id, order_date FROM orders
WHERE user_id = 1001 AND order_date > '2023-01-01';
```

6. 如何判断一个查询是否使用了索引?

判断方法
- 使用EXPLAIN命令查看执行计划。
- 检查key列是否显示使用的索引名。
- 检查type列是否为ref、range等较好的类型。
- 检查Extra列是否有"Using index"提示。

```sql
-- 检查索引使用情况
EXPLAIN SELECT * FROM users WHERE id = 1001;

-- 强制使用/忽略索引
SELECT * FROM users USE INDEX(idx_name) WHERE name = 'John';
SELECT * FROM users IGNORE INDEX(idx_name) WHERE name = 'John';
```

MySQL性能优化

1. 如何优化MySQL数据库性能?

数据库性能优化策略

服务器配置优化
- 调整innodb_buffer_pool_size(通常设为物理内存的50-70%)。
- 优化query_cache_size(MySQL 8.0已移除查询缓存)。
- 配置合理的max_connections。

SQL优化
- 避免SELECT *,只查询需要的列。
- 使用预处理语句防止SQL注入。
- 合理使用JOIN替代子查询。

**架构

版权声明:程序员胖胖胖虎阿 发表于 2025年6月18日 上午11:07。
转载请注明:

MySQL 高频面试要点梳理

| 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...