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


C
CyC2018 已提交
34
# 一、索引
C
CyC2018 已提交
35

C
CyC2018 已提交
36
## B+ Tree 原理
C
CyC2018 已提交
37

C
CyC2018 已提交
38
### 1. 数据结构
C
CyC2018 已提交
39

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

C
CyC2018 已提交
42
B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具有 B Tree 的平衡性,并且通过顺序访问指针来提高区间查询的性能。
C
CyC2018 已提交
43

C
CyC2018 已提交
44
在 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

C
CyC2018 已提交
46
<div align="center"> <img src="pics/d5ce91a7-45f9-4560-9917-0dccd4900826.png" width="400px"> </div><br>
C
CyC2018 已提交
47

C
CyC2018 已提交
48
### 2. 操作
C
CyC2018 已提交
49

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

除了用于查找,还可以用于排序和分组。
C
CyC2018 已提交
81

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

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

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

C
CyC2018 已提交
88
<div align="center"> <img src="pics/0f6f92e8-f15e-4c09-8562-b9c6114df9ce.png" width="400px"> </div><br>
C
CyC2018 已提交
89

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

C
CyC2018 已提交
92
<div align="center"> <img src="pics/1e74234e-d70b-411c-9333-226bcbb9c8f0.png" width="400px"> </div><br>
C
CyC2018 已提交
93 94

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
177 178 179 180
## 索引的优点

- 大大减少了服务器需要扫描的数据行数。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```sql
C
CyC2018 已提交
228 229 230 231 232
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 已提交
233 234
```

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

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

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

```sql
C
CyC2018 已提交
246
SELECT * FROM tab
C
CyC2018 已提交
247 248 249
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 已提交
250 251 252
```

```sql
C
CyC2018 已提交
253 254 255
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 已提交
256 257
```

C
CyC2018 已提交
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
# 三、存储引擎

## InnoDB

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

实现了四个标准的隔离级别,默认级别是可重复读(REPEATABLE READ)。在可重复读隔离级别下,通过多版本并发控制(MVCC)+ 间隙锁(Next-Key Locking)防止幻影读。

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

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

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

## MyISAM

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

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

不支持事务。

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

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

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

## 比较

- 事务:InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句。

- 并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。

- 外键:InnoDB 支持外键。

- 备份:InnoDB 支持在线热备份。

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

- 其它特性:MyISAM 支持压缩表和空间数据索引。

# 四、数据类型

## 整型

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

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

## 浮点数

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

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

## 字符串

主要有 CHAR 和 VARCHAR 两种类型,一种是定长的,一种是变长的。

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

C
CyC2018 已提交
320
在进行存储和检索时,会保留 VARCHAR 末尾的空格,而会删除 CHAR 末尾的空格。
C
CyC2018 已提交
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

## 时间和日期

MySQL 提供了两种相似的日期时间类型:DATETIME 和 TIMESTAMP。

### 1. DATETIME

能够保存从 1001 年到 9999 年的日期和时间,精度为秒,使用 8 字节的存储空间。

它与时区无关。

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

### 2. TIMESTAMP

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

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

MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提供了 UNIX_TIMESTAMP() 函数把日期转换为 UNIX 时间戳。

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

应该尽量使用 TIMESTAMP,因为它比 DATETIME 空间效率更高。

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

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

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

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

C
fix  
CyC2018 已提交
354
<div align="center"> <img src="pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
C
CyC2018 已提交
355

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

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

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

C
fix  
CyC2018 已提交
362
<div align="center"> <img src="pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
C
CyC2018 已提交
363

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

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

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

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

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

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

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

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

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

C
CyC2018 已提交
386 387 388 389 390 391
# 六、复制

## 主从复制

主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。

C
CyC2018 已提交
392 393 394
-  **binlog 线程** :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
-  **I/O 线程** :负责从主服务器上读取二进制日志,并写入从服务器的重放日志(Replay log)中。
-  **SQL 线程** :负责读取重放日志并重放其中的 SQL 语句。
C
CyC2018 已提交
395

C
fix  
CyC2018 已提交
396
<div align="center"> <img src="pics/master-slave.png"/> </div><br>
C
CyC2018 已提交
397 398 399

## 读写分离

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

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

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

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

C
fix  
CyC2018 已提交
410
<div align="center"> <img src="pics/master-slave-proxy.png"/> </div><br>
C
CyC2018 已提交
411

C
CyC2018 已提交
412 413 414
# 参考资料

- BaronScbwartz, PeterZaitsev, VadimTkacbenko, 等. 高性能 MySQL[M]. 电子工业出版社, 2013.
C
CyC2018 已提交
415
- 姜承尧. MySQL 技术内幕: InnoDB 存储引擎 [M]. 机械工业出版社, 2011.
C
CyC2018 已提交
416 417 418 419
- [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.")
C
CyC2018 已提交
420
- [MySQL 索引背后的数据结构及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
C
CyC2018 已提交
421
- [MySQL 性能优化神器 Explain 使用分析](https://segmentfault.com/a/1190000008131735)
C
CyC2018 已提交
422 423
- [How Sharding Works](https://medium.com/@jeeyoungk/how-sharding-works-b4dec46b3f6)
- [大众点评订单系统分库分表实践](https://tech.meituan.com/dianping_order_db_sharding.html)
C
CyC2018 已提交
424
- [B + 树](https://zh.wikipedia.org/wiki/B%2B%E6%A0%91)