- 1.MySQL使用有哪些注意事项
- 2.一条SQL在MySQL中如何运行的?
- 3.不可重复读和幻读
- 4.聚簇和非聚簇索引
- 5.如何定位并优化慢SQL
- 6.InnoDB和MyISAM的区别
- 7.索引数据结构选择
- 8.锁分类
- 9.MySQL中如何存储emoji标签
- 10.自增ID和UUID的选择
- 11.SQL的生命周期
- 12.SQL的执行顺序
- 13.varchar能放多少内容
- 14.Innodb的事务日志
- 15.Innodb的事务实现原理?
- 16.MySQL的复制原理以及流程
- 17.mysql自增主键用完了怎么办?
- 18.count(1)、count(*) 与 count(列名) 的区别
- 19.什么是死锁?怎么解决?
- 20.如何选择合适的分布式主键方案呢?
- 21.MySQL中in 和exists的区别
- 22.数据库自增主键可能遇到什么问题
- 23.MVCC熟悉吗,它的底层原理?
- 24.MySQL的主从延迟,你怎么解决?
- 25.MySQL的binlog有几种录入格式
- 26.读写分离常见方案?
- 27.数据库范式
- 参考资料
1.MySQL使用有哪些注意事项
索引失效规则
- where子句中包含or查询,可能会导致索引失效
- where子句中like ‘%xxx’会导致索引失效
- where子句中索引列上使用函数、算术运算会导致索引失效
- where子句中索引列上使用(!=、<>、not in、is not null)可能会导致索引失效
- where字句中索引列类型和查询参数类型不统一时,会导致索引失效(整形除外)
- where字句中左右连接字段编码不统一时,会导致索引失效
- 优化器认为全表扫描更快的情况下,索引失效
小结:
- 失效的场景
- 不等于
- like’%’
- 计算后的索引列
- 类型不匹配
- 连接时连个索引字段编码不匹配
- 优化器自己的确定
- 失效的场景
不适合索引场景
- 数据量少的情况下不适合加索引
- 写多读少的场景不适合加索引
-
索引相关概念
覆盖索引
- 索引下推
- B+Tree
- 回表
-
2.一条SQL在MySQL中如何运行的?
MySQL的逻辑架构图
第一层:连接层:管理客户端连接,进行用户认证
- 第二层:服务层
- SQL Interface:接收用户SQL语句
- Parser 解析器:对SQL进行语法和语义上的分析
- Optimizer优化器:生成执行计划,确定索引
- Caches & Buffers:缓冲(SQL语句:结果)
- 执行器:操作引擎,返回结果
- 第三层:引擎层:负责文件系统交互,负责MySQL数据的存储和提取操作。先上提供读写接口,向下完成与文件系统交互
-
SQL如何运行的
MySQL对客户端进行认证和权限查询
- 连接层会校验用户是否有执行该SQL的权限,无则直接错误返回
- MySQL8.0前,先查缓存,有数据则直接返回
- 对SQL进行语法分析和词法分析
- 通过优化器生成执行计划和进行索引选择
-
3.不可重复读和幻读
不可重复读:针对的是同一条数据而言,同一事务中两次读取结果不一致
- 幻读:针对的是范围查询而言,同一个范围事务前后两次读取,数据条数不一致
思考: 照上面的规则来说的话,MySQL的MVCC机制在不可重复读的级别就解决了幻读的问题
4.聚簇和非聚簇索引
- 数量:
- 聚簇索引:仅可有一个
- 非聚簇索引:可以有多个
物理存储顺序:
定位:开启慢查询日志
- 查看是否开启:show variables like ‘slow_query_log’
- 设置开启:set global slow_query_log = on
- 设置慢查询阈值:set global long_query_time = 5
- 定位日志位置:show variables like ‘%slow_query_log%’
- 通过文件查看日志内容:datadir/XXX-slow.log
- SQL本身优化
- 通过指定所需字段代替select *
- 修改导致索引失效的写法
- 避免使用子查询,使用连接查询代替
- 索引优化
- 最佳左前缀
- explain
- 索引失效规则
- 表结构优化
- 适当的冗余,反范式化
- 引入缓存中间件
- 数据库优化
- 单数据库参数优化:join_buffer_size、sort_buffer_size
- 分库分表
6.InnoDB和MyISAM的区别
| 特性 | InnoDB | MyISAM | | —- | —- | —- | | count(*) | 全表扫描 | 额外变量存储、O(1)查询速度 | | 事务 | 支持 | 不支持 | | 外键 | 支持 | 不支持 | | 索引底层实现 | B+Tree | B+Tree | | 物理存储属性 | 按照主键顺序 | 按照插入顺序 | | 锁粒度 | 行级 | 表级 | | 必须有主键? | 必须 | 不必须 | | 文件实际存储格式 |
- MySQL5.7
- 独立表空间模式
- 表名.frm:每个表结构
- 表名.idb:每个表的索引和数据
- 系统表空间模式
- 表名.frm:每个表结构
- ibdata1:索引和数据
- MySQL8.0
- 表名.idb:包含表结构、索引和数据
|
- 表结构
- 5.7:表名.frm
- 8.0:表名.sdi
- 索引:表名.MYI
- 数据:表名.MYD
|
7.索引数据结构选择
为什么不是二叉树
-
为什么不是平衡二叉树
平衡二叉树不会出现极端的情况,但是考虑到我们的查询是建立的磁盘IO上的。平衡二叉树对于基于内存的查询效果很好,但是基于磁盘IO,二叉树每个节点的载入都是一次磁盘IO操作。每次磁盘IO只能筛选粒度太粗啦。数量大的情况下树的深度太深啦!
为什么不是B-Tree
B-Tree的每个节点上不仅存储索引值,而且存储数据,这样相比较B+Tree只存储索引值而言,B+Tree的一个数据也可以存放下更多的索引值。导致树的高度就越低,磁盘IO次数就越少
B-Tree对于单条记录的查询可能优于B+Tree,但是范围查询时,还需要在树的上下层之间回溯。B+Tree所有数据存放在叶子节点,并且使用链表指针顺序链接。范围查询时极其容易
为什么不用Hash
hash单条记录ok,效率极高,范围查询怎么办?所以还是B+Tree
8.锁分类
读写类型角度
- 读锁
- 写锁
- 加锁态度
- 悲观锁
- 乐观锁
- 加锁方式
- 显式加锁:在SQL中显式地加锁
- 隐式加锁:MySQL依据隔离级别进行的加锁
- 锁粒度角度
- 表级锁
- 手动给表上锁
- 表级意向锁:执行行级别的加锁操作后,对于后面的数据表结构修改操作的一种锁控制
- 自增锁:生成记录的自增id时,表级加锁(3种加锁模式)
- MDL(元数据锁):有SQL对表结构做变更时
- 页级锁
- 行级锁
- 记录锁:针对某条具体的记录加锁,如:id=8加锁
- 间隙锁:锁住某段不存在的记录,如:id在(3,8)区间内的
- 临键锁:锁住某个条记录以及之前的不存在的记录,如:id在(3,8]区间的内的记录
- 插入意向锁:某个事务插入某条记录前,需要等待Gap锁的那个事务,在等待的时候上插入意向锁,插入意向锁实际就是一个特殊的Gap锁
- 表级锁
显式or隐式
自增ID值大小顺序即插入顺序,插入效率高,占有空间少
-
11.SQL的生命周期
客户端连接MySQL服务器
- 数据库进程拿到SQL
- 对SQL进行语法和词法分析
- 优化器生成执行计划
- 通过存储引擎查询数据,读取到内存中进行处理
- 返回处理结果到客户端
-
12.SQL的执行顺序
13.varchar能放多少内容
varchar最多可定义为varchar(65532)
- varchar(n)中的n指定的是字节数
varchar(n)具体可以放多少内容,要根据编码,如utf-8(3字节)。n/3
14.Innodb的事务日志
事务相关日志:redo日志和undo日志
- redo日志:提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。
- undo日志:在更新操作前要记录undo log,保存当前数据镜像。回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
日志存放方式
持久化:只要操作记录到redo log中,系统崩溃恢复后可以通过redo log做数据恢复
- 原子性:undo log记录历史版本信息,可以对事务进行回滚
- 隔离性:锁机制和MVCC机制(undo log)
一致性:回滚(事务之间的原子性)、事务之间的隔离性,保证了一致性
16.MySQL的复制原理以及流程
主库发生数据更新操作被记录到binlog中
- 从库连接主库,主库开启binlog dump 线程将binlog发送到从库
- 从库开启IO线程,将binlog写入relaylog中
从库开启SQL线程,读取relaylog中的内容并执行,完成数据复制
17.mysql自增主键用完了怎么办?
18.count(1)、count(*) 与 count(列名) 的区别
count(1)/count(*):不忽略null值
-
19.什么是死锁?怎么解决?
是什么:死锁是2个或多个事务在同一资源相互占用,并请求锁定对方的资源
- 四个必要条件:
- 互斥条件:资源的获取时互斥
- 请求和保持条件:线程因请求资源而导致阻塞时,对已获资源不释放
- 环路等待条件:出现等待环路
- 不剥夺条件:线程已获得的资源,在未使用完前无法被剥夺
解决方式
UUID
- Snowflake算法
- Redis生成ID
- ZooKeeper生成ID
-
21.MySQL中in 和exists的区别
前提:A是主表,B是放在in或exists中查询的表
B表的数据量小:使用in
-
22.数据库自增主键可能遇到什么问题
分库分表后,主键重复问题
- 自增主键产生锁,引发并发问题
-
23.MVCC熟悉吗,它的底层原理?
记录隐藏字段
- trx_id:每次记录当前记录的是哪个事务修改的
- roll_pointer:指向undo log日志中该记录旧版本的数据链
- undo log:该条记录所有的历史版本
- ReadView
- creator_trx_id:创建这个ReadView的事务id(纯select语句事务id=0)
- trx_ids:创建ReadView时系统中活跃的事务id
- up_limit_id:活跃事务中最小的事务id
- low_limit_id:下一个事务的id(最大事务id)
运行规则
产生原因:多个客户端并发对主库进行写操作,主库只有一个binlog dump线程在工作,当某个SQL执行时间过长或锁表,则导致SQL大量堆积。此时从库和主库就有不一致的状态产生
解决方式
statement:记录每条更新操作的SQL,函数无法记录,会出现语义分歧
- row:记录每一行的变动,日志量太大
mixed:普通操作记录statement模式,否则用row模式
26.读写分离常见方案?
应用程序自己编写逻辑,实现读写分离
-
27.数据库范式
1NF:所有字段都是不可再分的
- 2NF:所有的非主属性都完全函数依赖于候选键
- 3NF:所有的非主属性都不传递函数依赖于候选键
- BCNF:只有有X->Y,那么X必是候选键。(任何属性都完全函数依赖于候选键)
参考资料