auto commit

This commit is contained in:
CyC2018 2018-05-30 22:13:29 +08:00
parent b04f8e35a4
commit 49370134c3

View File

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