MySQL主流存储引擎概述
2013-08-01 15:53:47 阿炯

MySQL常用的存储引擎为MyISAM、InnoDB、MEMORY、MERGE,其中InnoDB提供事务安全表,其他存储引擎都是非事务安全表。 MySQL最常用存储引擎Myisam和Innodb,mysql 5.5.5以后默认存储引擎为Innodb,MySQL的每种引擎在MySQL里是通过插件的方式使用的,MySQL可以支持多种存储引擎。

MyISAM是MySQL的默认存储引擎,MyISAM不支持事务、也不支持外键,但其访问速度快,对事务完整性没有要求。默认的MySQL插件式存储引擎,它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。注意,通过更改STORAGE_ENGINE配置变量,能够方便地更改MySQL服务器的默认存储引擎。

InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是比起MyISAM存储引擎,InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引,用于事务处理应用程序,具有众多特性,包括ACID事务支持。

MEMORY存储引擎使用存在内存中的内容来创建表,每个MEMORY表只实际对应一个磁盘文件。MEMORY类型的表访问非常得快,因为它的数据是放在内存中的,并且默认使用HASH索引。但是一旦服务关闭,表中的数据就会丢失掉。其次它有空间大小的限制。将所有数据保存在RAM中,在需要快速查找引用和其他类似数据的环境下,可提供极快的访问。

MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同。MERGE表本身没有数据,对MERGE类型的表进行查询、更新、删除的操作,就是对内部的MyISAM表进行的。

Archive存储引擎为大量很少引用的历史、归档、或安全审计信息的存储和检索提供了完美的解决方案。

Federated存储引擎能够将多个分离的MySQL服务器链接起来,从多个物理服务器创建一个逻辑数据库。十分适合于分布式环境或数据集市环境。

BLACKHOLE存储引擎接受但不存储数据,并且检索总是返回一个空集。

Cluster/NDB存储引擎MySQL的簇式数据库引擎,尤其适合于具有高性能查找要求的应用程序,这类查找需求还要求具有最高的正常工作时间和可用性。

其他存储引擎包括CSV(引用由逗号隔开的用作数据库表的文件),Blackhole(用于临时禁止对数据库的应用程序输入),以及Example引擎(可为快速创建定制的插件式存储引擎提供帮助)。




它们间的特点关系对比

MyISAM

Myisam是Mysql的默认存储引擎,当create创建新表时,未指定新表的存储引擎时,默认使用Myisam。
每个MyISAM在磁盘上存储成三个文件。文件名都和表名相同,扩展名分别是.frm(存储表定义)、.MYD (MYData,存储数据)、.MYI (MYIndex,存储索引)。数据文件和索引文件可以放置在不同的目录,平均分布io,获得更快的速度。   

要指定索引和数据文件的路径,需要在创建表时通过'data directory'和'index dircetory'语句来指定,即它们可以放置在不同的路径下,当然要给出其绝对路径且还要有相应的权限。

造成myisam类型表损坏的原因有多种,且损坏后表就不能再被访问了,会提示错误的结束或要求修正或异常重启。解决的方法有:使用'check table'来检查myisam表,'repair table'可用来修复一个受损的myisam表。

MyISAM表还支持3中不同的存储格式: 
1、静态表
2、动态表
3、压缩表

静态表是默认的存储格式,静态表中的字段都是非变长的字段,优点是:存储非常迅速,容易缓存,出现故障容易恢复;缺点是:占用的空间通常比动态表多。(注意: 在存储时,列的宽度不足时,用空格补足,在返回给应用时并不会将这些空格也给应用;同理当字段后本来有空格时,数据库也会自动处理掉它,但字段前的空格将会保留)
 
动态表的字段是变长的,优点是:占用的空间相对较少,但是频繁地更新删除记录会产生碎片,需要定期改善性能(optimize table或myisamchk -r命令),并且出现故障的时候恢复相对比较困难。 

压缩表占用磁盘空间小,每个记录是被单独压缩的,所以只有非常小的访问开支且为只读。

