目录
11.1存储引擎
1.什么是存储引擎
存储引擎:可以看作是数据表存储数据的一种格式,不同的格式具有的特性也各不相同。
举例说明:只有InnoDB存储引擎支持事务、外键、行级锁等特性,而MyISAM则支持压缩机制等特性。
存储引擎的特点:本身是MySQL数据库服务器的底层组件之一,最大的特点是采用“可插拔”的存储引擎架构。
“可插拔”的理解:指的是对正在运行的MySQL服务器依然可根据实际需求使用特定语句加载(插入,INSTALL PLUGIN语句)或卸载(拔出,UNINSTALL PLUGIN语句)所需的存储引擎文件。
2.存储引擎的选择
首先看一下MySQL当前支持哪些存储引擎。
SHOW ENGINES;
执行以上SQL语句,运行的结果中含有6个字段。
XA(是否支持分布式事务)和Savepoints(是否支持事务的保存点设置)。
存储引擎 | 默认是否支持 | 是否支持事务 | 是否支持分布式事务 | 是否支持保存点 | 描述 |
InnoDB | DEFAULT | YES | YES | YES | 支持事务、行级锁和外键 |
MyISAM | YES | NO | NO | NO | 支持表锁、全文索引 |
MRG_MYISAM | YES | NO | NO | NO | 相同MyISAM表的集合 |
MEMORY | YES | NO | NO | NO | 内存存储,速度快但数据容易丢失,适用于临时表 |
CSV | YES | NO | NO | NO | 数据以文本方式存储在文件中 |
存储引擎 | 默认是否支持 | 是否支持事务 | 是否支持分布式事务 | 是否支持保存点 | 描述 |
ARCHIVE | YES | NO | NO | NO | 适用存储海量数据,有压缩功能,但不支持索引 |
BLACKHOLE | YES | NO | NO | NO | 黑洞引擎,写入的数据都会消失,适合做中继存储 |
PERFORMANCE_SCHEMA | YES | NO | NO | NO | 适用于性能架构 |
FEDERATED | NO | NULL | NULL | NULL | 用于访问远程的MySQL数据库 |
InnoDB存储引擎:在MySQL 5.7版本中被指定为默认的存储引擎。
MyISAM存储引擎:在MySQL5.5以前的版本中是MySQL的默认存储引擎。
3.Innodb存储引擎
适用的场景:非常适合业务逻辑比较强,修改操作比较多的项目。
存储格式
默认InnoDB数据表都共用一个表空间文件ibdata1,每张数据表都会在对应的数据库下创建一个与表同名的结构文件(数据库/表名.frm)。
设置数据表的独立表空间文件:全局变量innodb_file_per_table。
# ① 查看默认是否共用同一个表空间文件
SHOW VARIABLES LIKE 'innodb_file_per_table';
# ② 开启每个表独立的表空间文件
SET GLOBAL innodb_file_per_table=ON;
增加表空间大小
数据在实际的存储过程中,可能会遇到存储空间不足的情况,此时可采用MySQL提供的方式扩充InnoDB系统表空间的大小。
1.配置为自动扩展
自动扩展表空间的实现方式非常简单,只需为表空间中最后一个数据文件(利用系统变量innodb_data_file_path获取)指定autoextend属性,每次自动增加的空间大小由系统变量innodb_autoextend_increment设置,以兆字节(MB)为单位。
SHOW VARIABLES LIKE 'innodb_data_file_path';
SHOW VARIABLES LIKE 'innodb_autoextend_increment';
2.在表空间达到指定大小后,将数据存储到另一个文件中
在表空间中存储的数据达到上限时,也可以将数据存到另外一个指定的文件中。
第4步:启动MySQL服务器。
演示ibdata1达到12M时,将数据添加到另一个指定的文件ibdata2中,当ibdata2达到50M时再自动扩展。
① 关闭MySQL服务器,打开配置文件my.ini,添加以下配置。
innodb_data_file_path = ibdata1:12M;ibdata2:50M:autoextend
② 开启MySQL服务器,在ibdata1同目录下可看到新创建的文件ibdata2,然后登录MySQL服务器后,查看innodb_data_file_path系统变量已修改为以上设置的值。
多版本控制
多版本控制的实现方式:通过保存更改前的数据信息来处理多用户并发、事务回滚等情况的发生,从而保证数据读取的一致性。
多版本控制的内部实现原理:InnoDB存储引擎会为每条记录添加3个隐藏的字段,分别为DB_TRX_ID、DB_ROLL_PTR和DB_ROW_ID。
DB_ROW_ID字段:用于保存新增记录的ID。
4.MyISAM存储引擎
MyISAM的特点:表占用的空间小,数据写入速度快等特点。
MyISAM数据表的文件扩展名分别为frm、myd和myi,文件名与表名相同。
扩展名 | 功能说明 |
frm | 用于存储表的结构 |
myd | 用于存储数据,是MYData的缩写 |
myi | 用于存储索引,是MYIndex的缩写 |
数据在表中的存储,MyISAM与InnoDB的存储格式不同。
• MyISAM 表采用“堆组织”的方式存储数据,换言之,就是数据在 MyISAM 表中的保存顺序与插入顺序完全相 同。• InnoDB 表则采用“索引组织”方式存储数据,也就是数据会按照主键的顺序将记录显示到对应的位置,即使没有主键 InnoDB 也会自动选择表中符合条件的字段或采用 InnoDB 内置的 ROWID 作为主键。
11.2索引
1.索引概述
索引:是一种特殊的数据结构,可以看做是利用MySQL提供的语法将数据表中的某个或某些字段与记录的位置建立一个对应的关系,并按照一定的顺序排序好。
目的:就是为了快速定位指定数据的位置。
类型:
一张数据表中只能有一个聚簇索引。
全文索引:由FULLTEXT INDEX定义,用于根据查询字符提高数据量较大的字段查询速度。此索引在定义时字段类型必须是CHAR、VARCHAR或TEXT中的一种,在MySQL5.7版本中,仅MyISAM和InnoDB存储引擎支持全文索引。
2.索引的基本操作
创建索引的3种方式
CREATE TABLE 方式,与数据表同时创建。ALTER TABLE 方式, 对已创建的数据表进行添加 。CREATE INDEX 方式, 对已创建的数据表进行添加 , 不能添加主键索引 。
# 方式1:CREATE TABLE创建数据表时添加索引
CREATE TABLE 数据表名(
字段名 数据类型 [约束条件]
…
PRIMARY KEY [索引类型] (字段列表)[索引选项] ,
{INDEX|KEY} [索引名称] [索引类型] (字段列表)[索引选项],
UNIQUE [INDEX|KEY] [索引名称] [索引类型] (字段列表)[索引选项],
{FULLTEXT|SPATIAL} [INDEX|KEY] [索引名称] (字段列表)[索引选项]
)[表选项];
# 方式2:ALTER TABLE向已创建的数据表添加索引
ALTER TABLE 数据表名
ADD PRIMARY KEY[索引类型] (字段列表)[索引选项]
|ADD {INDEX|KEY} [索引名称] [索引类型] (字段列表)[索引选项]
|ADD UNIQUE [INDEX|KEY] [索引名称] [索引类型] (字段列表)[索引选项]
|ADD FULLTEXT [INDEX|KEY] [索引名称] (字段列表)[索引选项]
|ADD SPATIAL [INDEX|KEY] [索引名称] (字段列表)[索引选项], …;
# 方式3:CREATE INDEX向已创建的数据表添加索引
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX 索引名称
[索引类型] ON 数据表名 (字段列表)[索引选项][算法选项 | 锁选项]
创建索引的语法在使用时只需要确定3点:
一是确定采用哪种方式创建索引,选择对应的语句。
二是创建哪些索引。
三是为各索引设置选项
索引可设置的选项
索引选项 | 语法 |
索引类型 | USING {BTREE | HASH} |
字段列表 | 字段[(长度)[ASC | DESC]] |
索引选项 | KEY_BLOCK_SIZE [=] 值 | 索引类型| WITH PARSER 解析器插件名 | COMMENT '描述信息' |
算法选项 | ALGORITHM [=] {DEFAULT|INPLACE|COPY} |
锁选项 | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE} |
主键索引不能设置索引名称,其他索引的名称也可以省略,默认使用建立索引的字段表示,复合索引则使用第一个字段的名称作为索引名。
① 查看指定表中创建的索引信息
SHOW CREATE TABLE 数据表名称;
② 查看指定表中的索引信息
SHOW {INDEXES|INDEX|KEYS} FROM 表名;
③ 分析执行的SQL语句
{EXPLAIN | DESCRIBE | DESC}
{SELECT | DELETE | INSERT | REPLACE | UPDATE} statement
虽然对于MySQL而言,EXPLAIN、DESCRIBE和DESC表示的含义相同。但是在实际应用中,通常使用DESCRIBE和DESC获取表结构相关的信息,EXPLAIN用于获取执行查询的相关数据,如是否引用索引,可能用到的索引等。
主键索引在删除时,需要考虑该主键字段是否含有AUTO_INCREMENT属性,若有则需在删除主键索引前删除该属性,否则程序会报错误提示信息。
删除含有AUTO_INCREMENT属性的主键索引
# ① 删除主键字段的AUTO_INCREMENT属性
ALTER TABLE 数据表 MODIFY 字段名 字段类型
# ② 删除主键索引
ALTER TABLE 数据表 DROP PRIMARY KEY 或 DROP INDEX `PRIMARY` ON 数据表
当使用DROP INDEX删除主键索引时,其后的PRIMARY由于是MySQL中的保留字,因此必须使用反引号(`)包裹。
在MySQL中删除主键索引以外的其他索引时,根据索引名称采用以下语法中的任意一种都可以完成删除操作。
# 语法1
ALTER TABLE 数据表 DROP INDEX 索引名
# 语法2
DROP INDEX 索引名 ON 数据表 [算法选项][锁选项]
3.索引的使用原则
索引在使用时虽然可以提高查询速度,降低服务器的负载,但是相应的,索引的使用也会占用物理空间,给数据的维护造成很多麻烦,并且在创建和维护索引时,其消耗的时间会随着数据量的增加而增长。
导致索引失效的sql语句:
1.like查询(“%”和“_”开头)索引失效
2.or运算都要具有索引,否则索引失效
3.where条件字段是字符串类型,必须加引号
4.组合索引字段单独使用,左边生效,右边失效(左原则)
如何选择合适的列创建索引:
1.为常作条件,排序,分组,联合操作的字段建立索引
2.选择唯一性索引
3.选择较小的数列行,为较长的字符串使用前缀索引
11.3锁机制
1.认识锁机制
锁机制在不同存储引擎中的表现也有一定的区别。
根据存储引擎的不同,MySQL中常见的锁有两种
表级锁(如MyISAM、MEMORY存储引擎)
行级锁(如InnoDB存储引擎——特殊)
根据锁在MySQL中的状态也可将其分为“隐式”与“显式”。
“ 隐式 ” 锁 指的是 MySQL 服务器本身对数据资源的争用进行管理,它完全由服务器自动执行。“ 显式 ” 锁 指的是用户根据实际需求,对操作的数据显式的添加锁,同样在使用完数据资源后也需要用户对其进行解锁。
2.表级锁
表级锁:根据操作的不同可以分为读锁和写锁。
读锁:表示用户读取(如SELECT查询)数据资源时添加的锁,其他用户不可修改或增加数据资源,但是可以读取该数据资源,因此读锁也可称为共享锁。
写锁:表示用户对数据资源执行写(如INSERT、UPDATE、DELETE等)操作时添加的锁,除了当前添加写锁的用户外,其他用户都不能对其进行读/写操作,因此写锁也可以称为排他锁或独占锁。
MyISAM存储引擎表:是MySQL数据库中最典型的表级锁。
1.“隐式”读/写的表级锁
“隐式”读的表级锁:当用户对MyISAM存储引擎表执行SELECT查询操作前,服务器会“自动”地为其添加一个表级的读锁。
“隐式”写的表级锁:执行INSERT、UPDATE、DELETE等写操作前,服务器会“自动”地为其添加一个表级的写锁。
“隐式”表级锁要如何解锁:直到操作完毕,服务器再“自动”地为其解锁。
“隐式”表级锁的生命周期:SQL语句的执行时间,且该生命周期的持续时间一般都比较短暂。
“隐式”读的表级锁与“隐式”写的表级锁添加的优先级顺序:
默认服务器“自动”添加“隐式”锁时,表的更新操作优先于表的查询操作。添加写锁时,若表中没有任何锁则添加,否则将其插入到写锁等待的队列中。添加读锁时,若表中没有写锁则添加,否则将其插入到读锁等待的队列中。
2.“显式”读/写的表级锁
LOCK TABLES 数据表名 READ [LOCAL]| WRITE, …
表级锁的问题:锁定的粒度大,多用户访问会造成锁竞争,降低并发处理能力。
从数据库优化的角度来考虑:尽量减少表级锁定时间,提高多用户的并发能力。
如何释放“显式”表级锁:UNLOCK TABLES语句
用户设置的“显式”表级锁仅在当前会话内有效,若会话期间内未释放锁,在会话结束后也会自动释放。
3.行级锁
InnoDB存储引擎的表什么时候添加表级锁,什么时候添加行级锁呢?
1.“隐式”行级锁
“隐式”行级排他锁:当用户对InnoDB存储引擎表执行INSERT、UPDATE、DELETE等写操作前,服务器会“自动”地为通过索引条件检索的记录添加行级排他锁。
“隐式”行级排他锁要如何解锁:直到操作语句执行完毕,服务器再“自动”地为其解锁。
“隐式”行级排他锁的生命周期:语句的执行时间可以看作是“隐式”行级锁的生命周期,且该生命周期的持续时间一般都比较短暂。
延长“隐式”行级排他锁的生命周期:通常情况下,若要增加行级锁的生命周期,最常使用的方式是事务处理,让其在事务提交或回滚后再释放行级锁,使行级锁的生命周期与事务的相同。
2.“显式”行级锁
对于InnoDB表来说,若要保证当前事务中查询出的数据不会被其他事务更新或删除,利用普通的SELECT语句是无法办到的,此时需要利用MySQL提供的“锁定读取”的方式为查询操作显式的添加行级锁。
SELECT 语句 FOR UPDATE|LOCK IN SHARE MODE
FOR UPDATE:表示在查询时添加行级排他锁
LOCK IN SHARE MODE:表示在查询时添加行级共享锁。
用户在向InnoDB表显式添加行级锁时,InnoDB存储引擎首先会“自动”地向此表添加一个意向锁,然后再添加行级锁。
InnoDB表中当前用户的意向锁若与其他用户要添加的表级锁冲突时,有可能会发生死锁而产生错误。
默认当InnoDB处于REPEATABLE READ(可重复读)的隔离级别时,行级锁实际上是一个next-key锁,它是由间隙锁(gap lock)和记录锁(record lock)组成。
间隙锁的作用:在并发时防止其他事务在间隙插入记录,解决事务幻读问题。
在执行SELECT…FOR UPDATE时,若检索时未使用索引,则InnoDB存储引擎会给全表添加一个表级锁,并发时不允许其他用户进行插入。另外,若查询条件使用的是单字段的唯一性索引,InnoDB存储引擎的行级锁不会设置间隙锁。
间隙锁的使用虽然解决了事务幻读的情况,但是也会造成行锁定的范围变大,若在开发时想要禁止间隙锁的使用,可以将事务的隔离级别更改为READ COMMITTED(读取提交)。
查看InnoDB表的锁
InnoDB存储引擎的锁比较复杂,读者可以在添加一个行锁后,使用SHOW ENGINE INNODB STATUS语句查看当前表中添加的锁的类型。
SHOW ENGINE INNODB STATUS语句
11.4分表技术
水平分表
当一个表很大时,即使创建索引查询速度也很慢
把一个巨大的表按算法分割成小表,加快速度查询
用户id%表个数
缺点:增加了项目复杂度
11.5分区技术
1.分区概述
对于单表数据量过大的问题,除了可以使用分表技术,在物理上创建多张数据表解决外,还可以使用MySQL本身支持的分区技术提高数据库的整体性能。
分区技术:就是在操作数据表时可以根据给定的算法,将数据在逻辑上分到多个区域中存储。在分区中还可以设置子分区,将数据存放到更加具体的区域内。
分区技术可以使一张数据表中的数据存储在不同的物理磁盘中,相比单个磁盘或文件系统能够存储更多的数据,实现更高的查询吞吐量。
若在WHERE子句中包含分区条件,系统只需扫描相关的一个或多个分区而不用全表扫描,从而提高查询效率。
MySQL中分区技术在使用时对存储引擎以及锁有一定的要求,具体内容如下。
2.分区管理
创建分区
CREATE TABLE 数据表名称
[(字段与索引列表)][表选项]
PARTITION BY 分区算法(分区字段)[ PARTITIONS 分区数量]
[SUBPARTITION BY 子分区算法(子分区字段)[ SUBPARTITIONS 子分区数量]]
[(
PARTITION 分区名 [VALUES 值][其他选项][(SUBPARTITION 子分区名 [其他选项])],
…
)];
RANGE/LIST (表达式) 或 COLUMNS(字段列表)
HASH(表达式)
KEY [ALGORITHM={1|2}](字段列表)
KEY算法的ALGORITHM选项用于指定key-hashing函数的算法
值等于1:适用于MySQL5.1。
默认是2:适用于MySQL5.5及以后版本。
子分区算法仅支持 HASH和KEY。
# RANGE算法必须使用LESS THAN而不能用IN
PARTITION 分区名 VALUES LESS THAN {(表达式 | 值列表) | MAXVALUE}
# LIST算法必须使用IN而不能用LESS THAN
PARTITION 分区名 VALUES IN (值列表)
增加分区
# ① 已创建的数据表没有创建分区,添加分区的方式
ALTER TABLE 数据表名称 PARTITION BY 分区算法…;
# ② 已创建的数据表含有分区,添加分区的方式
# LIST或RANGE分区
ALTER TABLE 数据表名称 ADD PARTITION (分区选项, …);
# HASH或KEY分区
ALTER TABLE 数据表名称 PARTITIONS 数量;
当添加分区的数据表已经含有数据时,会按照分区的算法将已有的数据分配到不同的分区中。
删除分区
# 删除HASH、KEY分区
ALTER TABLE 数据表名称 COALESCE PARTITION 数量;
# 删除RANGE、LIST分区
ALTER TABLE 数据表名称 DROP PARTITION分区名称;
若在开发中仅要清空各分区表中的数据,不删除对应的分区文件,可以使用以下的语句实现。
ALTER TABLE 数据表名称 TRUNCATE PARTITION {分区名称 | ALL}
11.6数据碎片与维护
在MySQL数据库中,DELETE删除一条记录时,仅删除了数据表中保存的数据,而记录占用的存储空间会被保留。
长期删除数据、添加数据的过程中,索引文件和数据文件都将产生“空洞”,形成很多不连续的碎片,造成数据表占用空间变大,但表中记录数却很少的情况发生。
1.OPTIMIZE TABLE(支持MySQL中常见的存储引擎MyISAM和InnoDB)重新组织表中数据和关联索引数据的物理存储,减少存储空间并提高访问表时的I/O效率。
OPTIMIZE TABLE 表名;
InnoDB存储引擎的数据表不支持OPTIMIZE TABLE操作
2.使用ALTER TABLE将数据表的存储引擎修改为当前数据表的存储引擎,实现对数据碎片的整理。
ALTER TABLE 数据表 ENGINE='当前存储引擎';