MySQL高级——索引 (内附索引高频面试题)

目录

 

一、索引介绍以及使用

1.1 什么是索引?

1.2 索引的分类?

1.3 索引的创建、查询、删除 的方式?

 

二、高频面试题(通过面试题更能了解索引)

2.1 什么是索引?

2.2 MySQL索引是什么样的数据结构?

2.3 MySQL中的常用的存储引擎 MyISAM与InnoDB的区别?

2.4 如何选择存储引擎 MyISAM与InnoDB?

2.5 MyISAM与InnoDB实现BTree索引的方式不同在哪?

2.6 为什么要使用索引?(索引的优点?)

2.7 索引是怎么提高查询速度的?

2.8 既然索引这么多好处,为什么不给表中的每一列都创建索引?(索引的缺点?)

2.9 使用索引有哪些注意事项?(使用索引时,SQL语句怎么优化?)

2.10 什么是最左前缀原则?

2.11 什么是覆盖索引?


 

一、索引介绍以及使用

1.1 什么是索引?

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。

从官方定义中,我们可以知道索引本质是一种数据结构。

详细一点的解释就是:
数据库除了数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构通过某种方式指向数据。如此一来,就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是 索引。

简单一点的解释就是:
索引是排好序的可快速查找的数据结构。

形象一点的解释就是:
索引就好像是新华字典的查找目录,可以帮助你快速查找到字典中的指定内容。
索引也像是图书馆的书籍查找目录,可以帮你快速查询到你要的书在哪。

1.2 索引的分类?

  1. 单值索引:一个索引只包含一个列,一个表可以有多个单列索引。
  2. 复合索引:一个索引包含多个列。
  3. 唯一索引:索引列的值必须是唯一的,但允许有多个空值。

 

1.3 索引的创建、查询、删除 的方式?

索引的创建有两种方法:CREATE 和 ALTER 。

/*ALTER*/
ALTER TABLE tableName ADD [UNIQUE] INDEX idx_name1 (column_name1);
/*CREATE*/
CREATE [UNIQUE] INDEX idx_name1 on tableName(colum_name1);

查询索引:

/*查询索引*/
SHOW INDEX FROM tableNmae

删除索引:

/*删除索引*/
DROP INDEX [indexName] ON tableName;

下面示范一下

用create创建索引:

用alter创建单值索引:

创建多值索引:

用alter创建多值索引也类似,这里不演示了。

这里顺便说一下命名规范

非唯一索引的命名(单值或多值):idx_字段名   (多值:idx_字段名1_字段名2_字段名3.....)

唯一索引命名:uni_字段名

 

二、高频面试题(通过面试题更能了解索引)

2.1 什么是索引?

索引(Index)是帮助MySQL高效获取数据的数据结构。
(具体的可看上面的索引介绍。)

2.2 MySQL索引是什么样的数据结构?

MySQL索引主要使用的两种数据结构:

  1. 哈希索引
    哈希索引底层的数据结构就是哈希表,查询很快。
    所以在数据库的大部分需求为单条记录查询的时候,可以选择哈希索引。
    而其他大部分场景,一般选则BTree索引。
     
  2. BTree索引
    MySQL的BTree索引用的是BTree中的B+树。
    不过对于不同的存储引擎,实现的方式不同。
    比如主要的存储引擎MyISAM和InnoDB中的实现方法就不同。
    (提到了存储引擎MyISAM和InnoDB之后,可能会有下面三个“追命连击”)

2.3 MySQL中的常用的存储引擎 MyISAM与InnoDB的区别?

  1. InnoDB支持事务,而MyISAM不支持。
  2. InnoDB支持外键,而MyISAM不支持。
  3. InnoDB不支持全文索引,而MyISAM支持。
  4. InnoDB使用的是行级锁,MyISAM使用的是表级锁。
  5. InnoDB count(*) 时需要全表扫描,消耗资源多且速度慢;
    而MyISAM 是用一个变量保存了整个表的行数,count(*)时只需读取该变量即可,消耗资源很少且速度很快。

2.4 如何选择存储引擎 MyISAM与InnoDB?

  1. InnoDB适合写密集的的表,MyISAM适合读密集的表。
  2. 数据库做主从分离时,一般选择MyISAM作为主库的存储引擎,InnoDB作为从库的存储引擎。
  3. 需要支持事务,且需要支持较高并发时,选择InnoDB。
    不需要支持事务时,选择MyISAM。

