MySQL.md 20.5 KB
Newer Older
C
CyC2018 已提交
1
<!-- GFM-TOC -->
C
CyC2018 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
* [一、索引](#一索引)
    * [B+ Tree 原理](#b-tree-原理)
    * [MySQL 索引](#mysql-索引)
    * [索引优化](#索引优化)
    * [索引的优点](#索引的优点)
    * [索引的使用条件](#索引的使用条件)
* [二、查询性能优化](#二查询性能优化)
    * [使用 Explain 进行分析](#使用-explain-进行分析)
    * [优化数据访问](#优化数据访问)
    * [重构查询方式](#重构查询方式)
* [三、存储引擎](#三存储引擎)
    * [InnoDB](#innodb)
    * [MyISAM](#myisam)
    * [比较](#比较)
* [四、数据类型](#四数据类型)
    * [整型](#整型)
    * [浮点数](#浮点数)
    * [字符串](#字符串)
    * [时间和日期](#时间和日期)
* [五、切分](#五切分)
    * [水平切分](#水平切分)
    * [垂直切分](#垂直切分)
    * [Sharding 策略](#sharding-策略)
    * [Sharding 存在的问题](#sharding-存在的问题)
* [六、复制](#六复制)
    * [主从复制](#主从复制)
    * [读写分离](#读写分离)
* [参考资料](#参考资料)
C
CyC2018 已提交
30
<!-- GFM-TOC -->
C
CyC2018 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44


# 一、索引

## B+ Tree 原理

### 1. 数据结构

B Tree 指的是 Balance Tree,也就是平衡树。平衡树是一颗查找树,并且所有叶子节点位于同一层。

B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具有 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>

C
CyC2018 已提交
45
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/33576849-9275-47bb-ada7-8ded5f5e7c73.png" width="350px"> </div><br>
C
CyC2018 已提交
46 47 48 49

### 2. 操作

进行查找操作时,首先在根节点进行二分查找,找到一个 key 所在的指针,然后递归地在指针所指向的节点进行查找。直到查找到叶子节点,然后在叶子节点上进行二分查找,找出 key 所对应的 data。
C
CyC2018 已提交
50

C
CyC2018 已提交
51
插入删除操作会破坏平衡树的平衡性,因此在插入删除操作之后,需要对树进行一个分裂、合并、旋转等操作来维护平衡性。
C
CyC2018 已提交
52

C
CyC2018 已提交
53
### 3. 与红黑树的比较
C
CyC2018 已提交
54

C
CyC2018 已提交
55
红黑树等平衡树也可以用来实现索引,但是文件系统及数据库系统普遍采用 B+ Tree 作为索引结构,主要有以下两个原因:
C
CyC2018 已提交
56

C
CyC2018 已提交
57
(一)更少的查找次数
C
CyC2018 已提交
58

C
CyC2018 已提交
59
平衡树查找操作的时间复杂度和树高 h 相关,O(h)=O(log<sub>d</sub>N),其中 d 为每个节点的出度。
C
CyC2018 已提交
60

C
CyC2018 已提交
61
红黑树的出度为 2,而 B+ Tree 的出度一般都非常大,所以红黑树的树高 h 很明显比 B+ Tree 大非常多,查找的次数也就更多。
C
CyC2018 已提交
62

C
CyC2018 已提交
63
(二)利用磁盘预读特性
C
CyC2018 已提交
64

C
CyC2018 已提交
65
为了减少磁盘 I/O 操作,磁盘往往不是严格按需读取,而是每次都会预读。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的磁盘旋转时间,速度会非常快。
C
CyC2018 已提交
66

C
CyC2018 已提交
67
操作系统一般将内存和磁盘分割成固定大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点。并且可以利用预读特性,相邻的节点也能够被预先载入。
C
CyC2018 已提交
68

C
CyC2018 已提交
69
## MySQL 索引
C
CyC2018 已提交
70 71

索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。
C
CyC2018 已提交
72

C
CyC2018 已提交
73
### 1. B+Tree 索引
C
CyC2018 已提交
74

C
CyC2018 已提交
75
是大多数 MySQL 存储引擎的默认索引类型。
C
CyC2018 已提交
76

C
CyC2018 已提交
77 78
因为不再需要进行全表扫描,只需要对树进行搜索即可,所以查找速度快很多。

C
CyC2018 已提交
79
因为 B+ Tree 的有序性,所以除了用于查找,还可以用于排序和分组。
C
CyC2018 已提交
80

C
CyC2018 已提交
81 82
可以指定多个列作为索引列,多个索引列共同组成键。

C
CyC2018 已提交
83
适用于全键值、键值范围和键前缀查找,其中键前缀查找只适用于最左前缀查找。如果不是按照索引列的顺序进行查找,则无法使用索引。
C
CyC2018 已提交
84

C
CyC2018 已提交
85
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
C
CyC2018 已提交
86

C
CyC2018 已提交
87
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/45016e98-6879-4709-8569-262b2d6d60b9.png" width="350px"> </div><br>
C
CyC2018 已提交
88

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

C
CyC2018 已提交
91
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7c349b91-050b-4d72-a7f8-ec86320307ea.png" width="350px"> </div><br>
C
CyC2018 已提交
92

C
CyC2018 已提交
93
### 2. 哈希索引
C
CyC2018 已提交
94

C
CyC2018 已提交
95
哈希索引能以 O(1) 时间进行查找,但是失去了有序性:
C
CyC2018 已提交
96

C
CyC2018 已提交
97 98
- 无法用于排序与分组;
- 只支持精确查找,无法用于部分查找和范围查找。
C
CyC2018 已提交
99

C
CyC2018 已提交
100
InnoDB 存储引擎有一个特殊的功能叫“自适应哈希索引”,当某个索引值被使用的非常频繁时,会在 B+Tree 索引之上再创建一个哈希索引,这样就让 B+Tree 索引具有哈希索引的一些优点,比如快速的哈希查找。
C
CyC2018 已提交
101

C
CyC2018 已提交
102
### 3. 全文索引
C
CyC2018 已提交
103

C
CyC2018 已提交
104
MyISAM 存储引擎支持全文索引,用于查找文本中的关键词,而不是直接比较是否相等。
C
CyC2018 已提交
105

C
CyC2018 已提交
106
查找条件使用 MATCH AGAINST,而不是普通的 WHERE。
C
CyC2018 已提交
107

C
CyC2018 已提交
108
全文索引使用倒排索引实现,它记录着关键词到其所在文档的映射。
C
CyC2018 已提交
109

C
CyC2018 已提交
110
InnoDB 存储引擎在 MySQL 5.6.4 版本中也开始支持全文索引。
C
CyC2018 已提交
111

C
CyC2018 已提交
112
### 4. 空间数据索引
C
CyC2018 已提交
113

C
CyC2018 已提交
114
MyISAM 存储引擎支持空间数据索引(R-Tree),可以用于地理数据存储。空间数据索引会从所有维度来索引数据,可以有效地使用任意维度来进行组合查询。
C
CyC2018 已提交
115

C
CyC2018 已提交
116
必须使用 GIS 相关的函数来维护数据。
C
CyC2018 已提交
117

C
CyC2018 已提交
118
## 索引优化
C
CyC2018 已提交
119

C
CyC2018 已提交
120
### 1. 独立的列
C
CyC2018 已提交
121 122 123

在进行查询时,索引列不能是表达式的一部分,也不能是函数的参数,否则无法使用索引。

C
CyC2018 已提交
124
例如下面的查询不能使用 actor_id 列的索引:
C
CyC2018 已提交
125 126

```sql
C
CyC2018 已提交
127
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;
C
CyC2018 已提交
128 129
```

C
CyC2018 已提交
130
### 2. 多列索引
C
CyC2018 已提交
131

C
CyC2018 已提交
132
在需要使用多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好。例如下面的语句中,最好把 actor_id 和 film_id 设置为多列索引。
C
CyC2018 已提交
133 134

```sql
C
CyC2018 已提交
135 136
SELECT film_id, actor_ id FROM sakila.film_actor
WHERE actor_id = 1 AND film_id = 1;
C
CyC2018 已提交
137 138
```

C
CyC2018 已提交
139
### 3. 索引列的顺序
C
CyC2018 已提交
140

C
CyC2018 已提交
141 142
让选择性最强的索引列放在前面。

C
CyC2018 已提交
143
索引的选择性是指:不重复的索引值和记录总数的比值。最大值为 1,此时每个记录都有唯一的索引与其对应。选择性越高,每个记录的区分度越高,查询效率也越高。
C
CyC2018 已提交
144

C
CyC2018 已提交
145
例如下面显示的结果中 customer_id 的选择性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。
C
CyC2018 已提交
146 147

```sql
C
CyC2018 已提交
148 149
SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,
COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,
C
CyC2018 已提交
150
COUNT(*)
C
CyC2018 已提交
151
FROM payment;
C
CyC2018 已提交
152 153 154
```

```html
C
CyC2018 已提交
155 156 157
   staff_id_selectivity: 0.0001
customer_id_selectivity: 0.0373
               COUNT(*): 16049
C
CyC2018 已提交
158 159
```

C
CyC2018 已提交
160
### 4. 前缀索引
C
CyC2018 已提交
161

C
CyC2018 已提交
162
对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。
C
CyC2018 已提交
163

C
CyC2018 已提交
164
前缀长度的选取需要根据索引选择性来确定。
C
CyC2018 已提交
165

C
CyC2018 已提交
166
### 5. 覆盖索引
C
CyC2018 已提交
167 168 169

索引包含所有需要查询的字段的值。

C
CyC2018 已提交
170
具有以下优点:
C
CyC2018 已提交
171

C
CyC2018 已提交
172 173 174
- 索引通常远小于数据行的大小,只读取索引能大大减少数据访问量。
- 一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。
- 对于 InnoDB 引擎,若辅助索引能够覆盖查询,则无需访问主索引。
C
CyC2018 已提交
175

C
CyC2018 已提交
176
## 索引的优点
C
CyC2018 已提交
177

C
CyC2018 已提交
178
- 大大减少了服务器需要扫描的数据行数。
C
CyC2018 已提交
179

C
CyC2018 已提交
180
- 帮助服务器避免进行排序和分组,以及避免创建临时表(B+Tree 索引是有序的,可以用于 ORDER BY 和 GROUP BY 操作。临时表主要是在排序和分组过程中创建,不需要排序和分组,也就不需要创建临时表)。
C
CyC2018 已提交
181

C
CyC2018 已提交
182
- 将随机 I/O 变为顺序 I/O(B+Tree 索引是有序的,会将相邻的数据都存储在一起)。
C
CyC2018 已提交
183

C
CyC2018 已提交
184
## 索引的使用条件
C
CyC2018 已提交
185

C
CyC2018 已提交
186
- 对于非常小的表、大部分情况下简单的全表扫描比建立索引更高效;
C
CyC2018 已提交
187

C
CyC2018 已提交
188
- 对于中到大型的表,索引就非常有效;
C
CyC2018 已提交
189

C
CyC2018 已提交
190
- 但是对于特大型的表,建立和维护索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。
C
CyC2018 已提交
191

C
CyC2018 已提交
192
# 二、查询性能优化
C
CyC2018 已提交
193

C
CyC2018 已提交
194
## 使用 Explain 进行分析
C
CyC2018 已提交
195

C
CyC2018 已提交
196
Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explain 结果来优化查询语句。
C
CyC2018 已提交
197

C
CyC2018 已提交
198
比较重要的字段有:
C
CyC2018 已提交
199

C
CyC2018 已提交
200 201 202
- select_type : 查询类型,有简单查询、联合查询、子查询等
- key : 使用的索引
- rows : 扫描的行数
C
CyC2018 已提交
203

C
CyC2018 已提交
204
## 优化数据访问
C
CyC2018 已提交
205

C
CyC2018 已提交
206
### 1. 减少请求的数据量
C
CyC2018 已提交
207

C
CyC2018 已提交
208 209 210
- 只返回必要的列:最好不要使用 SELECT * 语句。
- 只返回必要的行:使用 LIMIT 语句来限制返回的数据。
- 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要查询的数据经常被重复查询时,缓存带来的查询性能提升将会是非常明显的。
C
CyC2018 已提交
211

C
CyC2018 已提交
212
### 2. 减少服务器端扫描的行数
C
CyC2018 已提交
213 214

最有效的方式是使用索引来覆盖查询。
C
CyC2018 已提交
215

C
CyC2018 已提交
216
## 重构查询方式
C
CyC2018 已提交
217

C
CyC2018 已提交
218
### 1. 切分大查询
C
CyC2018 已提交
219 220

一个大查询如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。
C
CyC2018 已提交
221 222

```sql
C
CyC2018 已提交
223
DELETE FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH);
C
CyC2018 已提交
224 225 226
```

```sql
C
CyC2018 已提交
227 228 229 230 231
rows_affected = 0
do {
    rows_affected = do_query(
    "DELETE FROM messages WHERE create  < DATE_SUB(NOW(), INTERVAL 3 MONTH) LIMIT 10000")
} while rows_affected > 0
C
CyC2018 已提交
232 233
```

C
CyC2018 已提交
234
### 2. 分解大连接查询
C
CyC2018 已提交
235

C
CyC2018 已提交
236
将一个大连接查询分解成对每一个表进行一次单表查询,然后在应用程序中进行关联,这样做的好处有:
C
CyC2018 已提交
237

C
CyC2018 已提交
238 239 240 241 242
- 让缓存更高效。对于连接查询,如果其中一个表发生变化,那么整个查询缓存就无法使用。而分解后的多个查询,即使其中一个表发生变化,对其它表的查询缓存依然可以使用。
- 分解成多个单表查询,这些单表查询的缓存结果更可能被其它查询使用到,从而减少冗余记录的查询。
- 减少锁竞争;
- 在应用层进行连接,可以更容易对数据库进行拆分,从而更容易做到高性能和可伸缩。
- 查询本身效率也可能会有所提升。例如下面的例子中,使用 IN() 代替连接查询,可以让 MySQL 按照 ID 顺序进行查询,这可能比随机的连接要更高效。
C
CyC2018 已提交
243 244

```sql
C
CyC2018 已提交
245 246 247 248
SELECT * FROM tab
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag='mysql';
C
CyC2018 已提交
249 250 251
```

```sql
C
CyC2018 已提交
252 253 254
SELECT * FROM tag WHERE tag='mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);
C
CyC2018 已提交
255 256
```

C
CyC2018 已提交
257
# 三、存储引擎
C
CyC2018 已提交
258

C
CyC2018 已提交
259
## InnoDB
C
CyC2018 已提交
260

C
CyC2018 已提交
261
是 MySQL 默认的事务型存储引擎,只有在需要它不支持的特性时,才考虑使用其它存储引擎。
C
CyC2018 已提交
262

C
CyC2018 已提交
263
实现了四个标准的隔离级别,默认级别是可重复读(REPEATABLE READ)。在可重复读隔离级别下,通过多版本并发控制(MVCC)+ 间隙锁(Next-Key Locking)防止幻影读。
C
CyC2018 已提交
264 265 266 267 268 269 270

主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。

内部做了很多优化,包括从磁盘读取数据时采用的可预测性读、能够加快读操作并且自动创建的自适应哈希索引、能够加速插入操作的插入缓冲区等。

支持真正的在线热备份。其它存储引擎不支持在线热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。

C
CyC2018 已提交
271
## MyISAM
C
CyC2018 已提交
272 273 274 275 276 277 278

设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。

提供了大量的特性,包括压缩表、空间数据索引等。

不支持事务。

C
CyC2018 已提交
279
不支持行级锁,只能对整张表加锁,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。
C
CyC2018 已提交
280 281 282

可以手工或者自动执行检查和修复操作,但是和事务恢复以及崩溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的。

C
CyC2018 已提交
283
如果指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。
C
CyC2018 已提交
284

C
CyC2018 已提交
285
## 比较
C
CyC2018 已提交
286

C
CyC2018 已提交
287
- 事务:InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句。
C
CyC2018 已提交
288

C
CyC2018 已提交
289
- 并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
C
CyC2018 已提交
290

C
CyC2018 已提交
291
- 外键:InnoDB 支持外键。
C
CyC2018 已提交
292

C
CyC2018 已提交
293
- 备份:InnoDB 支持在线热备份。
C
CyC2018 已提交
294

C
CyC2018 已提交
295
- 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。
C
CyC2018 已提交
296

C
CyC2018 已提交
297
- 其它特性:MyISAM 支持压缩表和空间数据索引。
C
CyC2018 已提交
298

C
CyC2018 已提交
299
# 四、数据类型
C
CyC2018 已提交
300

C
CyC2018 已提交
301
## 整型
C
CyC2018 已提交
302

C
CyC2018 已提交
303
TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 分别使用 8, 16, 24, 32, 64 位存储空间,一般情况下越小的列越好。
C
CyC2018 已提交
304

C
CyC2018 已提交
305
INT(11) 中的数字只是规定了交互工具显示字符的个数,对于存储和计算来说是没有意义的。
C
CyC2018 已提交
306

C
CyC2018 已提交
307
## 浮点数
C
CyC2018 已提交
308

C
CyC2018 已提交
309
FLOAT 和 DOUBLE 为浮点类型,DECIMAL 为高精度小数类型。CPU 原生支持浮点运算,但是不支持 DECIMAl 类型的计算,因此 DECIMAL 的计算比浮点类型需要更高的代价。
C
CyC2018 已提交
310

C
CyC2018 已提交
311
FLOAT、DOUBLE 和 DECIMAL 都可以指定列宽,例如 DECIMAL(18, 9) 表示总共 18 位,取 9 位存储小数部分,剩下 9 位存储整数部分。
C
CyC2018 已提交
312

C
CyC2018 已提交
313
## 字符串
C
CyC2018 已提交
314

C
CyC2018 已提交
315
主要有 CHAR 和 VARCHAR 两种类型,一种是定长的,一种是变长的。
C
CyC2018 已提交
316

C
CyC2018 已提交
317
VARCHAR 这种变长类型能够节省空间,因为只需要存储必要的内容。但是在执行 UPDATE 时可能会使行变得比原来长,当超出一个页所能容纳的大小时,就要执行额外的操作。MyISAM 会将行拆成不同的片段存储,而 InnoDB 则需要分裂页来使行放进页内。
C
CyC2018 已提交
318

C
CyC2018 已提交
319
在进行存储和检索时,会保留 VARCHAR 末尾的空格,而会删除 CHAR 末尾的空格。
C
CyC2018 已提交
320

C
CyC2018 已提交
321
## 时间和日期
C
CyC2018 已提交
322

C
CyC2018 已提交
323
MySQL 提供了两种相似的日期时间类型:DATETIME 和 TIMESTAMP。
C
CyC2018 已提交
324

C
CyC2018 已提交
325
### 1. DATETIME
C
CyC2018 已提交
326

C
CyC2018 已提交
327
能够保存从 1000 年到 9999 年的日期和时间,精度为秒,使用 8 字节的存储空间。
C
CyC2018 已提交
328 329 330

它与时区无关。

C
CyC2018 已提交
331
默认情况下,MySQL 以一种可排序的、无歧义的格式显示 DATETIME 值,例如“2008-01-16 22<span>:</span>37<span>:</span>08”,这是 ANSI 标准定义的日期和时间表示方法。
C
CyC2018 已提交
332

C
CyC2018 已提交
333
### 2. TIMESTAMP
C
CyC2018 已提交
334

C
CyC2018 已提交
335
和 UNIX 时间戳相同,保存从 1970 年 1 月 1 日午夜(格林威治时间)以来的秒数,使用 4 个字节,只能表示从 1970 年到 2038 年。
C
CyC2018 已提交
336 337 338

它和时区有关,也就是说一个时间戳在不同的时区所代表的具体时间是不同的。

C
CyC2018 已提交
339
MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提供了 UNIX_TIMESTAMP() 函数把日期转换为 UNIX 时间戳。
C
CyC2018 已提交
340

C
CyC2018 已提交
341
默认情况下,如果插入时没有指定 TIMESTAMP 列的值,会将这个值设置为当前时间。
C
CyC2018 已提交
342

C
CyC2018 已提交
343
应该尽量使用 TIMESTAMP,因为它比 DATETIME 空间效率更高。
C
CyC2018 已提交
344

C
CyC2018 已提交
345
# 五、切分
C
CyC2018 已提交
346

C
CyC2018 已提交
347
## 水平切分
C
CyC2018 已提交
348

C
CyC2018 已提交
349
水平切分又称为 Sharding,它是将同一个表中的记录拆分到多个结构相同的表中。
C
CyC2018 已提交
350

C
CyC2018 已提交
351
当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
C
CyC2018 已提交
352

C
CyC2018 已提交
353
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg" width=""> </div><br>
C
CyC2018 已提交
354

C
CyC2018 已提交
355
## 垂直切分
C
CyC2018 已提交
356

C
CyC2018 已提交
357
垂直切分是将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。
C
CyC2018 已提交
358

C
CyC2018 已提交
359
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。
C
CyC2018 已提交
360

C
CyC2018 已提交
361
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg" width=""> </div><br>
C
CyC2018 已提交
362

C
CyC2018 已提交
363
## Sharding 策略
C
CyC2018 已提交
364

C
CyC2018 已提交
365 366 367
- 哈希取模:hash(key) % N;
- 范围:可以是 ID 范围也可以是时间范围;
- 映射表:使用单独的一个数据库来存储映射关系。
C
CyC2018 已提交
368

C
CyC2018 已提交
369
## Sharding 存在的问题
C
CyC2018 已提交
370

C
CyC2018 已提交
371
### 1. 事务问题
C
CyC2018 已提交
372

C
CyC2018 已提交
373
使用分布式事务来解决,比如 XA 接口。
C
CyC2018 已提交
374

C
CyC2018 已提交
375
### 2. 连接
C
CyC2018 已提交
376

C
CyC2018 已提交
377
可以将原来的连接分解成多个单表查询,然后在用户程序中进行连接。
C
CyC2018 已提交
378

C
CyC2018 已提交
379
### 3. ID 唯一性
C
CyC2018 已提交
380

C
CyC2018 已提交
381 382 383
- 使用全局唯一 ID(GUID)
- 为每个分片指定一个 ID 范围
- 分布式 ID 生成器 (如 Twitter 的 Snowflake 算法)
C
CyC2018 已提交
384

C
CyC2018 已提交
385
# 六、复制
C
CyC2018 已提交
386

C
CyC2018 已提交
387
## 主从复制
C
CyC2018 已提交
388

C
CyC2018 已提交
389
主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。
C
CyC2018 已提交
390

C
CyC2018 已提交
391 392
-  **binlog 线程** :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
-  **I/O 线程** :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。
C
CyC2018 已提交
393
-  **SQL 线程** :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中重放(Replay)。
C
CyC2018 已提交
394

C
CyC2018 已提交
395
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/master-slave.png" width=""> </div><br>
C
CyC2018 已提交
396

C
CyC2018 已提交
397
## 读写分离
C
CyC2018 已提交
398

C
CyC2018 已提交
399
主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。
C
CyC2018 已提交
400

C
CyC2018 已提交
401
读写分离能提高性能的原因在于:
C
CyC2018 已提交
402

C
CyC2018 已提交
403 404 405
- 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
- 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;
- 增加冗余,提高可用性。
C
CyC2018 已提交
406

C
CyC2018 已提交
407 408
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。

C
CyC2018 已提交
409
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/master-slave-proxy.png" width=""> </div><br>
C
CyC2018 已提交
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427

# 参考资料

- 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)
- [SQL Azure Federation – Introduction](http://geekswithblogs.net/shaunxu/archive/2012/01/07/sql-azure-federation-ndash-introduction.aspx "Title of this entry.")
- [MySQL 索引背后的数据结构及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
- [MySQL 性能优化神器 Explain 使用分析](https://segmentfault.com/a/1190000008131735)
- [How Sharding Works](https://medium.com/@jeeyoungk/how-sharding-works-b4dec46b3f6)
- [大众点评订单系统分库分表实践](https://tech.meituan.com/dianping_order_db_sharding.html)
- [B + 树](https://zh.wikipedia.org/wiki/B%2B%E6%A0%91)




C
CyC2018 已提交
428 429 430 431 432 433
# 微信公众号


微信公众号 CyC2018 提供了该项目的离线阅读版本,后台回复 "下载" 即可领取。也提供了一份技术面试复习大纲,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点,后台回复 "大纲" 即可领取。我基本是按照这个大纲来进行复习的,对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。


C
CyC2018 已提交
434
<img width="580px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/other/公众号海报2.png"></img>