1.MySQL 存储引擎 InnoDB 和 MyISAM 区别
- innoDB:支持事务、行锁、外键、崩溃可恢复
- MyISAM:不支持事务,表锁,查询更快,不支持崩溃恢复
详细区别
1.事务支持
- innoDB:支持事务(ACID),可以commit/rollback
- MyISAM:不支持事务
2.锁机制
- Inn哦DB:行级锁+表锁 并发高,适合大量更新
- M有ISAM:表级锁 一写全锁,并发差
3.外键
- innoDB:支持外键
- MyISAM:不支持外键
4.崩溃恢复
- innoDB:支持crash-safe,redo/undo日志保证数据不丢失
- MyISAM:崩溃后易损坏,需要修复
5.count(*)效率
- MyISAM极快:总行数存在表meta里
- innoDB慢:要全表扫描统计
6.索引结构
- 都是B+Tree
- innoDB:聚簇索引,数据存在主键索引叶子节点
- MyISAM:非聚簇索引,索引和数据分开
7.适用场景
- innoDB:绝大多数业务 增删改多、需要事务、并发高、要求数据安全
- MyISAM:制度/极少写、统计类 纯查询、日志表、无需事务的简单表
总结
- innoDB支持事务、行锁、外键、崩溃恢复
- MyISAM不支持事务,只支持表锁,查询快但不安全
- 现在默认、体检、几乎都用innoDB
- MyISAM只有在极高读、几乎不写的场景才考虑
2.事务四大特性 ACID
A:Atomicity原子性
- 事务是最小执行单位,不可再分
- 要么全部执行成功,要么全部失败回滚
- 不会出现只执行一半的情况
C:Consistency一致性
- 事务执行前后,数据库的完整性约束不变
- 数据从一个合法状态,转到另一个合法状态
- 比如转账前后总金额不变
I:Isolation隔离性
- 多个事务并发执行时,互相不可干扰
- 一个事务看不到另一个事务的中间状态
- 通过隔离级别实现(读未提交、读已提交、可重复读、串行化)
D:Durability持久性
- 事务一旦提交陈工,对数据的修改就是永久的
- 即使数据库崩溃、断电、数据也不会丢失
总结
原子性保证操作不被打断,一致性保证数据合法,隔离性保证并发互不干扰,持久性保证提交后永久生效
3.事务隔离级别
四大隔离级别(从低到高)
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)——Oracle默认
- 可重复读(Repeatable Read)——MySQL InnoDB默认
- 串行化(Serializable)
对应会出现的问题
- 脏读:督导别的事务未提交的数据
- 不可重复读:同一事务内,两次查询结果不一样
- 幻读:同一事务内,查询到了新增/删除的行
级别与问题对照表
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | ✅ 会 | ✅ 会 | ✅ 会 |
| 读已提交 | ❌ 不会 | ✅ 会 | ✅ 会 |
| 可重复读 | ❌ 不会 | ❌ 不会 | ✅ 会(InnoDB 靠 MVCC 很大程度解决) |
| 串行化 | ❌ 不会 | ❌ 不会 | ❌ 不会 |
总结
- 读未提交:最低级,允许读到未提交数据,会脏读
- 读已提交:只能读到已提交数据,解决脏读,但会不可重复读。
- 可重复读:同一事务内多次读取结果一致,解决不可重复读,时MySQL默认。
- 串行化:最高级,完全串行执行,无并发问题,但性能最差。
4.索引是什么?为什么快?
1.索引是什么
索引是数据库中用于加速查询的数据结构,本质是排好序的快速查找结构。
MySQL InnoDB索引默认是B+树
可以理解为:
数据库的目录,不用再从头到尾翻书(全表扫描)
2.索引为什么快
A.避免全表扫描
- 无索引:查询要逐行遍历,O(n)
- 有索引:走B+树查找,O(log n)。数据量越大,差距越恐怖。
B.B+树本身结构极适合磁盘查询
- 层级少:几百万数据只需3~4层
- 叶子节点有序且连成链表
-
- 范围查询wherer id between 100 and 200极快
-
- 顺序遍历不用跳来跳去
- 只在叶子节点存数据,树更小、缓存命中率更高
C.索引本身有序
- 排序order by
- 分组group by
- 去重distinct
都可以直接利用有序性,避免额外排序。
D.减少磁盘I/O
数据库慢,90%都慢在磁盘I/O
索引通过树结构大幅减少I/O次数,所以速度提升巨大
总结
索引是排好序的B+树结构,通过避免全表扫描、减少磁盘I/O、利用树的快速查找特性,让查询从O(n)降到O(log n),所以极快。
5.唯一索引、主键索引、普通索引区别
1.主键索引(PRIMARY KEY)
- 列的值必须唯一,而且不能为NULL
- innoDB中主键索引就是聚簇索引,数据直接存在索引叶子节点
- 一般用id做主键
2.唯一索引(UNIQUE KEY)
- 一张表可以有多个
- 列的值必须唯一,但允许NULL(且多个NULL不冲突)
- 是非聚簇索引,叶子节点存主键值
3.普通索引(INDEX/KEY)
- 一张表可以有多个
- 没有任何约束,值可以重复、可以为NULL
- 只用来加速查询
对照表
| 类型 | 个数限制 | 值是否唯一 | 能否 NULL | 索引类型 |
|---|---|---|---|---|
| 主键索引 | 只能 1 个 | 唯一 | 不能 | 聚簇索引 |
| 唯一索引 | 可多个 | 唯一 | 能(多个 NULL) | 非聚簇索引 |
| 普通索引 | 可多个 | 可重复 | 能 | 非聚簇索引 |
使用场景
- 主键索引:必须有,业务唯一标识(id)
- 唯一索引:业务上不能重复,但不是主键(手机号、身份证)
- 普通索引:只用于加速查询,允许重复(性别、状态)
总结
主键只能一个,非空唯一却聚簇;唯一索引可多个,值唯一允许NULL;普通索引无约束,只提速。
6.left join /inner join /right join 区别
1.inner join(内连接)
只保留两张表中能匹配上的数据
- A有、B没有→不显示
- B有、A没有→不显示
- 只有两边都有的记录才会出现
select * from A inner join B on A.id=B.a_id;
2.left join(左连接)
左表数据完全保留,右表能匹配的就显示,匹配不上为NULL
- 左表(A)所有记录一定都在
- 右表(B)匹配不到的字段显示NULL
select * from A left join B on A.id=B.a_id;
3.right join(右连接)
右表数据全部保留左边能匹配就能显示,匹配不上为NULL
- 右表(B)所有记录一定都在
- 左表(A)匹配不到的字段显示NULL
select * from A left join B on A.id=B.a_id;
简记
-
inner join:取交集
-
left join:左表全部+匹配的右表
-
rigth join:右表全部+匹配的左表
-
想要必须存在的关联数据→inner join
-
想要左边表数据一定全显示→left join(常用)
-
right join很少用,一般改成left join看着更舒服
7.简单 SQL 手写:增删改查、分页、分组、排序
- 增(INSERT)
INSERT INTO user(id,name,age) VALUES(1,'张三',20);
- 删()
DELETE FROM user WHERE id=1;
- 改()
UPDATE user SET name='李四',age=21 WHERE id=1;
- 查()
SELECT id,name,age FROM user WHERE age>18;
- 排序()
SELECT * FROM user ORDER BY age DESC;
- 分组()
SELECT dept,COUNT(*) FROM user GROUP BY dept;
- 分组后筛选()
SELECT dept,COUNT(*) FROM user GROUP BY dept HAVING COUNT(*)>5;
- 分页()
MYSQL分页固定写法:
SELECT * FROM user LIMIT 偏移量, 每页条数;
-- 第1页,每页10条
SELECT * FROM user LIMIT 0, 10;
-- 第2页
SELECT * FROM user LIMIT 10, 10;
8.SQL 优化简单说几点
- 避免SELECT*,只查需要的字段
- where条件建索引,少用模糊查询%xxx%
- 避免索引失效:不做运算、不类型转换、不用!=、or慎用
- 少用子查询,优先使用join代替
- 分页优化:大偏移量用id>last_id方法
- group by/order by尽量用索引字段
- 避免全表扫描,小表驱动大表
- 合理建联合索引,遵循最左前缀原则