四、聚簇索引、非聚簇索引区别
聚簇索引、非聚簇索引也被称之为主索引、二级索引。
那么如何区分聚簇索引和非聚簇索引呢!
首先看一下Innodb引擎下,创建表生成的文件,可以看到有俩个ibd文件。
看到这里不知道大家有没有疑问,为什么看有的文章中也会有frm文件呢!但是在这里怎么没有呢!
原因是在MySQL8.0之后将源数据都存储到了表空间中,所以也就不存在frm文件喽!
都知道这个idb文件会存储数据信息和索引信息。
那再来看一下Myisam存储引擎创建表生产的文件。
从图中可以看到创建一个表会生成三个文件,扩展名分别为MYD、MYI、sdi。
MYD:是表数据文件(保存数据的文件)
MYI :是表索引文件(保存索引的文件)
那么就可以得出一个结论
只要数据跟索引存储在一个文件里,那就是聚簇索引,否则就是非聚簇索引。
这个时候就会有人问了,表中有主键的时候,idb文件中存储的是主键+数据,那么当没有设置主键时怎么办呢!
记住这一句话,在Innodb中,数据插入时必须跟一个索引值进行绑定,如果没有主键那就选择唯一索引,如果没有唯一索引就会选择一个6Byte的rowid。
五、表中存在多个索引数据是如何存储的
看了上文的解释,有没有产生过一丝疑问,在Innodb存储引擎下,如果存在多个索引,是不是会产生多个idb文件。
在Innodb中数据只会保存一份,如果有多个索引,会维护多个B+Tree
例如:表字段 id,name,age,sex。
id设置为主键索引(聚簇索引),name设置为普通索引,那么数据到底会存储几份呢!
不管一个表中设置多少个索引,数据只会存储一份,但是这张表会维护多个B+Tree。
按照这个案例中id为主键索引,name为普通索引,那么在这张表中就会维护俩颗B+Tree。
id主键索引跟数据存储在一起,name索引所在的B+Tree中叶子节点存储的是主键id的值。
对应的图就是以下俩幅图,可以好好的看一下。
最后给大家总结一个点:在Innodb中,一定有聚簇索引,其它索引都是非聚簇索引。
这里简单提一下myisam中只有非聚簇索引。
六、索引的几个技术名词
在面试中往往会问这几个关键词,分别为回表、覆盖索引、最左侧原则、索引下推,一定要知道哈!
1. 回表
网上对回表的解释各种各样,咔咔给你说种简单易懂的,但前提是你需要把聚簇索引、非聚簇索引区分清楚。
还是用上边的案例,id为主键索引,name为普通索引。
此时查询语句为select id,name,age from table where name = 'kaka'
那么这条语句会先在name的这颗B+Tree中寻找到主键id,然后在根据主键id的索引获取到数据并且返回。
其实这个过程就是从非聚簇索引跳转到聚簇索引中查找数据,被称为回表,也就是说当你查询的字段为非聚簇索引,但是非聚簇索引中没有将需要查询的字段全部包含就是回表。
在这个案例中,非聚簇索引name的叶子节点只有id,并没有age,所以会跳转到聚簇索引中,根据id在查询整条记录返回需要的字段数据。
2. 覆盖索引
覆盖索引,根据名字都能理解的差不多,就是查询的所有字段都创建了索引!
此时查询语句为select id,name from table where name = 'kaka'
那么这条语句就是使用了覆盖索引,因为id和name都为索引字段,查询的字段也是这俩个字段,所以被称为索引覆盖。
也就是说当非聚簇索引的叶子节点中包含了需要查询的字段时就被称为覆盖索引
3. 最左匹配
最左匹配原则是在组合索引中存在的。
还是用之前表信息:表字段 id,name,age,sex。
此时给name,age设置成组合索引。
以下语句中那个不符合最左侧原则。
select * from table where name = ? and age = ?
select * from table where name = ?
select * from table where age = ?
select * from table where age= ? and name= ?
可以自行做一下测验哈!是只有第三条语句不会用到索引,其它的三条语句都会符合最左侧原则。
关于这个最左侧原则远远不止这么简单的,一试就是一个坑,关于这部分内容咔咔后期会在优化文章中提到。
4. 索引下推
还是使用这条sql语句。
select * from table where name = ? and age = ?
索引下推是在MySQL5.6及以后的版本出现的。
之前的查询过程是,先根据name在存储引擎中获取数据,然后在根据age在server层进行过滤。
在有了索引下推之后,查询过程是根据name、age在存储引擎获取数据,返回对应的数据,不再到server层进行过滤。
当你使用Explain分析SQL语句时,如果出现了index condition pushdown那就是使用了索引下推,索引下推是在组合索引的情况出现几率最大的。
七、索引存储在什么地方
索引的数据文件是存储在磁盘中的,也是需要进行持久化操作。
但是当使用索引时会把数据从磁盘读取到内存中,读取方式为分块读取。
这时就要涉及到操作系统的概念,操作系统在磁盘中获取数据,假设现在要取的数据大小是1kb,但操作系统并不会只取出你需要的这1kb,而是会取出4kb的数据。
为什么会是4kb,因为在操作系统中一页的数据就是4kb。
那又为什么只需要1kb而取出整页的数据呢!
那就又会涉及到另一个概念那就是局部性原理:数据和程序都有聚集成群的倾向,在访问了一条数据之后,在之后有极大的可能再次访问这条数据和这条数据的相邻数据。
所以说MySQL的Innodb存储引擎,在读取数据时也会采取这种局部性原理,每次读取的数据是16kb。
在Innodb存储引擎下每页的大小默认为16kb,这个参数也可以进行调整,参数为innodb_page_size。
最后一点:
既然标题问的是索引数据存储在什么地方,在第一句就直接回答了索引是存储在磁盘中,并且以页为单位进行从磁盘往内存读取。
那为什么不直接存储在内存中呢!你有没有这个疑问呢!
如果索引数据只存储在内存中,那么当电脑关机,服务器宕机之后,就需要重新生成索引,这种的效率是十分低的。
八、总结
以上就是咔咔对索引的理解,在尽最大的可能将知识点说全面。
如果还有遗漏,或者文章中有错误的地方还请各位能给出提议。