如果你的应用是不需要事务,处理的只是基本的CRUD操作,那么MyISAM是不二选择。

在myisam表中,自增列可以是组合索引的其它列,当插入记录后,自增列是按组合索引的前几列进行排序后递增的。

InnoDB
InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比Myisam的存储引擎,InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引。支持外键存储引擎只有InnoDB,在创建外键的时候,要求附表必须有对应的索引,子表在创建外键的时候也会自动创建对应的索引。 
InnoDB存储方式为两种:
1、使用共享表空间存储,这种方式创建的表的结构保存在'.frm'文件中,数据和索引保存在innodb_data_home_dir和innodb_data_file_path定义的表空间中,可以是多个文件。
2、使用多表空间,这种方式创建的表结构仍然保存在'.frm'文件中,但数据和索引单独保存中'.ibd'文件中。如果是分区表,则每个分区对应单独的'.ibd'文件,文件名是“表名+分区名”,可以在创建分区时指定每个分区的数据文件位置,以此来将i/o分布在多个磁盘上。要使用多表空间方式,需要设置参数:innodb_file_per_table,并重启服务生效,新建表将新的方式来创建,已有的表仍会使用共享表空间方式存储。如果将已有的多表空间方式改回为共享表方式,则新建表会在共享表空间中创建,但已经有的多表空间依然保持原有的访问方式。所以表空间参数生效后,只对新建的表有效。

多表空间方式的数据文件没有大小限制,无需初始其大小,也不需要设置文件最大限制、扩展大小等参数。对于多表空间表,可以比较方便地进行单表备份和恢复,但直接复制'.ibd'文件是不行的,因为没有提供其数据字典信息,直接复制'.ibd'与'.frm'文件恢复时是不能被正确识别的,要通过下面指令来操作:
alter table tbl_x discard tablespace;
alter table tbl_x import tablespace;

即可将备份恢复到数据库中,但这种的单表备份,只能恢复到原表所在的数据库中,而不能恢复到其它库中,当然这需要使用'mysqldump'或'mysqlimport'工具来实现。

注意:即使在多表空间模式下,共享表空间是必须的,因此innodb将内部数据词典和未完成日志存放于此。

当对auto_increment列插入空、'0'、'null'时,它都将自动转换为合适且正确值。

当使用'last_insert_id()'查询当前线程最后插入记录使用值,若一次插入了多条记录,则它返回的是第一条记录所使用的自增值。

对于innodb表,自动增长列必须是索引,如果是组合索引,也必须是其的第一列,这个与myisam是有区别的。

InnoDB被设计成适用于高并发读写的情况.使用MVCC(Multi-Version Concurrency Control)以及行级锁来提供遵从ACID的事务支持。InnoDB支持外键参照完整性,具备故障恢复能力。另外 InnoDB的性能其实还是不错的,特别是在处理大数据量的情况下,用官方的话说就是: InnoDB的CPU效率是其他基于磁盘的关系数据库存储引擎所不能比的。不过InnoDB的备份恢复要麻烦一点,除非你使用了4.1以后版本提供的Mulit-tablespace支持,因为InnoDB和MyISAM不同,他的数据文件并不是独立对应于每张表的。而是使用的共享表空间,简单的拷贝覆盖方法对他不适用,必须在停掉MYSQL后对进行数据恢复。使用Per-Table Tablespacesd,使其每张表对应一个独立的表空间文件,则情况要简单很多。

在指定外鍵约束时,可以指定在删除、更新父表时,对子表进行相应操作,包括:restrict、cascade、set null、no action。其中restrict与no action相同,即限制在子表有关联记录的情况下父表不能更新;cascade表示父表在更新或删除时,更新或删除子表对应的记录;set null则表示父表在更新或删除时,更新或删除子表对应的字段被set null。所以选择后两种方式要谨慎,可能会因此错误的操作导致数据丢失。

当某表被其它表创建了外键参照,那么该表的对应索引或主键禁止被删除。