2.5 MyISAM与InnoDB实现BTree索引的方式不同在哪?

  1.  MyISAM: B+树叶子节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+树搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。
     
  2. InnoDB: 其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+树组织的一个索引结构,树的叶子节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”,而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,在走一遍主索引。 因此,在设计表的时候,不建议使用过长的字段作为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂。

2.6 为什么要使用索引?(索引的优点?)

  1. 可以大幅加快 数据的检索速度(因为大幅减少了检索的数据量),  这也是创建索引的最主要的原因。
    (就像使用新华字典找一个字,如果没有目录,我们就需要一页一页的来查找;而如果有目录,我们只需查询一下目录就可以快速找到。) 

  2. 通过索引列对数据进行排序,降低了数据排序的成本。使服务器避免了排序与创建临时表。

  3. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性

  4. 将随机IO变为了顺序IO

  5. 可以加速表和表之间的连接,在实现数据的参考完整性方面特别有意义。

2.7 索引是怎么提高查询速度的?

  1. 索引将无序的数据进行了排序,我们查询时只需查询索引即可快速查询到所需数据(就像使用字典的目录来查找)。

2.8 既然索引这么多好处,为什么不给表中的每一列都创建索引?(索引的缺点?)

因为索引也有一些缺点:

  1. 实际上索引也是一张表,该表保存了主键与索引,并指向实体表的记录,所以索引也要占用空间
  2. 索引虽然大幅提升了查询速度,但是会降低更新表的速度。因为在对表中数据进行增删改时,索引也要动态维护。这就会降低数据的维护速度(也就是降低更新表的速度)。
  3. 创建索引和维护索引也会耗费时间,并且数据量越大,耗费的时间越多。

2.9 使用索引有哪些注意事项?(使用索引时,SQL语句怎么优化?)

  1. 要遵循最左前缀原则。
  2. 少在索引列上进行操作。
  3. 范围条件之后的索引会失效。
  4. 使用模糊查询时,%写在最右边,不然后面的索引会失效。
  5. 不等,空值,or ,这几个会使索引失效,要少用。
  6. VARCHAR类型的数据,一定要记得写引号,不然会使索引失效。
  7. 覆盖索引查询很快 ( 覆盖索引不要写 select * )。
  8. 单行访问很慢。
    不要为了从存储中读取一个数据块而去获取其中的一行。
    最好读取的数据块中包含尽可能多的所需要的行。

2.10 什么是最左前缀原则?

使用多值索引时,要按索引字段的顺序使用。

例如:
user表里的属性字段a、b、c 有一个多值索引 (a,b,c) idx_a_b_c 。

select * from user where a=1 and b=1 and c=1 ; //a,b,c可以使用索引
select * from user where a=1 ; // a可以使用索引
select * from user where a=1 and c=1; // a可以使用索引,c不能使用索引,因为前面的b断了。
select * from user where b=1 and c=1; // b,c 都不能使用索引,因为前面的a断了。

#注意
select * from user where c=1 and b=1 and a=1;
//这个a,c,c都能使用索引,因为虽然顺序不对,但是MySQL会帮我们调整顺序。

2.11 什么是覆盖索引?

覆盖索引,就是select的数据列只用从索引中就能够取得,不必读取数据行,MySQL可以利用索引返回select列表中的字段,而不用根据索引再去读取数据文件。也就是说 查询列要被所建立的索引覆盖。

比如:user表有字段id、name、age、address,我们用字段name和age 建立索引 idx_name_age 。
那么查询时,
如果我们SQL是
select name,age from user  where username='猿兄' and age = 99; 
这就是覆盖索引,要查的 name 和 age 都在索引里,
所以我们根据索引查询数据的时候,就可以直接从索引中获得,而不用再去读取数据库。

而如果SQL是
select name,address from user  where username='猿兄' and age = 99; 
这样的话,因为address不在索引里
当我们根据索引查询数据时,还要再去读取一下数据库才能获取address这个数据。
这样就比较慢。

发布了92 篇原创文章 · 获赞 33 · 访问量 5955

猜你喜欢

转载自blog.csdn.net/love_MyLY/article/details/104121575