数据库基础与 MySQL 概览
❓ 面试官:能说说关系型数据库和非关系型数据库的区别吗?
频率:🔥🔥🔥
💡 一句话总结(先抛结论): 关系型数据库(如 MySQL)数据结构严谨、支持事务和强一致性,适合存储核心业务数据;非关系型数据库(NoSQL,如 Redis、MongoDB)数据结构灵活、读写性能极高、易于扩展,适合存储缓存、日志或海量非结构化数据。
📝 详细原理解析:
- 关系型数据库(RDBMS):
- 代表:MySQL、Oracle、PostgreSQL。
- 特点:以表格形式存储数据,表与表之间有明确的关联关系;支持复杂的 SQL 查询;支持 ACID 事务特性,保证数据的绝对一致性。
- 痛点:高并发读写性能遇到瓶颈,海量数据的横向扩展(分库分表)成本很高。
- 非关系型数据库(NoSQL):
- 代表:Redis(键值)、MongoDB(文档)、Elasticsearch(搜索引擎)、HBase(列族)。
- 特点:数据结构不固定(JSON、Key-Value 等);不强求 ACID,通常只保证最终一致性(BASE 理论);天生为分布式设计,横向扩展极容易。
- 痛点:不支持复杂的表关联查询,数据一致性较弱。
🌟 面试加分项(实战经验): 在实际项目中,我们绝对不会只用一种数据库,而是混合架构。比如在电商系统中:
- 订单、支付等核心钱款数据:存入 MySQL(保证强一致性)。
- 商品详情、首页轮播图等高频只读数据:存入 Redis(抗高并发)。
- 海量商品搜索、多条件筛选:存入 Elasticsearch(解决 MySQL 模糊查询不走索引的问题)。
- 海量操作日志:存入 MongoDB 或 HBase(解决关系型数据库容量问题)。
❓ 面试官:MySQL 中 InnoDB 和 MyISAM 引擎有什么区别?
频率:🔥🔥🔥🔥
💡 一句话总结(先抛结论): InnoDB 支持事务、支持外键、支持行级锁,是 MySQL 默认的首选引擎;而 MyISAM 不支持事务和外键,只支持表锁,但查询速度快。
📝 详细对比:
| 特性对比 | InnoDB(MySQL 5.5+ 默认) | MyISAM |
|---|---|---|
| 事务支持 | ✅ 支持 ACID 事务 | ❌ 不支持 |
| 锁的粒度 | 支持行锁(并发高) | 仅支持表锁(并发低) |
| 外键支持 | ✅ 支持 | ❌ 不支持 |
| MVCC | ✅ 支持 | ❌ 不支持 |
| 崩溃恢复 | ✅ 支持(Redo Log 安全恢复) | ❌ 不支持,挂了容易丢数据 |
| 索引结构 | 聚簇索引(数据和主键索引绑在一起) | 非聚簇索引(索引和数据文件分离) |
| COUNT(*) | 需扫描全表计算(慢) | 内部维护了一个计数器,直接返回(快) |
🌟 面试加分项(实战经验): 面试官可能会问:"现在还有必要用 MyISAM 吗?" 答:在极少数几乎没有更新操作、只有读操作、且不在乎丢失数据的报表或归档日志表中,可以考虑 MyISAM。但在目前绝大多数企业级开发中,我们统一要求全部使用 InnoDB。因为在 MySQL 8.0 之后,InnoDB 的查询性能已经优化得极好,且数据的安全性和并发写入能力是 MyISAM 无法比拟的。
❓ 面试官:能说说一条 SQL 查询语句在 MySQL 中的执行流程吗?
频率:🔥🔥🔥🔥
💡 一句话总结(先抛结论): 一条查询 SQL 会依次经过:客户端 -> 连接器 -> 查询缓存(MySQL 8.0 已废弃) -> 解析器 -> 优化器 -> 执行器 -> 存储引擎(InnoDB),最终把数据返回给客户端。
📝 详细原理解析:
- 连接器:负责跟客户端建立 TCP 连接、获取权限、维持和管理连接。
- 查询缓存:如果 SQL 命中缓存直接返回。但由于只要表一更新缓存就会失效,命中率极低,MySQL 8.0 已经彻底删除了这个功能。
- 解析器:进行词法分析(识别出 select、表明、列名)和语法分析(检查 SQL 是否写错了)。
- 优化器(核心):如果表里有多个索引,优化器负责决定使用哪个索引;如果是多表 JOIN,优化器决定各个表的连接顺序。最终生成最优的"执行计划"。
- 执行器:校验用户对该表的查询权限,然后根据执行计划,调用存储引擎的 API 接口去获取数据。
- 存储引擎:实际负责数据的存取(如 InnoDB),从磁盘/内存中查出数据返回给执行器。
🌟 面试加分项(实战经验): 了解这个流程对排查问题很有帮助。比如线上偶尔遇到 Access denied,说明在连接器阶段权限就被拒绝了;如果遇到 You have an error in your SQL syntax,这是在解析器阶段报错了;如果是明明有更好的索引但 MySQL 选错了(导致慢查询),那就是优化器阶段做出了错误的预估,我们可以用 FORCE INDEX 来强制干预优化器的选择。
❓ 面试官:什么是三大范式?在实际开发中一定要严格遵守吗?
频率:🔥🔥
💡 一句话总结(先抛结论): 三大范式是为了减少数据冗余设计的。第一范式要求列不可拆分,第二范式要求消除部分依赖,第三范式要求消除传递依赖。但在实际高并发开发中,我们通常会反范式设计,用空间换时间。
📝 详细原理解析:
- 第一范式(1NF):属性(字段)不可再分。比如不能把"省份-城市"作为一个字段存,必须拆分成两个字段。
- 第二范式(2NF):在 1NF 基础上,非主键列必须完全依赖于主键,不能只依赖主键的一部分(主要针对复合主键,普通单列主键天然满足 2NF)。
- 第三范式(3NF):在 2NF 基础上,非主键列必须直接依赖主键,不能存在传递依赖。比如:订单表里有
user_id,就不应该再存user_name(因为 name 依赖 id,id 依赖订单主键)。
🌟 面试加分项(实战经验): 严格遵守三范式会导致表分得非常细。在查询一个订单详情时,可能需要 JOIN 订单表、用户表、商品表、商家表等四五张表,这对数据库性能是毁灭性的打击。 所以在实际互联网开发中,我们普遍采用反范式设计(冗余设计)。 比如在订单表中,我们除了存 user_id,往往还会直接冗余存入下单那一刻的 user_name 和 user_phone,不仅省去了一次 JOIN 查询,还能防止未来用户改了名字导致历史订单信息被篡改。牺牲一点点存储空间,换取查询性能的大幅提升,这在当下是非常划算的。