diff --git a/notes/MySQL.md b/notes/MySQL.md
index fe9ba7da..0e39a69c 100644
--- a/notes/MySQL.md
+++ b/notes/MySQL.md
@@ -9,10 +9,10 @@
* [字符串](#字符串)
* [时间和日期](#时间和日期)
* [三、索引](#三索引)
+ * [B-Tree 和 B+Tree 原理](#b-tree-和-btree-原理)
* [索引分类](#索引分类)
* [索引的优点](#索引的优点)
* [索引优化](#索引优化)
- * [B-Tree 和 B+Tree 原理](#b-tree-和-btree-原理)
* [四、查询性能优化](#四查询性能优化)
* [使用 Explain 进行分析](#使用-explain-进行分析)
* [优化数据访问](#优化数据访问)
@@ -34,7 +34,7 @@ InnoDB 是 MySQL 默认的事务型存储引擎,只有在需要 InnoDB 不支
采用 MVCC 来支持高并发,并且实现了四个标准的隔离级别,默认级别是可重复读(REPEATABLE READ),并且通过间隙锁(next-key locking)策略防止幻读的出现。间隙锁使得 InnoDB 不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻影行的插入。
-表是基于聚簇索引建立的,它对主键的查询性能有很高的提升。
+表是基于聚簇索引建立的,它对主键的查询性能有很大的提升。
内部做了很多优化,包括从磁盘读取数据时采用的可预测性读、能够自动在内存中创建哈希索引以加速读操作的自适应哈希索引、能够加速插入操作的插入缓冲区等。
@@ -42,7 +42,7 @@ InnoDB 是 MySQL 默认的事务型存储引擎,只有在需要 InnoDB 不支
## MyISAM
-MyISAM 提供了大量的特性,包括全文索引、压缩表、空间数据索引等。应该注意的是,MySQL 5.6.4 也添加了对 InnoDB 存储引擎的全文索引支持。
+MyISAM 提供了大量的特性,包括压缩表、空间数据索引等。
不支持事务。
@@ -120,6 +120,58 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
对于非常小的表、大部分情况下简单的全表扫描比建立索引更高效。对于中到大型的表,索引就非常有效。但是对于特大型的表,建立和使用索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。
+## B-Tree 和 B+Tree 原理
+
+### 1. B-Tree
+
+
+
+定义一条数据记录为一个二元组 [key, data],B-Tree 是满足下列条件的数据结构:
+
+- 所有叶节点具有相同的深度,也就是说 B-Tree 是平衡的;
+- 一个节点中的 key 从左到右非递减排列;
+- 如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1,且不为 null,则该指针指向节点的所有 key 大于等于 keyi 且小于等于 keyi+1。
+
+查找算法:首先在根节点进行二分查找,如果找到则返回对应节点的 data,否则在相应区间的指针指向的节点递归进行查找。
+
+由于插入删除新的数据记录会破坏 B-Tree 的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持 B-Tree 性质。
+
+### 2. B+Tree
+
+
+
+与 B-Tree 相比,B+Tree 有以下不同点:
+
+- 每个节点的指针上限为 2d 而不是 2d+1(d 为节点的出度);
+- 内节点不存储 data,只存储 key;
+- 叶子节点不存储指针。
+
+### 3. 顺序访问指针
+
+
+
+一般在数据库系统或文件系统中使用的 B+Tree 结构都在经典 B+Tree 基础上进行了优化,在叶子节点增加了顺序访问指针,做这个优化的目的是为了提高区间访问的性能。
+
+### 4. B+Tree 和 B-Tree 优势
+
+红黑树等平衡树也可以用来实现索引,但是文件系统及数据库系统普遍采用 B+Tree 和 B-Tree 作为索引结构,主要有以下两个原因:
+
+**(一)更少的检索次数**
+
+平衡树检索数据的时间复杂度等于树高 h,而树高大致为 O(h)=O(logdN),其中 d 为每个节点的出度。
+
+红黑树的出度为 2,而 B+Tree 与 B-Tree 的出度一般都非常大。红黑树的树高 h 很明显比 B+Tree 和 B-Tree 大非常多,因此检索的次数也就更多。
+
+B+Tree 相比于 B-Tree 更适合外存索引,因为 B+Tree 内节点去掉了 data 域,因此可以拥有更大的出度,检索效率会更高。
+
+**(二)利用计算机预读特性**
+
+为了减少磁盘 I/O,磁盘往往不是严格按需读取,而是每次都会预读。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的旋转时间,因此速度会非常快。
+
+操作系统一般将内存和磁盘分割成固态大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点,并且可以利用预读特性,临近的节点也能够被预先载入。
+
+更多内容请参考:[MySQL 索引背后的数据结构及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
+
## 索引分类
### 1. B+Tree 索引
@@ -130,13 +182,9 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
B+Tree 索引是大多数 MySQL 存储引擎的默认索引类型。
-因为不再需要进行全表扫描,只需要对树进行搜索即可,因此查找速度快很多。
+因为不再需要进行全表扫描,只需要对树进行搜索即可,因此查找速度快很多。除了用于查找,还可以用于排序和分组。
-可以指定多个列作为索引列,多个索引列共同组成键。B+Tree 索引适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。
-
-除了用于查找,还可以用于排序和分组。
-
-如果不是按照索引列的顺序进行查找,则无法使用索引。
+可以指定多个列作为索引列,多个索引列共同组成键。B+Tree 索引适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。如果不是按照索引列的顺序进行查找,则无法使用索引。
### 2. 哈希索引
@@ -163,9 +211,9 @@ MyISAM 存储引擎支持空间数据索引,可以用于地理数据存储。
### 4. 全文索引
-MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较索引中的值。
+MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比值是否相等。查找条件使用 MATCH AGAINST,而不是普通的 WHERE。
-查找条件使用 MATCH AGAINST,而不是普通的 WHERE。
+InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引。
## 索引的优点
@@ -187,13 +235,7 @@ MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;
```
-### 2. 前缀索引
-
-对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。
-
-对于前缀长度的选取需要根据 **索引选择性** 来确定:不重复的索引值和记录总数的比值。选择性越高,查询效率也越高。最大值为 1,此时每个记录都有唯一的索引与其对应。
-
-### 3. 多列索引
+### 2. 多列索引
在需要使用多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好。例如下面的语句中,最好把 actor_id 和 film_id 设置为多列索引。
@@ -202,9 +244,11 @@ SELECT film_id, actor_ id FROM sakila.film_actor
WhERE actor_id = 1 AND film_id = 1;
```
-### 4. 索引列的顺序
+### 3. 索引列的顺序
-让选择性最强的索引列放在前面,例如下面显示的结果中 customer_id 的选择性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。
+让选择性最强的索引列放在前面,索引的选择性是指:不重复的索引值和记录总数的比值。最大值为 1,此时每个记录都有唯一的索引与其对应。选择性越高,查询效率也越高。
+
+例如下面显示的结果中 customer_id 的选择性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。
```sql
SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,
@@ -219,7 +263,23 @@ customer_id_selectivity: 0.0373
COUNT(*): 16049
```
-### 5. 聚簇索引
+### 4. 前缀索引
+
+对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。
+
+对于前缀长度的选取需要根据索引选择性来确定。
+
+### 5. 覆盖索引
+
+索引包含所有需要查询的字段的值。
+
+**优点**
+
+- 因为索引条目通常远小于数据行的大小,所以若只读取索引,能大大减少数据访问量。
+- 一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。
+- 对于 InnoDB 引擎,若二级索引能够覆盖查询,则无需访问聚簇索引。
+
+### 6. 聚簇索引
@@ -231,77 +291,16 @@ customer_id_selectivity: 0.0373
**优点**
-1. 可以把相关数据保存在一起,减少 I/O 操作。例如电子邮件表可以根据用户 ID 来聚集数据,这样只需要从磁盘读取少数的数据也就能获取某个用户的全部邮件,如果没有使用聚聚簇索引,则每封邮件都可能导致一次磁盘 I/O。
-2. 数据访问更快。
+- 可以把相关数据保存在一起,减少 I/O 操作。例如电子邮件表可以根据用户 ID 来聚集数据,这样只需要从磁盘读取少数的数据也就能获取某个用户的全部邮件,如果没有使用聚聚簇索引,则每封邮件都可能导致一次磁盘 I/O。
+- 数据访问更快。
**缺点**
-1. 聚簇索引最大限度提高了 I/O 密集型应用的性能,但是如果数据全部放在内存,就没必要用聚簇索引。
-2. 插入速度严重依赖于插入顺序,按主键的顺序插入是最快的。
-3. 更新操作代价很高,因为每个被更新的行都会移动到新的位置。
-4. 当插入到某个已满的页中,存储引擎会将该页分裂成两个页面来容纳该行,页分裂会导致表占用更多的磁盘空间。
-5. 如果行比较稀疏,或者由于页分裂导致数据存储不连续时,聚簇索引可能导致全表扫描速度变慢。
-
-### 6. 覆盖索引
-
-索引包含所有需要查询的字段的值。
-
-**优点**
-
-1. 因为索引条目通常远小于数据行的大小,所以若只读取索引,能大大减少数据访问量。
-2. 一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。
-3. 对于 InnoDB 引擎,若二级索引能够覆盖查询,则无需访问聚簇索引。
-
-## B-Tree 和 B+Tree 原理
-
-### 1. B-Tree
-
-
-
-定义一条数据记录为一个二元组 [key, data],B-Tree 是满足下列条件的数据结构:
-
-- 所有叶节点具有相同的深度,也就是说 B-Tree 是平衡的;
-- 一个节点中的 key 从左到右非递减排列;
-- 如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1,且不为 null,则该指针指向节点的所有 key 大于等于 keyi 且小于等于 keyi+1。
-
-在 B-Tree 中按 key 检索数据的算法非常直观:首先在根节点进行二分查找,如果找到则返回对应节点的 data,否则在相应区间的指针指向的节点递归进行查找。
-
-由于插入删除新的数据记录会破坏 B-Tree 的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持 B-Tree 性质。
-
-### 2. B+Tree
-
-
-
-与 B-Tree 相比,B+Tree 有以下不同点:
-
-- 每个节点的指针上限为 2d 而不是 2d+1;
-- 内节点不存储 data,只存储 key,叶子节点不存储指针。
-
-### 3. 带有顺序访问指针的 B+Tree
-
-
-
-一般在数据库系统或文件系统中使用的 B+Tree 结构都在经典 B+Tree 基础上进行了优化,在叶子节点增加了顺序访问指针,做这个优化的目的是为了提高区间访问的性能。
-
-### 4. 为什么使用 B+Tree 和 B-Tree
-
-红黑树等平衡树也可以用来实现索引,但是文件系统及数据库系统普遍采用 B+Tree B-Tree 作为索引结构,主要有以下两个原因:
-
-**(一)更少的检索次数**
-
-红黑树和 B+Tree B-Tree 检索数据的时间复杂度等于树高 h,而树高大致为 O(h)=O(logdN),其中 d 为每个节点的出度。
-
-红黑树的出度为 2,而 B+Tree 与 B-Tree 的出度一般都非常大。红黑树的树高 h 很明显比 B+Tree B-Tree 大非常多,因此检索的次数也就更多。
-
-B+Tree 相比于 B-Tree 更适合外存索引,因为 B+Tree 内节点去掉了 data 域,因此可以拥有更大的出度,检索效率会更高。
-
-**(二)利用计算机预读特性**
-
-为了减少磁盘 I/O,磁盘往往不是严格按需读取,而是每次都会预读。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的旋转时间,因此速度会非常快。
-
-操作系统一般将内存和磁盘分割成固态大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点,并且可以利用预读特性,临近的节点也能够被预先载入。
-
-更多内容请参考:[MySQL 索引背后的数据结构及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
+- 聚簇索引最大限度提高了 I/O 密集型应用的性能,但是如果数据全部放在内存,就没必要用聚簇索引。
+- 插入速度严重依赖于插入顺序,按主键的顺序插入是最快的。
+- 更新操作代价很高,因为每个被更新的行都会移动到新的位置。
+- 当插入到某个已满的页中,存储引擎会将该页分裂成两个页面来容纳该行,页分裂会导致表占用更多的磁盘空间。
+- 如果行比较稀疏,或者由于页分裂导致数据存储不连续时,聚簇索引可能导致全表扫描速度变慢。
# 四、查询性能优化
@@ -355,14 +354,14 @@ do {
} while rows_affected > 0
```
-### 2. 分解关联查询
+### 2. 分解大连接查询
-将一个关联查询分解成对每一个表进行一次单表查询,然后将结果在应用程序中进行关联,这样做的好处有:
+将一个大连接查询(JOIN)分解成对每一个表进行一次单表查询,然后将结果在应用程序中进行关联,这样做的好处有:
-- 让缓存更高效。对于关联查询,如果其中一个表发生变化,那么整个查询缓存就无法使用。而分解后的多个查询,即使其中一个表发生变化,对其它表的查询缓存依然可以使用。
+- 让缓存更高效。对于连接查询,如果其中一个表发生变化,那么整个查询缓存就无法使用。而分解后的多个查询,即使其中一个表发生变化,对其它表的查询缓存依然可以使用。
- 减少锁竞争;
-- 在应用层进行关联,可以更容易对数据库进行拆分,从而更容易做到高性能和可扩展。
-- 查询本身效率也可能会有所提升。例如下面的例子中,使用 IN() 代替关联查询,可以让 MySQL 按照 ID 顺序进行查询,这可能比随机的关联要更高效。
+- 在应用层进行连接,可以更容易对数据库进行拆分,从而更容易做到高性能和可扩展。
+- 查询本身效率也可能会有所提升。例如下面的例子中,使用 IN() 代替连接查询,可以让 MySQL 按照 ID 顺序进行查询,这可能比随机的连接要更高效。
- 分解成多个单表查询,这些单表查询的缓存结果更可能被其它查询使用到,从而减少冗余记录的查询。
```sql