【MySQL原理系列】- MySQL的存储引擎
文章目录
在文件系统中,MySQL将每个数据库(也可以称之为schema)保存为数据目录下的一个子目录
创建表时,MySQL会在数据库子目录下创建一个和表同名的 .frm 文件保存表的定义
-
因为MySQL使用文件系统的目录和文件来保存数据库和表的定义,大小写敏感性和具体的平台密切相关;在Windows中大小写是不敏感的,而在类Unix中则是敏感的
-
不同存储引擎保存数据和索引的方式不同,但表的定义在MySQL服务层统一处理
可以使用SHOW TABLE STATUS 命令显示表的相关信息
一、页
在MySQL中,页是存储引擎用于管理和组织数据的基本单位,是数据库从磁盘中读取或写入数据的最小块,也是缓存系统操作的基本单位
在InnoDB中,页的默认大小通常是 16KB
页的类型
不同类型的数据被存储在不同类型的页中,InnoDB中的页类型主要有以下几种:
- 数据页(Data Page):存储实际的表记录,每个数据页中包含了多条记录
- 索引页(Index Page):存储B+树结构的索引信息
- Undo页:用于存储事务回滚操作所需的数据
- 系统页:存储与数据字典和表空间相关的信息
页的功能
每次 MySQL 读取或写入磁盘时,操作的都是一页数据,而不是单条记录,好处如下:
- 提高磁盘IO效率:通过一次性读取多个记录(即一页数据)可以减少多次IO操作的开销
- 支持缓存:InnoDB使用 **缓冲池(buffer pool)**来缓存页,以减少磁盘访问。每当需要访问一条记录时,首先会检查该记录所在的页是否在缓冲池中,如果在,则直接从内存读取,避免磁盘IO
页与索引的关系
InnoDB 使用B+树索引结构,数据页和索引页共同构成了B+树的节点,叶子节点存储实际的数据,而非叶子节点存储指向其他页的指针
页分裂与合并
-
在B+树的索引结构中,当一个页的数据超过了页的容量,InnoDB 会进行 页分裂 操作,将数据分裂到两个页中,从而保持B+树的平衡
-
同样,当删除数据后,页中数据减少,InnoDB 可能会进行 页合并,以释放空间
二、InnoDB存储引擎
InnoDB是MySQL的默认事务型引擎,也是最重要、使用最广泛的存储引擎
它被设计用来处理大量的短期事务,短期事务大部分正常提交,且很少回滚
InnoDB的性能和自动崩溃恢复特性,使得它在非事务型存储的需求中也很流行。除非有特别原因需用其他存储引擎,否则用InnoDB引擎
-
InnoDB的数据存储在表空间tablespace中,表空间是由InnoDB管理的一个黑盒子,由一系列的数据文件组成,InnoDB可以将每个表的数据和索引存放在单独的文件中
-
InnoDB采用MVCC来支持高并发,并且实现了四个标准的隔离级别,默认是可重复读,并且通过间隙锁策略防止幻行的出现
-
InnoDB表是基于聚簇索引建立的,聚簇索引对主键查询有很高的性能,不过它的二级索引中必须包含主键列,所以如果主键列很大,其他的所有索引都会很大,若表上的索引较多的话,主键应尽量小
-
InnoDB的存储格式是平台独立的,与平台无关,可以在平台间迁移
-
InnoDB内部做了很多优化:
- 从磁盘读取数据时采用预读
- 自适应哈希索引能自动在内存中创建hash索引以加速读操作
- 用插入缓冲区加速插入操作的
-
作为事务型的存储引擎,InnoDB通过一些机制和工具支持真正的热备份
- 存储引擎要为所有用户维持一致性的视图,是非常复杂的工作
- MySQL的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入
三、MyISAM存储引擎
在MySQL 5.1及之前的版本,MyISAM是默认的存储引擎
MyISAM不支持事务和行级锁,崩溃后无法安全恢复
对于只读的数据,或表比较小能忍受修复操作,可以使用MyISAM,因其速度快
MyISAM会将表存储在两个文件中:数据文件和索引文件,分别以 .MYD 和 .MYI 为扩展名
-
MyISAM表可以存储的行记录数,一般受限于可用的磁盘空间,或者操作系统中单个文件的最大尺寸
-
MyISAM表可以包含动态或者静态行
- 动态静态指行长度是否固定
- 在MySQL 5.0中,MyISAM表如果是变长行,则默认配置只能处理256TB的数据,因为指向数据记录的指针长度是6个字节
1. MyISAM特性
-
加锁与并发
MyISAM对整张表加锁,而不是针对行。读取时对表加共享锁,写入时加排他锁,在表有读取查询的同时,也可以往表中插入新的记录(称为并发插入)
-
修复
对于MyISAM表,MySQL可以手工或者自动执行检查和修复操作,修复和事务恢复崩溃恢复不同
-
索引特性
对于MyISAM表,即使是BLOB和TEXT等长字段,也可以基于其前500个字符创建索引。MyISAM也支持全文索引,这是一种基于分词创建的索引
-
延迟更新索引键(Delayed Key Write)
创建MyISAM表时,如果指定了DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入到磁盘
2. MyISAM压缩表
如果表在创建并导入数据以后,不会再进行修改操作,则更适合用MyISAM压缩表
-
使用myisampack 对MyISAM表进行压缩
-
压缩表不能进行修改(除非将表解缩,修改数据,再次压缩)
-
读取压缩表数据时需要解压,每条记录独立压缩,故读取单行时不用解压整个表
-
压缩表的索引也是只读的
压缩表可以极大地减少磁盘空间占用,因此可以减少磁盘I/O,从而提升查询性能
解压的开销影响并不大,而减少I/O带来的好处要大得多
3. MyISAM性能
MyISAM引擎在某些场景下性能很好,但MyISAM最典型的性能问题是表锁的问题
四、MySQL内建的其他存储引擎
MySQL还有一些有特殊用途的存储引擎
-
Archive引擎
- Archive引擎不是一个事务型的引擎,而是一个针对高速插入和压缩做了优化的简单引擎
- 只支持INSERT 和SELECT 操作
- 支持行级锁和专用的缓冲区
- 会缓存所有的写并对插入的行进行压缩,比MyISAM表的磁盘I/O更少
- 可以实现高并发的插入,每次SELECT查询都需要执行全表扫描,适合日志和数据采集类应用
-
CSV引擎
CSV引擎可以将CSV文件作为MySQL的表来处理,CSV引擎可以在数据库运行时拷入或者拷出文件
-
可以将数据存储为CSV文件,复制到MySQL数据目录下,在MySQL中打开使用
-
同样,将数据写入到CSV引擎表,其他外部程序也能立即从表的数据文件中读取CSV格式的数据
-
因此CSV引擎可以作为一种数据交换的机制,非常有用
-
-
Memory引擎
- 如果要快速访问数据,并且数据不会被修改,重启以后丢失也没关系,则可以用Memory表
- 优点:Memory表至少比MyISAM表要快一个数量级,因为所有的数据都保存在内存中,不需要进行磁盘I/O,且Memory表支持Hash索引,因此查找操作非常快;Memory表的结构在重启以后还会保留,但数据会丢失
- 缺点:表级锁,并发写入的性能较低;不支持BLOB 或TEXT 类型的列,且每行的长度固定
- 用于查找或映射表,或保存数据分析中产生的中间数据。如果MySQL在执行查询的过程中需要使用临时表来保存中间结果,其临时表多选用Memory表;如果中间结果太大超出了Memory表的限制,或者含有BLOB 或TEXT 字段,则临时表会转换成MyISAM表
-
NDB集群引擎
MySQL服务器、NDB集群存储引擎,以及NDB数据库的组合,被称为MySQL集群(MySQL Cluster)
五、选择合适的引擎
除非要用到某些InnoDB不具备的特性,并且没有其他办法可以替代,否则都应该优先选择InnoDB引擎,所以以Oracle在MySQL 5.5版本时将InnoDB作为默认存储引擎
不要混合使用多种存储引擎,否则可能带来一系列复杂的问题
选引擎的考虑因素:
- 事务
- 应用需要事务支持,则InnoDB(或者XtraDB)
- 如果不需要事务,且主要是SELECT和INSERT 操作,那可选MyISAM
- 备份
- 如果需要在线热备份,则InnoDB
- 崩溃恢复
- MyISAM崩溃后发生损坏的概率比InnoDB高很多,而且恢复速度也要慢
- 特有的特性
- 很多应用依赖InnoDB聚簇索引的优化
- MySQL中只有MyISAM支持地理空间搜索
常见应用场景:
-
日志型应用
- 假设需要实时地记录日志到MySQL中,或者通过Apache的mod_log_sql 模块将网站的所有访问信息直接记录到表中,这一类应用的插入速度有很高的要求,数据库不能成为瓶颈
- MyISAM或者Archive存储引擎比较合适,因为它们开销低,而且插入速度非常快
-
读多写少的表
- 如果不介意MyISAM的崩溃恢复问题,选用MyISAM引擎是合适的
- MyISAM引擎在一开始可能没有任何问题,但随着应用压力的上升,则可能迅速恶化,各种锁争用、崩溃后的数据丢失等问题都会随之而来
-
订单处理
- 支持事务就是必要选项,还需考虑存储引擎对外键的支持情况,需用InnoDB
-
主题讨论区
- 多数应用只设计了几张表来保存所有的数据,所以核心表的读写压力非常大
- 中低负载时可以工作得很好,高负载时需要更换支持更高读写的存储引擎,如MyISAM
-
CD-ROM应用
-
CD-ROM或者DVD-ROM是两种只读的光盘存储介质
-
可以考虑使用MyISAM表或者MyISAM压缩表
-
-
大数据量
- 很多InnoDB数据库的数据量在3~5TB之间
- 大数据量下如果采用MyISAM,崩溃后的恢复就是噩梦
- 如果数据量继续增长到10TB以上的级别,就需要建立数据仓库Infobright
六、转换表的引擎
将表的存储引擎转换成另外一种引擎的方法:
-
ALTER TABLE:高效
- 将mytable 的引擎修改为InnoDB,
mysql> ALTER TABLE mytable ENGINE=InnoDB;
- 该方法执行时间很长,在复制期间可能消耗系统所有I/O能力,同时原表会加上读锁
- 如果转换表的存储引擎,将会失去和原引擎相关的所有特性;如将一张InnoDB表转换为MyISAM,然后再转换回InnoDB,原InnoDB表上所有的外键将丢失
- 将mytable 的引擎修改为InnoDB,
-
导出与导入:安全
- 使用mysqldump工具将数据导出到文件,然后修改文件中CREATE TABLE语句的存储引擎选项,注意修改表名,因为同一个数据库中不能存在相同的表名,即使它们使用的是不同的存储引擎
-
创建与查询(CREATE和SELECT)
-
综合了第一种方法的高效和第二种方法的安全
-
是先创建一个新的存储引擎的表,然后利用INSERT…SELECT 语法来导数据
mysql> CREATE TABLE innodb_table LIKE myisam_table;
mysql> ALTER TABLE innodb_table ENGINE=InnoDB;
mysql> INSERT INTO innodb_table SELECT \* FROM myisam_table;
-
如果有必要,可以在执行的过程中对原表加锁,以确保新表和原表的数据一致
-