Java程序员这项技能都没掌握,还是别去面试了

·  阅读 139
mysql 的索引(面试必问。因为大公司的数据规模一般都比较大,如果不走索引,带来的耗时是比较严重的)

你有没有遇到过你自己创建的索引,你自己却用不到的窘境?

你知道索引吗?索引具体采用的哪种数据结构呢?

聚簇索引和非聚簇索引,在查询数据的时候有区别吗?

其实有过阿里京东这些大厂面试经验的小伙伴们应该都有一种感觉这些大厂对于底层知识还是比较看重的,而我们却很少会或者说很少会再去想这些

今天,我们就来好好的聊一下MySQL的索引

什么是索引

索引其实就是一种数据结构,能够帮助我们快速的检索数据库中的数据。常见的MySQL主要有两种结构:Hash索引和B+ Tree索引,小编使用的是InnoDB引擎,默认的是B+树。

至于B+ Tree索引和Hash索引区别,这边给大家简单的说一下

Hash索引底层是哈希表,哈希表是一种以key-value存储数据的结构,所以多个数据在存储关系上是完全没有任何顺序关系的,对于区间查询是无法直接通过索引查询的,就需要全表扫描 。 哈希索引适合等值查询,但是不无法进行范围查询 哈希索引没办法利用索引完成排序 ,它不支持多列联合索引的最左匹配规则 如果有大量重复键值得情况下,因为存在哈希碰撞问题的原因会导致哈希索引的效率会很低。B+ Tree是一种多路平衡查询树,所以他的节点是天然有序的(左子节点小于父节点、父节点小于右子节点),所以对于范围查询的时候不需要做全表扫描。

聚簇索引和非聚簇索引

MySQL中最常见的两种存储引擎分别是MyISAM和InnoDB,分别实现了非聚簇索引和聚簇索引。

在 InnoDB 里,索引B+ Tree的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引。而索引B+ Tree的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引。

前段时间看到一个问题:“你知道为什么InnoDB非主键索引普遍比主键索引要慢吗?”答案是InnoDB使用了聚簇索引,主键索引主需要查询一次,而非主键索引需要查询两次。

为什么非主键索引需要查询两次呢?且看接下来的内容。

主索引与辅助索引

首先介绍一下基础的概念。在索引的分类中,我们可以按照索引的键是否为主键来分为“主索引”和“辅助索引”,使用主键键值建立的索引称为“主索引”,其它的称为“辅助索引”。因此主索引只能有一个,辅助索引可以有很多个。

为什么需要用到辅助索引?因为前面我们介绍了,查询语句如果想要使用索引,是需要满足最左匹配原则的。有时候我们的查询并不会使用到主键列,所以需要在其它列建立索引,即辅助索引。

非聚簇索引

非聚簇索引的主索引和辅助索引几乎是一样的,只是主索引不允许重复,不允许空值,他们的叶子结点的key都存储指向键值对应的数据的物理地址。

非聚簇索引的数据表和索引表是分开存储的。非聚簇索引中的数据是根据数据的插入顺序保存。因此非聚簇索引更适合单个数据的查询。插入顺序不受键值影响。

聚簇索引

聚簇索引的主索引的叶子结点存储的是键值对应的数据本身,辅助索引的叶子结点存储的是键值对应的数据的主键键值。因此主键的值长度越小越好,类型越简单越好。

聚簇索引的数据和主键索引存储在一起。

聚簇索引的数据是根据主键的顺序保存。因此适合按主键索引的区间查找,可以有更少的磁盘I/O,加快查询速度。但是也是因为这个原因,聚簇索引的插入顺序最好按照主键单调的顺序插入,否则会频繁的引起页分裂(BTree插入时的一个操作),严重影响性能。

在InnoDB中,如果只需要查找索引的列,就尽量不要加入其它的列,这样会提高查询效率。

一张图说明聚簇索引与非聚簇索引的区别:


很多小伙伴以为:在查询数据的时候,因为非主键索引的叶子节点是主键的值,查到主键的值以后,就还需要再通过主键的值再进行一次查询。主键索引查询只会查一次,而非主键索引需要回表查询多次

其实不是全部情况都是这样的:覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。 当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。 如,表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。当我们通过SQL语句:select key2 from covering_index_sample where key1 = ‘keytest’;的时候,就可以通过覆盖索引查询,无需回表。

这里详细说一下覆盖索引和联合索引

覆盖索引

创建了一个辅助索引,如果能直接从这个辅助索引文件中获取到数据,而无需去访问聚集索引(自增主键索引)文件的话,那么这中就用到索引覆盖了。

这种的效率是极其高的。

select a from table xxx where b = 2复制代码

像上面这个语句,如果只是为列b建立索引,那么执行这个SQL是可以用到索引的,但是由于a列的数据并没有在这个b索引中,索引需要再次访问聚集索引文件。

如果建立(b,a)这样的联合索引,那么这个联合索引文件就会包含了a列和b列的值,这样执行上面的语句,就可以用到索引覆盖了。

联合索引

联合索引就是多列索引,存在的目的是为了提高查询性能。

CREATE TABLE `xxxx` (  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '自增',  `code` int(10),  `age` int(10),  PRIMARY KEY (`id`),  KEY `code` (`code`)) ENGINE=InnoDB复制代码

部分同学会觉得直接使用单列索引即可,为啥非要使用联合索引。其实从我上面举得例子就可以发现,只是使用单列索引的话,虽然也是用到了索引,但是经常会回溯到聚集索引,还是有性能损耗的,尤其是还要加上排序等操作,那就更慢了。这里再举一个例子,分页查询

select id,code from xxxx order by age limit 50000,10;复制代码

如果只是在age列建立索引的话,这个SQL查询的效率不高,但是建立(age,code)怎样的联合索引,就无需回溯到聚集索引,便可完成操作。

简单枚举值的列不要建立索引

某个列的值只有0和1,为这种列建立辅助索引就大可不必,因为没任何区分度,比如说按照0来找,从B+数中可以找到一大堆数据,性能差。

索引列不要参与计算

B+数存的是key和数据,如要查询的时候,需要对树中的数据先计算后再比较,代价太大了,也极其的慢,因此索引列使用了函数,压根就无法用到索引,MySql也不支持这样做。

能扩展索引就扩展,尽量别新建

联合索引的好处已经在上面有提到了,如果数据库有a索引,现在b列也需要索引,那么直接建立(a,b)即可。因为像b=11或者b in (11,22)这种查询,

MySql是会优化的,可以用到索引的,可以放心使用。

索引的优缺点

优势:以快速检索,减少I/O次数,加快检索速度;根据索引分组和排序,可以加快分组和排序;

劣势:索引本身也是表,因此会占用存储空间。索引的维护和创建需要时间成本,这个成本随着数据量增大而增大;构建索引会降低数据表的修改操作(删除,添加,修改)的效率,因为在修改数据表的同时还需要修改索引表。

今天对索引的介绍暂时就到这里,如果有小伙伴对MySQL索引还有问题或者是不清楚的地方可以评论或者私信我

                        

             

有一些学习资料给到大家,需要的点击MySQL免费领取

                       


分类:
阅读
标签: