diff --git a/notes/MySQL.md b/notes/MySQL.md index a51a9dd7..1f58643a 100644 --- a/notes/MySQL.md +++ b/notes/MySQL.md @@ -9,7 +9,7 @@ * [字符串](#字符串) * [时间和日期](#时间和日期) * [三、索引](#三索引) - * [B-Tree 和 B+Tree 原理](#b-tree-和-btree-原理) + * [B Tree 原理](#b-tree-原理) * [索引分类](#索引分类) * [索引的优点](#索引的优点) * [索引优化](#索引优化) @@ -119,17 +119,17 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提 # 三、索引 -索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。 - 索引能够轻易将查询性能提升几个数量级。 -对于非常小的表、大部分情况下简单的全表扫描比建立索引更高效。对于中到大型的表,索引就非常有效。但是对于特大型的表,建立和使用索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。 +对于非常小的表、大部分情况下简单的全表扫描比建立索引更高效。对于中到大型的表,索引就非常有效。但是对于特大型的表,建立和维护索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。 -## B-Tree 和 B+Tree 原理 +索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。 + +## B Tree 原理 ### 1. B-Tree -

+

定义一条数据记录为一个二元组 [key, data],B-Tree 是满足下列条件的数据结构: @@ -143,7 +143,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提 ### 2. B+Tree -

+

与 B-Tree 相比,B+Tree 有以下不同点: @@ -153,7 +153,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提 ### 3. 顺序访问指针 -

+

一般在数据库系统或文件系统中使用的 B+Tree 结构都在经典 B+Tree 基础上进行了优化,在叶子节点增加了顺序访问指针,做这个优化的目的是为了提高区间访问的性能。 @@ -161,7 +161,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提 红黑树等平衡树也可以用来实现索引,但是文件系统及数据库系统普遍采用 B+Tree 和 B-Tree 作为索引结构,主要有以下两个原因: -**(一)更少的检索次数** +(一)更少的检索次数 平衡树检索数据的时间复杂度等于树高 h,而树高大致为 O(h)=O(logdN),其中 d 为每个节点的出度。 @@ -169,7 +169,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提 B+Tree 相比于 B-Tree 更适合外存索引,因为 B+Tree 内节点去掉了 data 域,因此可以拥有更大的出度,检索效率会更高。 -**(二)利用计算机预读特性** +(二)利用计算机预读特性 为了减少磁盘 I/O,磁盘往往不是严格按需读取,而是每次都会预读。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的旋转时间,因此速度会非常快。 @@ -181,45 +181,50 @@ B+Tree 相比于 B-Tree 更适合外存索引,因为 B+Tree 内节点去掉了 ### 1. B+Tree 索引 -

- -《高性能 MySQL》一书使用 B-Tree 进行描述,其实从技术上来说这种索引是 B+Tree,因为只有叶子节点存储数据值。 - B+Tree 索引是大多数 MySQL 存储引擎的默认索引类型。 因为不再需要进行全表扫描,只需要对树进行搜索即可,因此查找速度快很多。除了用于查找,还可以用于排序和分组。 可以指定多个列作为索引列,多个索引列共同组成键。B+Tree 索引适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。如果不是按照索引列的顺序进行查找,则无法使用索引。 +InnoDB 的 B+Tree 索引分为主索引和辅助索引。 + +主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。 + +

+ +辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。 + +

+ + + + ### 2. 哈希索引 -基于哈希表实现,优点是查找非常快。 - -在 MySQL 中只有 Memory 引擎显式支持哈希索引。 - InnoDB 引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B+Tree 索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。 -限制: +哈希索引能以 O(1) 时间进行查找,但是失去了有序性,它具有以下限制: -- 哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中的行的速度很快,所以大部分情况下这一点对性能影响并不明显; - 无法用于排序与分组; - 只支持精确查找,无法用于部分查找和范围查找; - 如果哈希冲突很多,查找速度会变得很慢。 +- 哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中的行的速度很快,所以大部分情况下这一点对性能影响并不明显; -### 3. 空间数据索引(R-Tree) - -MyISAM 存储引擎支持空间数据索引,可以用于地理数据存储。 - -空间数据索引会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。 - -必须使用 GIS 相关的函数来维护数据。 - -### 4. 全文索引 +### 3. 全文索引 MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较是否相等。查找条件使用 MATCH AGAINST,而不是普通的 WHERE。 +全文索引一般使用倒排索引实现,它记录着关键词到其所在文档的映射。 + InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引。 +### 4. 空间数据索引(R-Tree) + +MyISAM 存储引擎支持空间数据索引,可以用于地理数据存储。空间数据索引会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。 + +必须使用 GIS 相关的函数来维护数据。 + ## 索引的优点 - 大大减少了服务器需要扫描的数据行数。 @@ -278,35 +283,12 @@ customer_id_selectivity: 0.0373 索引包含所有需要查询的字段的值。 -**优点** +具有以下优点优点: - 因为索引条目通常远小于数据行的大小,所以若只读取索引,能大大减少数据访问量。 - 一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。 - 对于 InnoDB 引擎,若二级索引能够覆盖查询,则无需访问聚簇索引。 -### 6. 聚簇索引 - -

- -聚簇索引并不是一种索引类型,而是一种数据存储方式。 - -术语“聚簇”表示数据行和相邻的键值紧密地存储在一起,InnoDB 的聚簇索引在同一个结构中保存了 B+Tree 索引和数据行。 - -因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。 - -**优点** - -- 可以把相关数据保存在一起,减少 I/O 操作。例如电子邮件表可以根据用户 ID 来聚集数据,这样只需要从磁盘读取少数的数据也就能获取某个用户的全部邮件,如果没有使用聚簇索引,则每封邮件都可能导致一次磁盘 I/O。 -- 数据访问更快。 - -**缺点** - -- 聚簇索引最大限度提高了 I/O 密集型应用的性能,但是如果数据全部放在内存,就没必要用聚簇索引。 -- 插入速度严重依赖于插入顺序,按主键的顺序插入是最快的。 -- 更新操作代价很高,因为每个被更新的行都会移动到新的位置。 -- 当插入到某个已满的页中,存储引擎会将该页分裂成两个页面来容纳该行,页分裂会导致表占用更多的磁盘空间。 -- 如果行比较稀疏,或者由于页分裂导致数据存储不连续时,聚簇索引可能导致全表扫描速度变慢。 - # 四、查询性能优化 ## 使用 Explain 进行分析 @@ -325,15 +307,15 @@ Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explai ### 1. 减少请求的数据量 -**(一)只返回必要的列** +(一)只返回必要的列 最好不要使用 SELECT * 语句。 -**(二)只返回必要的行** +(二)只返回必要的行 使用 WHERE 语句进行查询过滤,有时候也需要使用 LIMIT 语句来限制返回的数据。 -**(三)缓存重复查询的数据** +(三)缓存重复查询的数据 使用缓存可以避免在数据库中进行查询,特别要查询的数据经常被重复查询,缓存可以带来的查询性能提升将会是非常明显的。 @@ -456,6 +438,7 @@ MySQL 读写分离能提高性能的原因在于: # 参考资料 - BaronScbwartz, PeterZaitsev, VadimTkacbenko, 等. 高性能 MySQL[M]. 电子工业出版社, 2013. +- 姜承尧. MySQL 技术内幕: InnoDB 存储引擎 [M]. 机械工业出版社, 2011. - [20+ 条 MySQL 性能优化的最佳经验](https://www.jfox.info/20-tiao-mysql-xing-nen-you-hua-de-zui-jia-jing-yan.html) - [服务端指南 数据存储篇 | MySQL(09) 分库与分表带来的分布式困境与应对之策](http://blog.720ui.com/2017/mysql_core_09_multi_db_table2/ "服务端指南 数据存储篇 | MySQL(09) 分库与分表带来的分布式困境与应对之策") - [How to create unique row ID in sharded databases?](https://stackoverflow.com/questions/788829/how-to-create-unique-row-id-in-sharded-databases) diff --git a/pics/061c88c1-572f-424f-b580-9cbce903a3fe.png b/pics/061c88c1-572f-424f-b580-9cbce903a3fe.png new file mode 100644 index 00000000..eb25a980 Binary files /dev/null and b/pics/061c88c1-572f-424f-b580-9cbce903a3fe.png differ diff --git a/pics/06976908-98ab-46e9-a632-f0c2760ec46c.png b/pics/06976908-98ab-46e9-a632-f0c2760ec46c.png new file mode 100644 index 00000000..f042f8f6 Binary files /dev/null and b/pics/06976908-98ab-46e9-a632-f0c2760ec46c.png differ diff --git a/pics/7299afd2-9114-44e6-9d5e-4025d0b2a541.png b/pics/7299afd2-9114-44e6-9d5e-4025d0b2a541.png new file mode 100644 index 00000000..812d4643 Binary files /dev/null and b/pics/7299afd2-9114-44e6-9d5e-4025d0b2a541.png differ diff --git a/pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg b/pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg new file mode 100644 index 00000000..31c70314 Binary files /dev/null and b/pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg differ diff --git a/pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg b/pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg new file mode 100644 index 00000000..593513fe Binary files /dev/null and b/pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg differ