Full-Stack-Notes/notes/MySQL_基础.md
2019-08-16 11:58:11 +08:00

161 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 一、常见存储引擎
### 1.1 InnoDB
### 1.2 MyISAM
MyISAM 是 MySQL 5.5 之前默认的存储引擎。在创建 MyISAM 表时会创建两个同名的文件:
+ 扩展名为 `.MYD``MYData`):用于存储表数据;
+ 扩展名为 `.MYI` `MYIndex` 用于存储表的索引信息。
在 MySQL 8.0 之后,就只会创建上述两个同名文件,这时表结构的定义存储在 MySQL 数据字典中,但在 MySQL 8.0 之前,还会存在一个扩展名为 `.frm` 的扩展文件用于存储表结构信息。MyISAM 与 InnoDB 主要的区别其只支持表级锁,不支持行级锁,不支持事务。
### 1.3 MEMORY
MEMORY 存储引擎(又称为 HEAP会将表中的数据存储在内存中它具有以下特征
- MEMORY 表的表定义信息存储在 MySQL 数据字典中,而实际的数据则存储在内存空间中,并以块为单位进行划分;因此当服务器重启后,表本身并不会被删除,只是表中的所有数据都会丢失。
- MEMORY 存储引擎支持 HASH 索引和 BTREE 索引,默认采用 HASH 索引。
- MEMORY 表使用固定长度的行存储格式,即便是 VARCHAR 类型也会使用固定长度进行存储。
- MEMORY 支持 AUTO_INCREMENT 列,但不支持 BLOB 列或 TEXT 列。
- MEMORY 表和 MySQL 内部临时表的区别在于:两者默认都采用内存进行存储,但 MEMORY 表不受存储转换的影响,而内部临时表则会在达到阈值时自动转换为磁盘存储。
基于以上特性MEMORY 表适合用于存储临时数据 ,如会话状态、实时位置等信息。
### 1.4 CSV
CSV 存储引擎使用逗号分隔值的格式将数据存储在文本文件中。创建 CSV 表时会同时创建两个同名的文件:
+ 一个扩展名为 `csv` ,负责存储表的数据,其文件格式为纯文本,可以通过电子表格应用程序 (如 Microsoft Excel ) 进行修改,对应的修改操作也会直接反应在数据库表中。
+ 另一个扩展名为 `CSM`,负责存储表的状态和表中存在的行数。
### 1.5 ARCHIVE
ARCHIVE 默认采用 zlib 无损数据压缩算法进行数据压缩能够利用极小的空间存储大量的数据。创建ARCHIVE 表时,存储引擎会创建与表同名的 `ARZ` 文件,用于存储数据。它还具有以下特点:
+ ARCHIVE 引擎支持 INSERTREPLACE 和 SELECT但不支持 DELETE 或 UPDATE。
+ ARCHIVE 引擎支持 AUTO_INCREMENT 属性,并支持在其对应的列上建立索引,如果尝试在其他不具有 AUTO_INCREMENT 属性的列上建立索引,则会抛出异常。
+ ARCHIVE 引擎不支持分区。
### 1.6 MEGRE
MERGE 存储引擎,也称为 MRG_MyISAM 引擎,是一组相同 MyISAM 表的集合。 ”相同” 表示所有表必须具有相同的列数据类型和索引信息。要创建 MERG E表必须指定 UNION =list-of-tables选项如下
```sql
mysql> CREATE TABLE t1 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, message CHAR(20)) ENGINE=MyISAM;
mysql> CREATE TABLE t2 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, message CHAR(20)) ENGINE=MyISAM;
mysql> INSERT INTO t1 (message) VALUES ('Testing'),('table'),('t1');
mysql> INSERT INTO t2 (message) VALUES ('Testing'),('table'),('t2');
mysql> CREATE TABLE total (a INT NOT NULL AUTO_INCREMENT,message CHAR(20), INDEX(a))
ENGINE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;
```
创建表时你还可以通过 INSERT_METHOD 选项来控制 MERGE 表的插入:使用 FIRST 或 LAST 分别表示在第一个或最后一个基础表中进行插入;如果未指定 INSERT_METHOD 或者设置值为 NO ,则表示不允许在 MERGE 表上执行插入操作。除此之外你还可以在MERGE表上使用 SELECTDELETEUPDATE 语句,示例如下:
```sql
mysql> SELECT * FROM total;
+---+---------+
| a | message |
+---+---------+
| 1 | Testing |
| 2 | table |
| 3 | t1 |
| 1 | Testing |
| 2 | table |
| 3 | t2 |
+---+---------+
```
## 二、索引
### 2.1 B+ tree 索引
B-Tree 适用于以下类型的查找:
+ **全值匹配**:以索引为条件进行精确查找。如 `emp_no` 字段为索引,查询条件为 `emp_no = 10008`
+ **前缀匹配**:以联合索引的前缀为查找条件。如 `emp_no``dept_no` 为联合索引,查找条件为 `emp_no = 10008`
+ **列前缀匹配**:匹配索引列的值的开头部分。如 `dept_no` 为索引,查询条件为 `dept_no like "d1%"`;
+ **匹配范围值**:按照索引列匹配一定范围内的值。如 `emp_no` 字段为索引,查询条件为 `emp_no > 10008`
+ **只访问索引的查询**:如 `emp_no` 字段为索引,查询语句为 `select emp_no from employees`
+ **精确匹配某一列并范围匹配某一列**:如 `emp_no``dept_no` 为联合索引,查找条件为 `dept_no = "d004" and emp_no < 10020`
### 2.2 哈希索引
使用哈希索引时,存储引擎会对索引列的值进行哈希运算,并将计算出的哈希值和指向该行数据的指针存储在索引中,因此它更适用于等值比较查询,而不是范围查询。在建立哈希索引时,需要选取选择性比较高的列,即列上的数据不容易重复 (如身份证号),这样可以尽量避免哈希冲突。因为哈希索引并不需要存储索引列的数据,所以其结构比较紧凑,对应的查询速度也比较快。
InnoDB 引擎有一个名为 “自适应哈希索引 (adaptive hash index)” 的功能,当某些索引值被频繁使用时,它会在内存中基于 B-Tree 索引在创建一个哈希索引,从而让 B-Tree 索引具备哈希索引的优点,如快速查找。
### 2.3 索引的优点
+ 索引极大减少了服务器需要扫描的数据量;
+ 索引可以帮助服务器避免排序和临时表;
+ 索引可以将随机 IO 转换为顺序 IO。
### 2.4 索引的创建与使用策略
- 在查询时,应该避免在索引列上使用函数或者表达式;
- 对于多列索引,应该按照使用频率由高到低的顺序建立联合索引;
- 建立索引时,应该考虑查询时候的排序和分组的需求。只有当索引列的顺序和 ORDER BY 字句的顺序完全一致并且遵循同样的升序或降序规则时候MySQL 才会使用索引来对结果做排序。
- 尽量避免创建冗余的索引。通常会出现以下两种情况的冗余:
+ 已经存在索引 (AB),接着又创建了索引 A此时会出现冗余因为索引 A 只是索引 (AB) 的前缀索引;
+ 为主键列再次创建索引,因为主键已经是唯一索引了,此时再创建就会出现冗余。
## 三、锁
### 3.1 共享锁与排它锁
InnoDB 存储引擎支持以下两种标准的行级锁:
+ 共享锁 ( S Lock又称读锁):允许加锁事务读取数据;
+ 排它锁 ( X Lock又称写锁):允许加锁事务删除或者修改数据。
排它锁和共享锁的兼容情况如下:
| | **X** | **X** |
| ----- | ------ | ------ |
| **X** | 不兼容 | 不兼容 |
| **S** | 不兼容 | 兼容 |
### 3.2 意向锁
为了说明意向锁的作用,这里先引入一个案例:假设事务 A 利用 S 锁锁住了表中的某一行,让其只能读不能写。之后事务 B 尝试申请整个表的写锁,如果事务 B 申请成功,那么理论上它就应该能修改表中的任意一行,这与事务 A 持有的行锁是冲突的。想要解决这个问题,数据库必须知道表中某一行已经被锁定,从而在事务 B 尝试申请整个表的写锁时阻塞它。想要知道表中某一行被锁定,可以对表的每一行进行遍历,这种方式性能比较差,所以 InnoDB 引入了意向锁。
+ 意向共享锁 ( IS Lock ):当前表中某行或者某几行数据存在共享锁;
+ 意向排它锁 ( LX Lock ):当前表中某行或者某几行数据存在排它锁。
按照意向锁的规则,当上面的事务 A 给表中的某一行加 S 锁时,会同时给表加上 IS 锁,之后事务 B 尝试获取表的 X 锁时,由于 X 锁与 IS 锁并不兼容,所以事务 B 会被阻塞。
| | X | IX | S | IS |
| ------ | ------ | ------ | ------ | ------ |
| **X** | 不兼容 | 不兼容 | 不兼容 | 不兼容 |
| **IX** | 不兼容 | 兼容 | 不兼容 | 兼容 |
| **S** | 不兼容 | 不兼容 | 兼容 | 兼容 |
| **IS** | 不兼容 | 兼容 | 兼容 | 兼容 |
## 三、事务
## 参考资料
1. [ InnoDB 数据页解析](http://mysql.taobao.org/monthly/2018/04/03/)
2. [MySQL索引背后的数据结构及算法原理](https://blog.codinglabs.org/articles/theory-of-mysql-index.html)