mysql> create table menu(id smallint not null auto_increment primary key,alias char(16) not null,descri varchar(256))engine=InnoDB;
mysql> insert into menu values('','news','about all news');
mysql> insert into menu values('null','product','in open source product variety');

mysql>create table article(id int not null auto_increment,pid smallint not null,keywords varchar(256),intro tinytext,last_update timestamp default 0 on update current_timestamp,primary key(id),key idx_art_menu(pid),constraint foreign key (pid) references menu(id) on delete restrict on update cascade)engine=innodb;

constraint 后最好跟一直观别名,来描述此外键约束。

mysql> insert into article values('',1,'mysql key words','none of none','');
Query OK, 1 row affected, 2 warnings (0.00 sec)

mysql> show warnings;
+---------+------+------------------------------------------------------+
| Level   | Code | Message                                              |
+---------+------+------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: '' for column 'id' at row 1 |
| Warning | 1265 | Data truncated for column 'last_update' at row 1     |
+---------+------+------------------------------------------------------+
2 rows in set (0.00 sec)

mysql> select * from article;
+----+-----+-----------------+--------------+---------------------+
| id | pid | keywords        | intro        | last_update         |
+----+-----+-----------------+--------------+---------------------+
|  1 |   1 | mysql key words | none of none | 0000-00-00 00:00:00 |
+----+-----+-----------------+--------------+---------------------+

mysql> insert into article values('null',2,'free oa office','intro text here',now());

mysql> insert into article values('null',3,'mysql storeage engine ','may be lots of it',now());
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`article`, CONSTRAINT `article_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `menu` (`id`) ON UPDATE CASCADE)

mysql> delete from menu where id=2;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`article`, CONSTRAINT `article_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `menu` (`id`) ON UPDATE CASCADE)

在导入多个表的数据时,如果需要忽略表之前的导入顺序,可以暂时关闭外键的检查;同理,在执行load data 和 alter table操作的时候,可以通过暂时关闭外键约束来加快处理速度,指令是:"set foreign_key_checks=0;",在处理完成后,通过"set foreign_key_checks=1;"来复原。

InnoDB完全支持4个事务隔离级别,但不支持全文检索,通过索引实现了行级锁定,但全表扫描仍然会表锁,使用的时候注意间隙锁的影响。并且读写阻塞与事务隔离级别相关,具有非常高效的缓存特性,能够缓存索引,也能缓存数据。整个表和主键以CLUSTER方式存储。

InnoDB适用场景

InnoDB具有较好的事务特性,也就是事务支持,其行级锁定机制对高并发有很好的适应能力,但需要确保查询是通过索引来完成。能够很好地适应于数据更新较为频繁的场景,但是对数据一致性要求较高,如果硬件设备内存较大,可以利用InnoDB较好的缓存能力来提高内存利用率,尽可能减少磁盘IO。

4个事务隔离级别

未授权读取(Read Uncommitted):读未提交数据,这是事务最低的隔离级别,在并发的事务中,它允许一个事务可以读到另一个事务未提交的更新数据。(会出现脏读,不可重复读和幻读)

授权读取(Read Committed):读已提交数据,保证并发的事务中,一个事务修改的数据提交后才能被另外一个事务读取到。(会出现不可重复读和幻读)

可重复读取(Repeatable Read):可重复读,这种事务隔离级别可以防止脏读,不可重复读,但是可能出现幻读。一般是使用“快照”的方式来实现。

序列化(Serializable):事务被处理为顺序执行,这是花费最高的,但也是最可靠的事务隔离级别,能够有效避免脏读、不可重复读、幻读。

脏读、不可重复读、幻读的概念

脏读

一个事务读取到另一事务未提交的更新新据。当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作也可能是不正确的。

不可重复读

在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是后续读取不能读到另一事务已提交的更新数据。

幻读

事务T1执行一次查询,然后事务T2新插入一行记录,这行记录恰好可以满足T1所使用的查询的条件。然后T1又使用相同的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行。这个新行就称为“幻像”,因为对T1来说这一行就像突然出现的一样。

