MySQL面经
内容援引自JavaGuide、哔哩哔哩黑马程序员数据库从入门到精通,感谢各位大神原创分享
数据库Mysql
常见的关系型数据库包括mysql
、SQL Server
、Oracle
、常见的非关系型数据库Redis
、MongDB
等。
特点
Mysql
开源免费,生态完善,支持事务、高可用(读写分离、分库分表)。
基础架构:
- 服务层:连接器、查询缓存(移除)、分析器、优化器、执行器;通用日志模块
binlog
- 存储引擎层:插件式存储引擎(为表设置存储引擎),支持
InnoDB
、MyISAM
等;InnoDB包括redolog
和undolog
日志
存储引擎
使用插件式存储引擎,默认InnoDB支持事务、行锁、外键,数据恢复(redolog),MyISAM不支持事务、采用表锁、不支持外键,不支持数据恢复。此外InnoDB主键使用聚簇索引,叶子节点保存记录,MyISAM使用非聚簇索引,叶子节点保存记录的地址,两者均为B+ Tree。
MySQL索引
用于快速查询或快速定位
的排序
的数据结构,常见的索引结构包括Hash树、B树、B+树、红黑树。InnoDB和MyISAM均使用B+树作为索引结构。
索引优缺点
优点:加快检索速度,创建唯一索引保证数据唯一性。缺点:创建、维护索引时间开销,且索引占物理存储空间。
索引结构
- 为什么不使用hash?
可能出现哈希碰撞(拉链式)、不支持顺序查找和范围查找。 - 为什么不使用B树?
B树节点存索引和数据,B+树只有叶子节点存储索引和数据且构成双向链表,其它节点存储索引,故相同数据量下B树高度更高,查询效率更低,且不支持范围查找。 - 为什么不使用红黑树?
红黑树是自平衡二叉查找树,树过高造成大量的磁盘 IO。 - B+树一般不超过3层,能存储多少数据?
最小存储单元一页16KB,叶子节点存索引和记录,假设索引和一条记录占1KB,则一页可存16K/1K=16
条记录,非叶子节点存索引和指针,假设主键索引为bigint占8字节,指针占6字节,则一个节点可存16k/(8+4)=1170
个指针,两层的B+树可存1170*16
条记录,三层的B+树可存1170*1170*16
条记录,约两千万数据量。
索引的类别
索引相关的概念包括聚簇索引、非聚簇索引、主键索引、辅助索引、唯一索引、普通索引、联合索引、覆盖索引、前缀索引、全文索引。
聚簇索引,叶子节点保存索引和记录,非聚簇索引叶子节点保存索引和记录相关值(记录地址或主键),且InnoDB存储引擎非聚簇索引不一定需要回表查询(覆盖索引)
主键索引,非null,不可重复,没有显示指定时检查是否存在非null的唯一索引,存在则将该字段作为主键索引否则默认创建6字节的自增索引。设计表时不建议使用过长字段作为主键,不建议使用非单调字段作为主键(引发索引频繁分裂,这解释了为什么不宜使用UUID作为主键)。
联合索引,多个字段一起创建索引,索引使用要求满足最左匹配原则,缺失停止匹配,范围查询右侧字段
停止匹配
# 创建(a,b,c)联合索引 等值查询中a、ab、abc均可使用索引,b、bc、c不可使用索引,全部为等值查询时字段顺序对是否使用索引不产生影响;
# 以下语句a,b走索引,c不走索引,建议将区分度高的字段放最左侧以过滤更多数据
select * from t where a=1 and b > 1 and c=1;
# 如果是建立(a,c,b)联合索引,则a,b,c都走索引
索引下推:非聚簇索引遍历过程中,根据索引中包含的字段过滤不符合条件的记录,减少回表次数。
正确使用索引
- 是否有必要创建索引,很少查询的表没必要创建索引,频繁更新的字段不适合创建索引;
- 为哪些字段创建索引,为查询字段,排序字段和分组字段创建索引,优先创建联合索引且区分度高的字段放在左侧(可能产生覆盖索引效果,避免回表,且可以过滤较多记录),字符串类型的字段可优先考虑前缀索引;
- 避免索引失效,如隐式类型转换、在字段上进行函数操作、
or
逻辑中某条件字段没有索引则涉及的索引全部失效
索引优化
- SQL提示,在SQL语句中加入人为提示优化操作
use index
、ignore index
、force index
,注意use index仅是建议,不代表优化器会选择的执行计划; - 插入数据,批量插入、手动提交事务、主键顺序插入
- 主键 优化,减少主键长度、主键递增、避免对主键进行修改
update
优化,InnoDB行锁针对索引,有索引时锁行,没有索引锁表
#id有主键索引,锁行;
update student set no = '123' where id = 1;
#name没有索引,锁表
update student set no = '123' where name = 'test';
order by
优化,多字段排序且一个升序一个降序,要注意创建索引时索引的升序和降序limit
优化,覆盖索引、子查询、联表查询
# 优化前
SELECT * FROM xxx limit 1000000,20
# 子查询优化
SELECT * FROM xxx WHERE ID >=(select id from xxx limit 1000000, 1) limit 20;
# 联表优化
SELECT * FROM xxx a JOIN (select id from xxx limit 1000000, 20) b ON a.ID = b.id;
MySQL事务
ACID原则,原子性、一致性、隔离性、持久性
其中一致性是目的,原子性是指要么都执行,要么都不执行,隔离性是指并发事务的独立性,持久性是指事务被提交后可持久化。
并发事务的问题,脏读、不可重复读、幻读
脏读是指事务A读取事务B未提交的数据,不可重复读是指事务A多次读某条记录的读取结果不同,幻读是指幻读指事务A读取某一范围的数据行,事务B在该范围内插入了新行,事务A再读取该范围的数据行时,出现幻影行
。
并发事务控制,锁+MVCC
MySQL中通过读写锁实现并发控制,读锁为共享锁,写锁为排它锁,读读兼容,读写或写写互斥。按粒度MySQL锁又可划分为表锁和行锁,其中表锁不会出现死锁,锁冲突概率高,并发性能低;行锁针对索引字段加锁,会出现死锁,并发度高,行锁 又包括记录锁、间隙锁、临键锁。
- 行锁发生死锁的场景描述
事务A | 事务B |
---|---|
1、delete from xxxx where id = 1; |
|
2、delete from xxxx where id = 2; |
|
3、delete from xxxx where id = 2; 事务A等事务B释放记录2行锁 |
|
4、delete from xxxx where id = 1; 事务B等事务A释放记录1行锁 |
- MVCC 多版本并发控制
MySQL的隔离级别包括读未提交(脏读、不可重复读、幻读风险),读已提交(不可重复读,幻读风险),可重复读(默认隔离级别,幻读风险)和可串行化。特殊的,InnoDB实现的可重复读隔离级别可解决幻读风险,快照读由MVCC机制保证,当前读使用临键锁保证。
在读已提交和可重复读隔离级别下,执行普通select
会使用一致性非锁定读MVCC
,读记录的快照数据;执行insert
、delete
、update
、select...lock in share mode
、select...for update
会使用锁定读,读取记录的最新数据,并对读取到的记录加锁,即当前读。
MVCC机制的实现依赖隐藏字段、Read View
和undo log
,InnoDB存储引擎为记录添加默认主键
(主键不存在且不存在非空的唯一索引时默认添加)、事务id
,回滚指针
3个隐藏字段;读已提交隔离级别下每次select查询前创建Read View,可重复读隔离级别下事务开始第一次select前创建Read View,Read View用于可见性判断,主要包括m_low_limit_id
、m_up_limit_id
、m_ids
、m_creator_trx_id
字段,根据数据可见性算法(比较记录的事务id和Read View中字段)若当前记录对该事务不可见则使用回滚指针进行数据回滚。
三大日志
Mysql日志包括查询日志、慢查询日志、错误日志和binlog
日志、redolog
日志、undolog
日志,其中binlog支持数据备份和主从同步,rodolog支持数据 恢复以保证持久性,undolog支持事务回滚以保证原子性和支持MVCC多版本并发控制。
binlog
- MySQL
binlog日志支持数据备份和主从同步,包括三种记录格式statement
、row
和mixed
,其中statement记录SQL语句(获得时间戳等SQL语句容易导致数据备份不一致或主从数据不一致),row记录SQL语句和操作数以规避以上问题,但占用内存,折中方案mixed由MySQL判断是否会引起数据不一致,选择statement或row。
binlog的刷盘策略:1)事务提交将binlog cache写入到page cache,系统自行决定刷盘;2)事务提交进行刷盘;3)折中方案,提交事务binlog cache写入到page cache,提交N个事务进行刷盘;
redolog
- InnoDB
redolog日志支持数据恢复,保证事务的持久性。Mysql数据以页16KB为单位(页、段、区、表),查询记录时从磁盘加载数据页放入缓冲池Buffer pool中,后续查询优先在缓冲池中查找,未命中再从磁盘加载,减少IO开销。更新记录时,更新缓存数据,将数据页上的更新记录到redolog buffer中,根据一定的刷盘策略进行持久化。
rodolog刷盘策略:1)事务提交不进行刷盘(Mysql实例挂或宕机可能会有一秒数据的丢失);2)事务提交将redolog buffer写入page cache中(Mysql实例挂没有数据丢失,宕机可能会有一秒的数据丢失);3)事务提交刷盘(Mysql实例挂或宕机不会有数据丢失)。兜底措施后台线程每隔1s将redolog buffer写入到page cache,然后进行刷盘;redolog buffer占用内存到一定阈值后台线程主动刷盘。
为什么要使用redolog,而不是直接将修改的数据页刷盘?通常数据更新只影响数据页中的少量记录,且数据页刷盘是随机写,刷盘成本高。采用redolog记录更新属于顺序写,刷盘成本低,有利于提高数据库的并发能力。
两阶段提交
:redolog prepare - binlog - redolog commit。
- redolog-宕机-binlog,主从结构中,主使用redolog数据恢复,从使用binlog数据恢复,主从数据不一致。
- binlog-宕机-redolog,主从结构中主使用redolog,从使用binlog,主从数据不一致。
- 两阶段提交,redolog prepare - 宕机 - binlog - redolog commit,redolog有事务记录,binlog没有事务记录,事务回滚;redolog prepare - binlog - 宕机 - redolog commit,redolog有事务记录,binlog也有对应的事务记录,提交事务恢复 数据。
undolog
undolog日志支持事务回滚和MVCC,保证事务的原子性和隔离性。
MySQL执行计划
explain sql
热门相关:斗神战帝 明月照大江 仗剑高歌 寂静王冠 第一神算:纨绔大小姐