本篇主要介绍MySQL中常见的存储引擎。
目录
一、InnoDB引擎
简介
特性
最佳实践
创建InnoDB
存储文件
二、MyISAM存储引擎
简介
特性
创建MyISAM表
存储文件
存储格式
静态格式
动态格式
压缩格式
三、MEMORY存储引擎
简介
特点
创建MEMORY表
存储文件
内存管理
一、InnoDB引擎
简介
InnoDB是一款兼具高性能和高可靠性的存储引擎。在MySQL中默认以InnoDB作为存储引擎,在创建表时,如果我们没有指定其它存储引擎作为存储引擎,将默认使用InnoDB作为存储引擎。
特性
InnoDB的主要特点如下:
- InnoDB支持使用事务,事务遵从ACID特性,且事务具有回滚,提交和崩溃恢复的功能,以保护用户的数据。
- InnoDB支持行级锁,能够带来更多的并发。
- InnoDB在内存中维护了一个缓冲池,将常用的数据保存到缓冲池中,如果要使用的数据包含在缓冲池中,则直接从缓冲池中读取,如果不包含则从磁盘中读取并使用,并将从磁盘中读取到的数据保存到缓冲池中,从而减少磁盘IO的次数,从而大大提高SQL的执行性能。
- InnoDB支持使用外键约束,以保证数据的完整性,在进行插入插入,更新,删除时确保关联表之间的一致性。
- 在InnoDB中实现了一个自适应哈希的功能,当某条查询语句被执行多次时,会自动将该语句和执行结果通过Key-value的结构组织起来,下次进行相同的查询时,直接返回查询结果。
最佳实践
下面我们来了解一下如何使用,才能发挥出InnoDB的最佳效果。
- 在表中为查询最频繁的列(或多个列) 指定主键(或复合主键),如果没有合适的列作为主键,则创建一个自增的列作为主键。
- 在多个表根据相同的ID查询数据,建议使用表连接,可以在连接的列上定义外键,并在每个表中使用相同的数据类型来声明这些列,添加外键可以确保被外键引用的列使用索引,从而提高性能。
- 将多个DML操作组合在自己创建的事务中,统一提交或者回滚,以免创建事务过于频繁,(DML操作会自动创建一个事务并自动提交)。
- 由于DML语句自动创建的事务是自动提交的,因此在每秒提交数百次事务的服务器上,应该结合存储设备的写入速度,关闭事务的自动提交,可以通过系统变量autocommit=off设置。
- 不使用Lock Tabel来对表加锁,因为InnoDB可以在不牺牲可靠性和高性能的情况下同时保证对一张表的并发访问。
创建InnoDB
创建InnoDB表的语法如下:
use test_db #选择数据库
create table InnoDB_test(id int primary key auto_increment,name varchar(20)) engine = InnoDB; #创建一个InnoDB表
存储文件
创建的InnoDB表的表空间文件会保存到数据目录中的数据库同名目录中,例如上面创建的这个表的文件就会被保存如下目录中,文件名为 表名.ibd,里面包含了表的具体数据和相关表描述信息。
我们是无法直接该.ibd文件中的表描述信息的,如果需要读取的话,可以使用ibd2sdi工具进行读取,使用方法如下:
ibd2sdi --dump-file=InnoDB_test.txt InnoDB_test.ibd
通过上述命令就能提取我们的.ibd文件中的表描述信息,并在当前目录生成一个我们可以读懂的.txt文件,文件的内容如下:
在MySQL5.x版本以前的版本中会生成一个.frm文件来单独描述表描述信息。
二、MyISAM存储引擎
简介
相对于InnoDB引擎而言,MyISAM引擎的表空间文件占用的空间相对较小,但MyISAM引擎采用的一个表级锁,因此在并发场景下,读写性能相对较低,MyISAM存储引擎通常在中小型web项目以及级数据仓库中的只读或者主要是读的场景中使用。
特性
- MyISAM表中最大可以存放2^64行数据
- 每个MyISAM表中最多可以创建64个索引,每个索引中最多包含16个列
- 支持并发插入
- 可以将数据文件和索引文件放到不同设备的不同目录中,从而提高访问速度
- BLOB和TEXT类型的数据也能够被索引。
- 索引列中允许出现null值
- 可以设置myisam_recover_options系统变量来使mysqld在启动时自动修复上一次没有正确关闭的MyISAM表。
- 表中varchar 和char列总和最多可达64kb
- unique约束的长度不受限制。
创建MyISAM表
在创建MyISAM表需要显示指定使用MyISAM引擎,具体语法如下:
CREATE TABLE myisam_test(id int primary key auto_increment ,name varchar(20))ENGINE = MyISAM [DATA DIRECTORY = PATH][INDEX DIRECTORY = PATH];
其中DATA DIRECTORY和INDEX DIRECTORY表示数据文件和索引文件的绝对地址,我们可以显示指定,不指定则使用默认的数据目录来存放数据文件和索引文件。
存储文件
创建MyISAM表时会根据表名生成三个不同后缀名的文件,分别是.MYD(数据文件)、.MYI(索引文件)、.sdi(表信息描述文件(JSON格式))。这三个文件和InnoDB表的.ibd文件一样,都默认保存在MySQL的数据目录中。
存储格式
MyISAM表支持三种不同的存储格式,其中FIXED(静态格式),和DYNAMIC(动态格式),根据使用的列类型自动选择,而另一种格式,只能使用myisampack实用程序生成并且为只读。
当表中的列不存在BLOB类型和TEXT类型的列时,在使用CREATE TABLE 或者ALTER TABLE语句创建或者修改表时,可以提过ROW_FORMAT将表设置成动态格式或者静态格式。
使用myisamchk可以将压缩格式的MyISAM表进行解压,语法为myisamcnk --uppack.下面我们来具体了解一下这三种存储格式。
静态格式
静态格式是MyISAM表的默认格式,一般在表中不含可变类型(varchar,BLOB,TEXT,varbinary)的列时使用,如果包含且长度小于固定的列宽,则字符串用空格补充到列宽,二进制用0x00字节补充到列宽,因此,静态格式中所有列的长度都是固定的。因为长度固定我们可以直接通过行号和固定行的长度来直接定位到目标行在磁盘的位置,从而增加磁盘访问的速度,除此之外,固定的位置还能让我们在数据损坏时更好的进行恢复,但由于无论可变长度的类型是否达到最长,都会补到最长的列宽,这样会造成一定的空间浪费。另外需要注意的是如果当前类可为null,会用1bit的额外空间来标识当前是否为null。总的来说,静态格式的安全性,访问速度和简易性相对更好,但会带来一些空间浪费。
动态格式
当表中包含可变长度类型的列时,通常使用动态格式,也可以通过ROW_FORMAT = DYNAMIC选项设置。动态格式中,每一行的长度都不是固定的,在每一行中都包含一个标记来指示当前行有多长,如果行因为更新操作而使长度增加,下次如果长度减少,就可能会带来一些空间碎片,可以使用OPTIMIZE TABLE table_name 语句或者myisamcnk -r来整理这些空间碎片。除此之外,在每一行中还包含一个位图,来标识哪些列为空字符串或者值为0,这些被标识的列将不会被保存到磁盘中,因此动态格式的空间占用要小很多,和静态格式一样,会额外用1bit的空间来标识可能为null的列是否为null。使用动态格式时,每一行每一列都可以使用单独的方式来进行压缩,常用的压缩方式如下:
- 如果某列的值为0,无论原来该列为哪种数据类型,都只用一个bit储存
- 如果列中可能出现的不同的值的数量较少,则数据类型转为枚举
- 如果数据取值范围较小,则统一使用更小的数据类型来进行存储,例如一个bigint列,其取值范围只有(-128,127),那么就转用tinyint来存储
总的来说,动态格式的空间占用要比固定格式小很多,但由于不固定的长度,访问速度相对较慢。
压缩格式
对于使用myisampack生成的只读数据表,统一使用压缩格式,压缩格式的特点如下:
- 压缩格式的磁盘占用非常小,实现了最大限度的空间节省
- 适用于固定长度和动态长度的数据行
- 数据只读,不能进行删除和更新等修改操作
三、MEMORY存储引擎
简介
使用MEMORY引擎创建的表,其所有数据都保存到内存中,但由于内存的特殊性,一断机器关闭或者断电都会使数据丢失,因此使用MEMORY存储引擎创建的表一般只用作临时表或者只读的缓存。
特点
MEMORY存储引擎具有如下特点:
- 使用固定长度的存储格式,当列为可变长度类型时,使用固定长度来存储。
- 不能包含BLOB、TEXT类型的列
- 非临时MEMORY表在所有客户端之间共享
- 支持hash索引(默认使用)和B树索引
- 不支持表分区
- 使用单线程来操作表,在高并发的场景下可能会出现较为严重的锁竞争,因此,即使数据保存在内存中,使用MEMORY表的性能不一定比InnoDB高
创建MEMORY表
创建MEMORY表时,需要在建表语句后面显示指定,具体如下:
CREATE TABLE memory_test(id int primary key auto_increment ,name varchar(20))ENGINE = MEMORY
存储文件
由于memory表的所有数据都保存到内存中,因此没有专门的文件用来专门保存数据,只有一个sdi文件来保存表描述信息和数据字典。
内存管理
接下来我们来了解一下MEMORY存储引擎是如何管理内存中的数据时,具体可以总结为以下几点:
- MEMORY存储引擎只有在删除整张表或者删除表中的所有行时才会真的将表中的数据所占用的内存进行回收,如果只是删除单行,不会真的去回收该数据的内存。如果需要回收已删除行的数据,可以使用ALTER TABLE ENGINE = MEMORY来强制对表进行重建。
- 对于表中一行数据所占内存,可以通过下面的公式进行计算 : (所有B树索引长度)SUM_OVER_ALL_BTREE_KEYS(max_length_of_key + sizeof(char*) * 4) + (所有hash索引的长度)SUM_OVER_ALL_HASH_KEYS(sizeof(char*) * 2) + (单行数据长度)ALIGN(length_of_row+1, sizeof(char*))。其中,ALIGN函数是使行长度为char类型大小的精确倍数。需要注意的是sizeof(char*)在32位机器上的长度为4,在64位上则为8.
- max_heap_tbale_size系统变量用来设置一张MEMORY表的最大容量,默认为16mb(如果需要修改通常只修改当前会话的值,只有在要确定所有会话表都采用统一的大小时才修改全局的值)
- 每次重启服务器,MEMORY表中的数据将全部被清楚,其数据永远不会写入磁盘持久化保存