数据库事务的4个特性

原子性(Atomic)
组成一个事务的多个数据库操作是一个不可分割的原子单元;只有所有操作执行成功,整个事务才提交,其中一个操作失败,都必须回滚到初始状态。

一致性(Consistency)
事务操作成功后数据库所处的状态和它的业务规则是一致的;(即数据总额不会被破坏。如A账户转账100到B账户,无论操作成功与否,A和B的存款总额是不变的)

隔离性(Isolation)
在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对彼此产生干扰。(并非是完全无干扰,
根据数据库的隔离级别,会产生不同程度的干扰)

持久性(Durability)
一旦事务提交成功,事务中的数据操作都必须持久化到数据库中;就算数据库崩溃,也必须保证有某种机制恢复。


MEMORY

MEMORY类型的存储引擎主要用于那些内容变化不频繁的代码表,或者作为统计操作的中间结果表,便于高效地堆中间结果进行分析并得到最终的统计结果。对MEMORY存储引擎的表进行更新操作要谨慎,因为数据并没有实际写入到磁盘中,所以一定要对下次重新启动服务后如何获得这些修改后的数据有所考虑。 此类表实际仅对应一个磁盘文件:.frm,默认使用hash索引。

mysql>create table arts engine=memory select id,alias,title,hits from freeoadb.content;
mysql> show table status like 'corps';

每个memory有所能放置的数据量,受到max_heap_table_size系统变量约束,初始值为16MB,可以按需加大;另外在其定义时,可以通过max_rows来指定表的最大行数。服务器需要充足的内存来维持这些表,当不需要这些表及内容时,清空(delete from 或 truncate)它们可以释放内存。
当数据量过大时,就会报出下面的问题,而导致建表失败:
ERROR 1114 (HY000): The table 'arts' is full

此种类型表有许多自身不足,从而限制了其用途。大小限制、字段类型限制、无持久性。查询速度快,可用其做一些中间结果暂存表之用。

使用MySQL Memory存储引擎的出发点是速度。为得到最快的响应时间,采用的逻辑存储介质是系统内存。虽然在内存中存储表数据确实会提供很高的性能,但当mysqld守护进程崩溃时,所有的Memory数据都会丢失。获得速度的同时也带来了一些缺陷。它要求存储在Memory数据表里的数据使用的是长度不变的格式,这意味着不能使用BLOB和TEXT这样的长度可变的数据类型,VARCHAR是一种长度可变的类型,但因为它在MySQL内部当做长度固定不变的CHAR类型,所以可以使用。

一般在以下几种情况下使用Memory存储引擎:

目标数据较小,而且被非常频繁地访问。在内存中存放数据,所以会造成内存的使用,可以通过参数max_heap_table_size控制Memory表的大小,设置此参数,就可以限制Memory表的最大大小。

如果数据是临时的,而且要求必须立即可用,那么就可以存放在内存表中。

存储在Memory表中的数据如果突然丢失,不会对应用服务产生实质的负面影响。

Memory同时支持散列索引和B树索引。B树索引的优于散列索引的是,可以使用部分查询和通配查询,也可以使用<、>和>=等操作符方便数据挖掘。散列索引进行“相等比较”非常快,但是对“范围比较”的速度就慢多了,因此散列索引值适合使用在=和<>的操作符中,不适合在<或>操作符中,也同样不适合用在order by子句中。


Merge

MERGE用于将一系列等同的MyISAM表以逻辑方式组合在一起,并作为一个对象引用它。MERGE表的优点在于可以突破对单个MyISAM表大小的限制,通过将不同的表分布在多个磁盘上,可以有效的改善MERGE表的访问效率。 

MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同。MERGE表本身没有数据,对MERGE类型的表进行查询、更新、删除的操作,就是对内部的MyISAM表进行的。 对此类表的插入操作,是通过insert_method子句定义的表,可以有3个不同值:first:作用在第一个表上;last:作用在最后一个表上;不定义或定义为'no':不能对这个merge表进入插入操作。当对其进行drop时,只是删除了merge的定义,而对内部表内容没有影响。
merge表在磁盘上有两个相关文件,一个是'.frm'文件存储表定义,另一个'.mrg'文件包含了组合表的信息,由哪些表组成、插入数据时的依据规则。可以直接通过编辑'.mrg'文件来修改其内容,后通过'flush tables'来刷新生效。

示例
mysql> create table art10 like freeoa.content;
mysql> create table art11 like freeoa.content;
mysql> create table art12 like freeoa.content;

insert into art10(id,title,created,hits) select id,title,created,hits from freeoa.content where year(created)=2010 limit 5;

art11与art12表采取类似的操作,插入相关年份的一些记录。

创建主表,这里采用复制其它表的方法,快速而不容易出错。
mysql> create table art like art10;
mysql> alter table art engine=merge union(art10,art11,art12) insert_method=last;

mysql> show create table art;
......
ENGINE=MRG_MyISAM DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`art10`,`art11`,`art12`)

且从art表全部查询出的记录数目为各个子表的记录数之和。

当向art表中插入记录时,会插入到最后一张子表中:即art12表,即使这条记录是2011年的。这也正是merge表与分区表之间的区别,merge表并不能智能地将记录写到对应的表中,而分区是支持此类逻缉的,它们在使用上是透明的。需要注意的是,分区表不是存储引擎。

解释一下MERGE表的建表语句。

ENGINE=MERGE
指明使用MERGE引擎,有些同学可能见到过ENGINE=MRG_MyISAM的例子,也是对的,它们是一回事。

UNION=(t1, t2)
指明了MERGE表中挂接了些哪表,可以通过alter table的方式修改UNION的值,以实现增删MERGE表子表的功能。比如:

alter table tb_merge engine=merge union(tb_freeoa) insert_method=last;

INSERT_METHOD=LAST
INSERT_METHOD指明插入方式,取值可以是:0 不允许插入;FIRST 插入到UNION中的第一个表; LAST 插入到UNION中的最后一个表。

MERGE表及构成MERGE数据表结构的各成员数据表必须具有完全一样的结构。每一个成员数据表的数据列必须按照同样的顺序定义同样的名字和类型,索引也必须按照同样的顺序和同样的方式定义。

ARCHIVE

Archive是归档的意思,在归档之后很多的高级功能就不再支持了,仅仅支持最基本的插入和查询两种功能。在MySQL 5.5版以前,Archive是不支持索引,但是在MySQL 5.5以后的版本中就开始支持索引了。Archive拥有很好的压缩机制,它使用zlib压缩库,在记录被请求时会实时压缩,所以它经常被用来当做仓库使用。

如何选择合适的存储引擎
选择标准: 根据应用特点选择合适的存储引擎,对于复杂的应用系统可以根据实际情况选择多种存储引擎进行组合。下面是常用存储引擎的适用环境:
1、MyISAM:默认的MySQL插件式存储引擎,它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一
2、InnoDB:用于事务处理应用程序,具有众多特性,包括ACID事务支持
3、Memory:将所有数据保存在RAM中,在需要快速查找引用和其他类似数据的环境下,可提供极快的访问
4、Merge:允许MySQL DBA或开发人员将一系列等同的MyISAM表以逻辑方式组合在一起,并作为1个对象引用它们。对于诸如数据仓储等VLDB环境十分适合。

如何查看服务器有哪些存储引擎可以使用?
为确定你的MySQL服务器可以用哪些存储引擎,执行如下命令:
show engines;

如何选择合适的存储引擎?
选择标准可以分为:
(1)是否需要支持事务;
(2)是否需要使用热备;
(3)崩溃恢复:能否接受崩溃;
(4)是否需要外键支持;

然后按照标准,选择对应的存储引擎即可。

MyISAM和InnoDB的区别

InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB 类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。

MyIASM是IASM表的新版本,有如下扩展:  
二进制层次的可移植性
NULL列索引
对变长行比ISAM表有更少的碎片
支持大文件
更好的索引压缩
更好的键码统计分布
更好和更快的auto_increment处理

