1. 什么是关系型数据库?MySQL属于哪种数据库?
**答**:关系型数据库(RDBMS)是建立在关系模型基础上的数据库,它使用表(Table)来存储数据,表由行(Row)和列(Column)组成。数据之间可以存在各种关系(一对一、一对多、多对多)。MySQL是一种开源的关系型数据库管理系统(RDBMS)。
2. SQL有哪些主要类型?
**答**:主要分为四类:
* **DDL (数据定义语言)**:用于定义或修改数据库结构。如 `CREATE`, `ALTER`, `DROP`, `TRUNCATE`。
* **DML (数据操作语言)**:用于对数据进行增删改查。如 `SELECT`, `INSERT`, `UPDATE`, `DELETE`。
* **DCL (数据控制语言)**:用于控制数据库的访问权限。如 `GRANT`, `REVOKE`。
* **TCL (事务控制语言)**:用于管理数据库中的事务。如 `COMMIT`, `ROLLBACK`, `SAVEPOINT`。
3. `CHAR` 和 `VARCHAR` 有什么区别?
**答**:
| 特性 | CHAR | VARCHAR |
| :--- | :--- | :--- |
| **长度** | **固定长度**。定义时指定长度,不足的部分用空格填充。 | **可变长度**。根据实际内容长度存储,再加1-2个字节记录长度。 |
| **存储空间** | 总是占用定义长度的空间(例如 `CHAR(10)` 总是占10个字符的空间)。 | 占用实际数据长度 + 长度标识的空间。 |
| **存取速度** | 由于长度固定,**存取速度更快**。 | 由于需要计算长度,**存取速度稍慢**。 |
| **适用场景** | 存储长度基本固定的数据,如MD5哈希值、身份证号、手机号等。 | 存储长度变化较大的数据,如文章标题、用户名、地址等。 |
4. `INNER JOIN`、`LEFT JOIN`、`RIGHT JOIN` 和 `FULL JOIN` 的区别?
**答**:
* **INNER JOIN(内连接)**:返回两个表中**匹配**的行。
* **LEFT JOIN(左连接)**:返回左表的**所有**行,以及右表中**匹配**的行。如果右表无匹配,则右表部分为NULL。
* **RIGHT JOIN(右连接)**:返回右表的**所有**行,以及左表中**匹配**的行。如果左表无匹配,则左表部分为NULL。
* **FULL JOIN(全外连接)**:返回左表和右表中的所有行。如果某一边没有匹配,另一边则为NULL。**MySQL不直接支持FULL JOIN**,但可以通过 `LEFT JOIN UNION RIGHT JOIN` 来模拟。
二、索引(核心考点)
5. 什么是索引?它的作用和优缺点是什么?
**答**:索引是一种**数据结构**(如B+Tree),帮助MySQL高效获取数据,类似于书的目录。
* **优点**:
* **大大加快数据的检索速度**(最主要优点)。
* 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
* 加速表与表之间的连接。
* **缺点**:
* **需要占用额外的磁盘空间**。
* **会降低数据写入(INSERT/UPDATE/DELETE)的速度**,因为索引也需要同时被维护。
6. MySQL的索引主要使用哪种数据结构?为什么?
**答**:主要使用 **B+Tree**。
* **为什么是B+Tree?**
-
**矮胖树,查询效率高**:B+Tree是一个多路平衡查找树,层级很低(通常3-4层就能存储千万级数据),意味着磁盘I/O次数非常少(每次I/O读取一页)。
-
**适合范围查询**:所有数据都存储在叶子节点,并且叶子节点之间通过指针相连,范围查询只需要遍历链表即可,非常高效。
-
**查询效率稳定**:任何查询都需要从根节点走到叶子节点,查询路径长度相同,效率稳定。
7. 什么是聚簇索引和非聚簇索引?
**答**:
* **聚簇索引(Clustered Index)**:**表数据本身就按索引结构存储**。叶子节点直接存储**整行数据**。一张表**只能有一个**聚簇索引(通常就是主键索引)。InnoDB的表必须有聚簇索引。
* **非聚簇索引(Secondary Index,辅助索引)**:叶子节点存储的是**主键的值**(InnoDB)或**指向数据行的物理地址**(MyISAM)。查找到主键后,还需要**回表查询**(通过主键回到聚簇索引中查找完整数据行)。
8. 什么是回表查询和覆盖索引?
**答**:
* **回表查询**:先通过非聚簇索引找到对应记录的**主键值**,再根据主键值到**聚簇索引**中查找完整行数据的过程。多了一次索引查找,性能较低。
* **覆盖索引**:如果一个索引包含了(或覆盖了)查询语句所需要的**所有字段**,那么引擎就可以直接从这个索引的叶子节点得到结果,而无需回表。这能极大地提升性能。
* **例子**:表 `user` 有索引 `idx_name_age (name, age)`。查询 `SELECT age FROM user WHERE name = '张三'`; 因为 `age` 已经在 `idx_name_age` 索引中了,所以无需回表。
9. 如何创建高效的索引?(索引优化策略)
**答**:
-
**最左前缀原则**:对于联合索引 `(a, b, c)`,它可以用于查询 `a`, `a,b`, `a,b,c`,但不能用于查询 `b` 或 `c` 或 `b,c`(索引会失效)。
-
**避免在索引列上使用函数或计算**:`WHERE YEAR(create_time) = 2023` 会导致索引失效。应改为范围查询 `WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31'`。
-
**选择区分度高的列建索引**:区分度指索引列不同值的数量与总记录数的比值。比值越高,索引效率越好(如身份证号非常适合建索引,性别则不适合)。
-
**使用覆盖索引**,避免回表。
-
**避免使用 `SELECT *`**,只取需要的字段,增加覆盖索引的可能性。
三、事务与锁(核心考点)
10. 什么是数据库事务?它的ACID特性是什么?
**答**:事务是数据库操作的最小工作单元,作为一个整体一起向系统提交,要么都执行,要么都不执行。
* **A - Atomicity (原子性)**:事务中的所有操作是一个不可分割的整体,要么全部成功,要么全部失败回滚。
* **C - Consistency (一致性)**:事务执行前后,数据库必须从一个一致性状态变换到另一个一致性状态(数据完整性不被破坏)。
* **I - Isolation (隔离性)**:并发事务之间相互隔离,不应互相干扰。
* **D - Durability (持久性)**:事务一旦提交,它对数据库的改变就是永久性的。
11. MySQL的隔离级别有哪些?分别解决了什么并发问题?
**答**:由低到高有四个级别:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
| :--- | :--- | :--- | :--- |
| **读未提交 (Read Uncommitted)** | ❌ 可能 | ❌ 可能 | ❌ 可能 |
| **读已提交 (Read Committed)** | ✅ 避免 | ❌ 可能 | ❌ 可能 |
| **可重复读 (Repeatable Read)** | ✅ 避免 | ✅ 避免 | ❌ 可能 |
| **串行化 (Serializable)** | ✅ 避免 | ✅ 避免 | ✅ 避免 |
* **脏读**:一个事务读到了另一个**未提交事务**修改的数据。
* **不可重复读**:一个事务内,多次读取**同一数据**,结果不同(因为被其他已提交事务**修改**了)。
* **幻读**:一个事务内,多次查询**同一范围**的数据,记录数不同(因为被其他已提交事务**新增或删除**了)。**InnoDB在RR级别通过MVCC和间隙锁解决了幻读问题**。
**MySQL默认的隔离级别是可重复读 (Repeatable Read)**。