二、建立索引时那些不为人知的内幕
弄明白了索引的底层数据结构后,再一起来聊一聊创建索引后会发生什么事情呢?一般我们都会以下述方式创建索引:
-- ①通过CREATE语句创建
CREATE INDEX indexName ON tableName (columnName(length) [ASC|DESC]);
-- ②通过ALTER语句创建
ALTER TABLE tableName ADD INDEX indexName(columnName(length) [ASC|DESC]);
-- ③建表时通过DML语句创建
CREATE TABLE tableName(
columnName1 INT(8) NOT NULL,
columnName2 ....,
.....,
INDEX [indexName] (columnName(length))
);
复制代码
在咱们通过SQL命令创建索引时,MySQL首先会判断一下当前表的存储引擎,索引机制本身是由存储引擎层提供实现的,不同的引擎实现的索引也不同,因此创建索引时第一步就会先判断存储引擎,然后根据不同的存储引擎创建索引,这里重点聊一下常用的MyISAM、InnoDB。
2.1、常用存储引擎的数据存储
首先为了能够实际观察到两个引擎之间的区别,分别使用MyISAM、InnoDB两个引擎创建两张表:
-- 创建一张使用MyISAM引擎的表:zz_myisam_index
CREATE TABLE `zz_myisam_index` (
`z_m_id` int(8) NOT NULL,
`z_m_name` varchar(255) NULL DEFAULT ''
)
ENGINE = MyISAM
CHARACTER SET = utf8
COLLATE = utf8_general_ci
ROW_FORMAT = Compact;
-- 创建一张使用InnoDB引擎的表:zz_innodb_index
CREATE TABLE `zz_innodb_index` (
`z_i_id` int(8) NOT NULL,
`z_i_name` varchar(255) NULL DEFAULT ''
)
ENGINE = InnoDB
CHARACTER SET = utf8
COLLATE = utf8_general_ci
ROW_FORMAT = Compact;
复制代码
上述过程中创建了两张表:zz_myisam_index、zz_innodb_index,分别使用了不同的引擎,而MySQL中对于所有的数据都会放入到磁盘中存储,因此先来找一下这两张表的本地位置,默认位于C:ProgramDataMySQLMySQL Server 5.xdata这个目录中,在这里保存着所有已创建的数据库磁盘文件,首先从这里面找到对应的数据库并进入目录,如下:

2.1.1、使用MyISAM引擎的表
zz_myisam_index这张表是使用MyISAM引擎的表,在磁盘中有三个文件:
- zz_myisam_index.frm:该文件中存储表的结构信息。
- zz_myisam_index.MYD:该文件中存储表的行数据。
- zz_myisam_index.MYI:该文件中存储表的索引数据。
也就是说,MyISAM引擎的表数据和索引数据,是分别放在两个不同的磁盘文件中存储的,这也意味着MyISAM引擎并不支持聚簇索引,因为聚簇索引要求表数据和索引数据一起存储在同一块空间,而MyISAM的.MYI索引文件中,存储的是表数据所在的地址指针。
2.1.2、使用InnoDB引擎的表
zz_innodb_index这张表是使用InnoDB引擎的表,在磁盘中仅有两个文件:
- zz_innodb_index.frm:该文件中存储表的结构信息。
- zz_innodb_index.ibd:该文件中存储表的行数据和索引数据。
因为InnoDB引擎中,表数据和索引数据都一起放在.ibd文件中,也就代表着索引数据和表数据是处于同一块空间存储的,这符合聚簇索引的定义,因此InnoDB支持聚簇索引。
同时也正由于这个原因,所以如果使用InnoDB引擎的表未主动创建聚簇索引,它会自动选择表中的主键字段,作为聚簇索引的字段。但如果表中未声明主键字段,那则会选择一个非空唯一索引来作为聚簇索引。但如果表中依旧没有非空的唯一索引,InnoDB则会隐式定义一个主键来作为聚簇索引(这个列在上层是不可见的,是一个按序自增的值)。
OK~,搞明白两种常用引擎的底层存储区别后,接下来再聊聊手动创建索引后究竟会发生什么?
2.2、手动创建索引后发生的事情
当手动创建索引后,MySQL会先看一下当前表的存储引擎是谁,接着会判断一下表中是否存在数据,如果表中没有数据,则直接构建一些索引的信息,例如索引字段是谁、索引键占多少个字节、创建的是啥类型索引、索引的名字、索引归属哪张表、索引的数据结构.....,然后直接写入对应的磁盘文件中,比如MyISAM的表则写入到.MYI文件中,InnoDB引擎的表则写入到.ibd文件中。