数据库存储引擎是数据库底层软件组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据操作。简而言之,存储引擎就是指表的类型。数据库的存储引擎决定了表在计算机中的存储方式。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎还可以获得特定的功能。
现在许多数据库管理系统都支持多种不同的存储引擎。MySQL的核心就是存储引擎。
MySQL 提供了多个不同的存储引擎,包括处理事务安全表的引擎和处理非事务安全表的引擎。在 MySQL 中,不需要在整个服务器中使用同一种存储引擎,针对具体的要求,可以对每一个表使用不同的存储引擎。
MySQL 5.7 支持的存储引擎有 InnoDB、MyISAM、Memory、Merge、Archive、CSV、BLACKHOLE 等。可以使用SHOW ENGINES;
语句查看系统所支持的引擎类型,结果如图所示。
Support 列的值表示某种引擎是否能使用,YES
表示可以使用,NO
表示不能使用,DEFAULT
表示该引擎为当前默认的存储引擎。
下面简要描写几种存储引擎,后面会对其中的几种(主要是 InnoDB 和 MyISAM )进行详细讲解。像 NDB 这样的需要更多扩展性的讨论,这超出了本教程的介绍范畴,所以在教程后面对它们不会介绍太多。
存储引擎 | 描述 |
---|---|
ARCHIVE | 用于数据存档的引擎,数据被插入后就不能在修改了,且不支持索引。 |
CSV | 在存储数据时,会以逗号作为数据项之间的分隔符。 |
BLACKHOLE | 会丢弃写操作,该操作会返回空内容。 |
FEDERATED | 将数据存储在远程数据库中,用来访问远程表的存储引擎。 |
InnoDB | 具备外键支持功能的事务处理引擎 |
MEMORY | 置于内存的表 |
MERGE | 用来管理由多个 MyISAM 表构成的表集合 |
MyISAM | 主要的非事务处理存储引擎 |
NDB | MySQL 集群专用存储引擎 |
有几种存储引擎的名字还有同义词,例如,MRG_MyISAM 和 NDBCLUSTER 分别是 MERGE 和 NDB 的同义词。存储引擎 MEMORY 和 InnoDB 在早期分别称为 HEAP 和 Innobase。虽然后面两个名字仍能被识别,但是已经被废弃了。
MySQL常用的存储引擎:
- MylSAM
- InnoDB
注意:一个表只能使用一个存储引擎,一个库中不同的表可以使用不同的存储引擎。
静态表是默认的存储格式。静态表中的字段都是非可变字段,这样每个记录都是固定长度的,这种存储方式的优点是存储非常迅速,容易缓存,出现故障容易恢复;缺点是占用的空间通常比动态表多。 静态格式是MyISAM表的默认存储格式。当表不包含变量长度列(VARCHAR, BLOB, 或TEXT)时,使用这个格式。每一行用固定字节数存储。静态格式是三种存储格式中最简单和最安全的,同时也是最快的ondisk格式。
基本特征:
动态表包含可变字段,记录不是固定长度的,这样存储的优点是占用空间较少,但是频繁的更新、删除记录会产生碎片,需要定期执行OPTIMIZE TABLE语句或myisamchk-r命令来改善性能,并且出现故障的时候恢复相对比较困难(因为会产生磁盘碎片,而且存储空间不是连续的)。
动态表特征(动态格式)
如果一个MyISAM表包含任何可变长度 列(VARCHAR, BLOB或TEXTDynamic),或者如果一个表被用ROW_FORMAT=DYNAMIC选项来创建,动态存储格式被使用。
基本特征:
压缩表由 myisamchk 工具创建,占据非常小的空间,因为每条记录都是被单独压缩的,所以只有非常小的访问开支。(压缩的过程中会占用CPU性能)
已压缩表特征(已压缩格式)
MySQL分发版本里默认包含myisampack工具,已压缩存储格式是由它创建的只读格式。
压缩表有下列特征:
注:
- 使用like进行模糊查询时,会进行全表扫描,锁定整个表。
- 对没有创建索引的字段进行查询,也会进行全表扫描锁定整个表。
- 使用索引进行查询,则是行级锁定。
select count(*) from table;
时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。需要注意的是当count(*)语句包含where条件时MyISAM也需要扫描整个表。MyISAM: : 不支持事务和外键约束,占用空间较小,访问速度快,表级锁定,支持全文索引,适用于不需要事务处理、单独写入或查询的应用场景。(写入和查询不一起使用的场景)
InnoDB: : 支持事务处理、外键约束、占用空间比MyISAM 大,支持行级锁定,5.5版本后支持全文索引,读写开发能力较好,适用于需要事务处理、读写频繁,一致性要求高,数据更新频繁的应用场景。
1、需要考虑每个存储引擎提供了哪些不同的核心功能及应用场景。
2、支持的字段和数据类型
3、锁定类型:不同的存储引擎支持不同级别的锁定
show engines;
#Engine:存储引擎的名称。
#Support:YES表示引擎受支持且处于活动状态,NO表示不支持,DEFAULT表示默认存储引擎。DISABLED表示支持引擎但已将其禁用。
#Comment:存储引擎的简要说明。
#Transactions:存储引擎是否支持事务。
#XA:存储引擎是否支持XA事务。
#Savepoints:存储引擎是否支持回滚点(标记点)。
方法一:
show table status from 库名 where name=‘表名’\G
方法二:
use 库名;
show create table 表名;
修改当前数据表使用的存储引擎。
use 库名;
alter table 表名 engine=存储引擎名称;eg : use school;
alter table class engine=MyISAM; #将class表的存储引擎修改为MyISAM注意:因为MyISAM不支持外键约束,如果数据表设置了外键,则无法修改为MyISAM。
MyISAM不支持外键约束,如果数据表设置了外键,则无法修改为MyISAM:
注意:此方法只对修改配置文件并重启mysql服务之后新创建的表有效,已经存在的表不会有变更。
创建数据表时如果没有指定存储引擎,则会使用默认存储引擎。
vim /etc/my.cnf
…
[mysqld]
default-storage-engine=InnoDB #修改这一行,指定默认存储引擎为InnoDBsystemctl restart mysqld #重启服务
use 库名;
create table 表名(字段1 数据类型,…) engine=存储引擎名称;eg : use school;
create table teacher(id int,name varchar(10)) engine=MyISAM;
#指定存储引擎为MyISAM
一、简介
数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能例外。MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎所针对的应用场景特点都不太一样,为了满足各自特定应用场景的需求,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计,所以各存储引擎的锁定机制也有较大区别。MySQL各存储引擎使用了三种类型(级别)的锁定机制:表级锁定,行级锁定和页级锁定。
二、行级锁
行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
使用行级锁定的主要是InnoDB存储引擎。
三、表级锁
通常用在DDL语句中,如DELETE TABLE,ALTER TABLE等。
和行级锁定相反,表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。
当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。
四、页级锁
页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。
在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。
使用页级锁定的主要是BerkeleyDB存储引擎。
五、特性
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
适用:从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。
准备一个数据表www:
create table www(id int primary key,name char(10),age int);
insert into www values(1,‘a’,100),(2,‘b’,200),(3,‘c’,300),(4,‘d’,400),(5,‘e’,500),(6,‘f’,600);
alter table www add index name_index(name);
#对name字段创建普通索引
InnoDB行锁是通过给索引项加锁来实现的,如果没有索引,InnoDB将通过隐藏的聚簇索引来对记录加锁。
因为id字段是主键,Innodb对于主键使用了聚簇索引,删除过程中会直接锁住整行记录。行级锁定。
因为name字段是普通索引,会先锁住索引的两行(因为a有两行),接着会锁住相应主键对应的记录。行级锁定。
因为age字段没有索引,会使用全表扫描过滤,这时表上的各个记录都将加上锁。表级锁定。
死锁一般是事务相互等待对方资源,最后形成环路造成的。
session1 | session2 |
---|---|
begin; | begin; |
delete from www where id=5;#事务结束前,id=5的行会被锁定 | |
select * from www where id=1 for update; #加排他锁,模拟并发情况,锁定id=1的行 | |
delete from www where id=1; #死锁产生 | |
update www set name=‘g’ where id=5; #死锁产生。因为会话1中id=5的行还在删除过程中,该行已被锁定 | |
rollback; #回滚,结束事务。id=5的行被解锁 | |
update www set name=‘g’ where id=5; #成功更新数据 |
for update: 可以为数据库中的行上一个排它锁。当一个事务的操作未完成时,其他事务可以读取该行数据,但是不能写入、更新或删除。
使用更合理的业务逻辑,以固定的顺序访问表和行。
大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。
为表添加合理的索引。如果不使用索引将会为表的每一行记录添加上锁,死锁的概率大大增加。
- MyISAM和InnoDB的区别:
- MyISAM:不支持事务和外键约束,占用空间较小,访问速度快,表级锁定,适用于不需要事务处理、单独写入或查询的应用场景。(写入和查询不一起使用的场景)
- InnoDB:支持事务处理、外键约束、占用空间比MyISAM 大,支持行级锁定,读写开发能力较好,适用于需要事务处理、读写频繁的应用场景。
- 查看系统支持的存储引擎:
show engines;- 查看表使用的存储引擎:
- 方法一:show table status from 库名 where name=‘表名’\G
- 方法二:show create table 表名;
- 修改存储引擎:
- 方法一:修改已存在的表使用的存储引擎
alter table 表名 engine=存储引擎名称;- 方法二:修改配置文件,指定默认存储引擎
vim /etc/my.cnf
[mysqld]
default-storage-engine=InnoDB #修改这一行,指定默认存储引擎为InnoDB
systemctl restart mysqld #重启服务- 方法三:创建表时指定存储引擎
create table 表名(字段1 数据类型,…) engine=存储引擎名称;
如何选择合适的存储引擎
使用哪种引擎需要根据需求灵活选择,一个数据库中多个表可以使用不同的引擎以满足各种性能和实际需求。 使用合适的存储引擎,将会提高整个数据库的性能。 下面提供几个选择标准,然后按照标准,根据实际情况,选择对应的存储引擎即可:
- 是否需要支持事务;
- 是否需要使用热备;
- 崩溃恢复,能否接受崩溃;
- 是否需要外键支持;
- 存储的限制;
- 对索引和缓存的支持。