以下是一些细节和具体实现的差别:

1.InnoDB不支持FULLTEXT类型的索引。

2.InnoDB中不保存表的 具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。

3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。

4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。

5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如:update table set num=1 where name like “%freeoa%”

任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。


MySQL数据库架构简介



最上层用于连接、线程处理;第二层中包含了大多数 的核心服务,包括了对 SQL 的解析、分析、优化和缓存等功能,存储过程、触发器和视图都是在这里实现的;而第三层就是 真正负责数据的存储和提取的存储引擎,例如:InnoDB、MyISAM等,文中对存储引擎的介绍都是对 InnoDB 实现的分析。
 
数据存储结构

在整个数据库体系结构中,我们可以使用不同的存储引擎来存储数据,而绝大多数存储引擎都以二进制的形式存储数据。

在 InnoDB 存储引擎中,所有的数据都被逻辑地存放在表空间中,表空间(tablespace)是存储引擎中最高的存储逻辑单位,在表空间的下面又包括段(segment)、区(extent)、页(page):


同一个数据库实例的所有表空间都有相同的页大小;默认情况下,表空间中的页大小都为 16KB,当然也可以通过改变 innodb_page_size 选项对默认大小进行修改,需要注意的是不同的页大小最终也会导致区大小的不同。


从图中可以看出,在 InnoDB 存储引擎中,一个区的大小最小为 1MB,页的数量最少为 64 个。


随机读取和顺序读取

在我们常用的sql理解中,数据是以行的形式读取出来的,其实不然,通过上述的结构,我们可以了解到,单次从磁盘读取单位是页,而不是行,也就是说,你即便只读取一行记录,从磁盘中也是会读取一页的,当然了单页读取代价也是蛮高的,一般都会进行预读。


1、数据的读取路径


关系型数据库管理系统最重要的一个目标就是,确保表或者索引中的数据是随时可以用的。那么为了尽可能的实现这个目标,会使用内存中的缓冲池来最小化磁盘活动。

每一个缓冲池都足够大,大到可以存放许多页,可能是成千上万的页。

缓冲池管理器将尽力确保经常使用的数据被保存于池中,以避免一些不必要的磁盘读。如果一个索引或者表页在缓冲池中被找到,那么将会处理很快。

如果在缓冲池中,没有找到数据,会从磁盘服务器的缓冲区里面去读取。

磁盘服务器的缓冲区,如同数据库的缓冲池读取一样,磁盘服务器试图将频繁使用的数据保留在内存中,以降低高昂的磁盘读取成本。这个读取成本大概会在1ms左右。

如果磁盘服务器的缓冲池中依然没有找到数据,此时就必须要从磁盘读取了,此时读取又分区随机读取和顺序读取。


2、随机I/O

我们必须记住一个页包含了多条记录,我们可能需要该页上的所有行,也可能是其中一部分,或者是一行,但所花费的成本都是相同的,读取一个页,需要一次随机I/O,大约需要10ms的时间。


时间组成:


我们可以看到,一次随机IO需要耗时的时间还是很久的,10ms对计算机来说是一个很长的时间节点了。

 
3、顺序读取

如果我们需要将多个页读取到缓冲池中,并按顺序处理它们,此时读取的速度回变的很快,具体的原理,在B树索引中也有过介绍,此时读取每个页面(4kb)所花费的时间大概为0.1ms左右,这个时间消耗对随机IO有很大的优势。


以下几种情况,会对数据进行顺序读取。

全表扫描

全索引扫描

索引片扫描

通过聚蔟索引扫描表行


顺序读取有两个重要的优势:

同时读取多个页意味着平均读取每个页的时间将会减少。在当前磁盘服务器条件下,对于4kb大小的页而言,这一值可能会低于0.1ms(40MB/s)。由于数据库引擎知道需要读取哪些页,所有可以在页被真正请求之前就提前将其读取进来,我们称为预读。