diff --git a/mysql/1.sql.md b/mysql/1.sql.md new file mode 100644 index 0000000..5bf5c88 --- /dev/null +++ b/mysql/1.sql.md @@ -0,0 +1,30 @@ +# SQL 优化 + +- [SQL 优化](#sql-优化) + - [SQL 执行过程](#sql-执行过程) + - [问题定位](#问题定位) + - [优化](#优化) + - [SQL 注入](#sql-注入) + +## SQL 执行过程 + +![SQL执行过程](./sql.png) + +## 问题定位 + +- 满查询日志 +- explain 分析执行计划 + +## 优化 + +- 表设计,避免数据冗余和重复计算 +- 合理设计索引 +- 分库分表,减少数据量,减小查询范围 + +## SQL 注入 + +- 用户参数中包含了 SQL 语句,修改了原 SQL 的意图 +- 避免方法 + - 预编译,?号占位符 + - 正则表达式过滤参数 + - 过滤转义 diff --git a/mysql/2.view.md b/mysql/2.view.md new file mode 100644 index 0000000..519b127 --- /dev/null +++ b/mysql/2.view.md @@ -0,0 +1,21 @@ +# 视图 + +- [视图](#视图) + - [视图定义](#视图定义) + - [优点](#优点) + +## 视图定义 + +- 一种虚拟表,逻辑上的表,不包含数据 +- 使用 SQL 定义 + ```sql + create view_name as + ``` +- 通过视图可以展现基表全部或部分数据 +- 通常用于查询,增删改会有限制 + +## 优点 + +- 简单可复用,隐藏基表复杂的 SQL +- 安全 +- 数据独立,屏蔽基表数量、表结构的变化 diff --git a/mysql/3.index.md b/mysql/3.index.md new file mode 100644 index 0000000..813cc03 --- /dev/null +++ b/mysql/3.index.md @@ -0,0 +1,65 @@ +# 索引 + +- [索引](#索引) + - [索引定义](#索引定义) + - [使用索引的场景](#使用索引的场景) + - [不需使用索引的场景](#不需使用索引的场景) + - [索引失效](#索引失效) + - [索引的代价](#索引的代价) + - [主键索引](#主键索引) + - [唯一索引](#唯一索引) + - [覆盖索引](#覆盖索引) + - [索引下推](#索引下推) + +## 索引定义 + +- 一种有序的存储结构 +- 按照单个或多个列的值进行排序 +- 对应着一个 B+树 +- 提升搜索效率 + +## 使用索引的场景 + +- where +- group by +- order by + +## 不需使用索引的场景 + +- 没有 where/group by/order by +- 区分度不高的列 +- 经常修改的列 +- 数据量少 + +## 索引失效 + +- 左模糊匹配 +- 索引参与运算,使用函数、表达式运算、隐式转换 +- where or 有非索引字段 +- 不符合最左匹配原则 + +## 索引的代价 + +- B+树空间 +- 维护 B+树的时间 + +## 主键索引 + +- 非空唯一索引 +- 一个表只有一个主键索引,primary key 修饰或者使用第一个非空唯一索引作为主键,或者自动生成主键 +- 包含所有行信息 + +## 唯一索引 + +- 索引列不能出现重复值,可以有 null 值 +- unique 修饰 +- 只包含索引信息和主键信息 + +## 覆盖索引 + +- 直接通过辅助索引就能获取全部要查询的数据,无需回表查询 +- 在 select from 之间尽量列出所有需要的字段,如果字段恰好都在辅助索引 B+树中,就会使用覆盖索引 + +## 索引下推 + +- 在索引的遍历过程中,对索引中包含字段先做判断,直接将不满足的数据行排除,从而减少回表的次数 diff --git a/mysql/4.B+tree.md b/mysql/4.B+tree.md new file mode 100644 index 0000000..77ecdd1 --- /dev/null +++ b/mysql/4.B+tree.md @@ -0,0 +1,15 @@ +# B+树 + +- [B+树](#b树) + - [B+树特点](#b树特点) + +## B+树特点 + +- 多路平衡搜索树 + - 多路,降低层高,减少磁盘 IO + - 平衡,增删改通过平衡确保搜索时间稳定 + - 搜索,有序 +- 所有叶子节点在同一层 +- 叶子节点间有双向链表连接,方便范围查询和降低磁盘 IO +- 节点大小固定,16K +- 非叶子节点记录索引信息,叶子节点存放数据信息 diff --git a/mysql/5.transaction.md b/mysql/5.transaction.md new file mode 100644 index 0000000..c59fd0e --- /dev/null +++ b/mysql/5.transaction.md @@ -0,0 +1,75 @@ +# 事务 + +- [事务](#事务) + - [事务特性](#事务特性) + - [原子性](#原子性) + - [一致性](#一致性) + - [隔离性](#隔离性) + - [持久性](#持久性) + - [隔离级别](#隔离级别) + - [读未提交](#读未提交) + - [读已提交](#读已提交) + - [可重复读](#可重复读) + - [可串行化](#可串行化) + - [脏读](#脏读) + - [不可重复读](#不可重复读) + - [幻读](#幻读) + +## 事务特性 + +### 原子性 + +- 事务中的所有操作要么全部成功执行,要么全部回滚 +- 如果在事务执行过程中发生错误,会将已经执行的操作进行回滚,保持数据一致性 + +### 一致性 + +- 事务开始前和结束后,数据库的完整性约束没有被破坏 +- 在事务执行过程中对数据的修改必须符合预定义的规则,以保证数据的有效性和正确性 + +### 隔离性 + +- 每个事务在并发执行时都应该相互隔离,并且不应该互相干扰 +- 一个事务在提交之前对其他事务是不可见的,防止了读取到未提交或部分提交的数据 + +### 持久性 + +- 一旦事务提交成功后,其所做的修改就会永久保存到数据库中,并且不能被撤销 +- 即使在系统故障或断电情况下,也能够保证数据不会丢失 + +## 隔离级别 + +### 读未提交 + +- 一个事务可以读取另一个事务尚未提交的数据 +- 这可能导致脏读:一个事务读取了另一个事务尚未提交的数据。如果该事务回滚,读取到的数据将无效 + +### 读已提交 + +- 一个事务只能读取另一个事务已提交的数据 +- 解决了脏读问题,但可能导致不可重复读:在一个事务中,多次读取同一数据,由于其他事务的修改,导致返回的数据不一致 + +### 可重复读 + +- 一个事务在其生命周期内多次读取同一数据,数据始终保持一致 +- 解决了不可重复读问题,但可能导致幻读:在一个事务中,两次查询范围相同的记录,由于其他事务的插入或删除操作,导致返回的记录数量不一致 + +### 可串行化 + +- 事务被强制按顺序执行,完全避免了脏读、不可重复读和幻读等问题 +- 牺牲了并发性能,因为事务必须按顺序执行 + +## 脏读 + +- 一个事务可以读到其它事务未提交的状态 + +## 不可重复读 + +- 一个事务中两次读的结果不同 +- 因为读以提交是读最新版本的数据,最新的数据可能被其它事务修改 + +## 幻读 + +- 一个事务中两次读取同一个范围的结果不同 +- 因为当前读和快照读不一致造成 +- 解决:把快照读改成当前读,可重复读下范围查询会加上 gap 锁 diff --git a/mysql/6.dead-lock.md b/mysql/6.dead-lock.md new file mode 100644 index 0000000..09aee74 --- /dev/null +++ b/mysql/6.dead-lock.md @@ -0,0 +1,52 @@ +# 死锁 + +- [死锁](#死锁) + - [死锁原因](#死锁原因) + - [锁类型](#锁类型) + - [S 锁](#s-锁) + - [X 锁](#x-锁) + - [gap 锁](#gap-锁) + - [auto-inc 锁](#auto-inc-锁) + - [插入意向锁](#插入意向锁) + - [解决死锁](#解决死锁) + +## 死锁原因 + +- 多个事务并发执行时因争夺资源而造成互相等待 +- 相反顺序加锁 +- 外键和触发器等隐式给子表加锁 +- S 锁和 X 锁冲突 +- 已经获取 gap 锁后,尝试获取插入意向锁造成等待 + +## 锁类型 + +### S 锁 + +- 可串行化中,查询自动加 S 锁 +- 可重复读中,查询可以手动加 S 锁 + +### X 锁 + +- 查询中,使用 for update 加 X 锁 +- 删除或更新自动加 X 锁 + +### gap 锁 + +- 可重复读中,范围操作或未命中加 gap 锁,避免幻读 + +### auto-inc 锁 + +- 插入时的特殊锁,插入后马上释放 + +### 插入意向锁 + +- 插入意图锁是一种间隙锁,在执行插入之前设置 +- 插入意向锁只会和间隙锁或者 Next-key 锁冲突 + +## 解决死锁 + +- 修改 SQL,调整加锁顺序 +- 降低隔离级别 +- 添加合理的索引,不走索引会全表加锁 +- 避免大事务 +- 避免同一个时间点执行多个操作同一表的事务 diff --git a/mysql/7.mvcc.md b/mysql/7.mvcc.md new file mode 100644 index 0000000..2fdca38 --- /dev/null +++ b/mysql/7.mvcc.md @@ -0,0 +1,30 @@ +# MVCC + +- [MVCC](#mvcc) + - [MVCC 特点](#mvcc-特点) + - [关键数据结构](#关键数据结构) + - [read view](#read-view) + - [聚集索引中隐藏的列](#聚集索引中隐藏的列) + +## MVCC 特点 + +- 一致性非锁定读 +- 解决隔离级别中的读优化 +- 读已提交中,mvcc 读取最新已提交版本 +- 可重复读中,mvcc 读取本事务开始前一个版本 + +## 关键数据结构 + +### read view + +- m_ids,创建 read view 时,启动未提交的事务 id +- min_trx_id,创建 read view 时,启动未提交的事务 id 中的最小值 +- max_trx_id,创建 read view 时,预分配给下一个事务的 id +- creator_trx_id,创建该 read view 的事务 id +- 读已提交中,每次读取操作创建 read view +- 可重复读中,每次开始事务创建 read view + +### 聚集索引中隐藏的列 + +- trx_id,记录修改事务 id +- roll_pointer,记录回滚版本在 undolog 中的位置 diff --git a/mysql/README.md b/mysql/README.md new file mode 100644 index 0000000..99130c6 --- /dev/null +++ b/mysql/README.md @@ -0,0 +1,9 @@ +# MySQL + +- [x] [SQL 优化](./1.sql.md) +- [x] [视图](./2.view.md) +- [x] [索引](./3.index.md) +- [x] [B+树](./4.B+tree.md) +- [x] [事务](./5.transaction.md) +- [x] [死锁](./6.dead-lock.md) +- [x] [MVCC](./7.mvcc.md) diff --git a/mysql/sql.png b/mysql/sql.png new file mode 100644 index 0000000..47a0dc1 Binary files /dev/null and b/mysql/sql.png differ