之前,我以为我对MySQL索引了解很多。相信很多人对MySQL的索引都不陌生。索引(Index)是一种帮助MySQL高效获取数据的数据结构。因为索引是MySQL中比较重要的一个知识点,相信很多人都有一定的了解,尤其是在面试中频繁出现的时候。发帖者认为自己对MySQL索引的知识比较多,由于最近在找工作面试,所以一个人复习了很多索引方面的知识。但是,我在图森仍然很伤心。直到被阿里的面试官虐了才知道,我对索引的知识只有小学生水平。下面是我总结的一次阿里面试中的指标相关问题和知识点。1.指数概念和指数模型我们是怎么谈指数的?我提到我们的业务量比较大,每天大概有几百万的新数据产生,所以我们就有了下面的对话:Q:你们每天都做这个吗?大量的数据存储在关系型数据库中吗?A:是的,我们在线使用MySQL数据库。Q:每天几百万条数据,一个月几千万条。您是否优化了查询?A:我们在数据库里建立了一些索引(我很后悔当时说的那些话)这里可以看到,阿里的面试官不会像一些公司一样,带着题库一个一个地问问题,而是从什么开始面试官在面试过程中做了一些内容。Q:那你能说说什么是指数吗?A:(这道题对我来说肯定很难)索引其实就是一种数据结构,可以帮助我们快速检索数据库中的数据。Q:那么索引用的是哪种数据结构呢?A:(这道题我也背过)常见的MySQL主要有两种结构:Hash索引和B+Tree索引。我们使用InnoDB引擎,默认是B+树。这里我耍了个花样,特意说索引跟存储引擎有关。希望面试官能问我一些关于存储引擎的问题。不过面试官并没有被我带走……Q:既然你提到了InnoDB使用的B+树索引模型,你知道为什么要使用B+树吗?与Hash索引相比有什么优缺点?A:(突然觉得这道题有点难,不过还是根据自己的知识储备回答了一些简单的题)因为Hash索引的底层是哈希表,而哈希表是一种存储数据的结构在key-value中,这么多条数据的存储关系中根本没有顺序关系。所以无法直接通过索引进行范围查询,需要全表扫描。因此,哈希索引只适用于等价查询场景。B+树是多路平衡查询树,所以它的节点自然是有序的(左子节点小于父节点,父节点小于右子节点),所以不需要做范围查询的全表扫描。Q:除了上面的范围查询,你能说出一些其他的区别吗?A:(这个问题回答不好,后来google了一下)B+Tree索引和Hash索引的区别?哈希索引适用于等值查询,但不能进行范围查询。哈希索引不能使用索引来完成排序。哈希索引不支持多列联合索引的最左匹配规则。如果有大量重复的key值,hash索引的效率会很低,因为存在hash碰撞问题2.聚簇索引,覆盖索引Q:刚才我们讲了B+Tree,你知道什么可以存储在B+树的叶子节点中?A:InnoDB的B+树可能存储整行数据,也可能是主键的值。问:两者有什么区别?A:(他问我叶节点的时候,我猜他可能会问我聚簇索引和非聚簇索引)在InnoDB中,索引B+树存储整行数据的叶节点是主键索引,也称为聚簇索引。B+树的叶子节点存储主键值的索引是非主键索引,也称为非聚集索引。Q:那么,聚簇索引和非聚簇索引在查询数据的时候有什么区别吗?A:聚集索引查询会更快吗?问:为什么?A:因为主键索引树的叶子节点直接就是我们要查询的整行数据。非主键索引的叶子节点就是主键的值。找到主键的值后,需要通过主键的值再进行一次查询。Q:刚才您提到主键索引查询只会查一次,而非主键索引需要多次回表查询。(后来才知道这个过程叫returntable)是不是所有情况都是这样?非主键索引会被多次查询吗?A:(啊,这个问题我回答不好,后来自己查了资料才知道通过覆盖索引只能查询一次)覆盖索引?覆盖索引(coveringindex)是指查询语句的执行只能从索引中获取,而无需从数据表中读取。也可以说达到了索引覆盖。当一条查询语句满足覆盖索引条件时,MySQL只需要使用索引返回查询所需的数据,避免了需要查找索引再返回表的操作,减少了I/O,提高了效率。例如表covering_index_sample中有一个公共索引idx_key1_key2(key1,key2)。当我们通过SQL语句:selectkey2fromcovering_index_samplewherekey1='keytest';时,我们可以通过覆盖索引进行查询,而无需返回表。3.联合索引,最左前缀匹配Q:不知道也没关系。我想问一下,你在创建索引时会考虑哪些因素?A:我们一般查询的概率很高,往往会把索引设置为where条件的一个字段。Q:你用过联合索引吗?A:是的,我们已经为一些表创建了联合索引。Q:创建联合索引时,如何选择联合索引中多个字段的顺序?A:我们把识别度最高的字段放在最前面。问:你为什么这样做?A:(这个问题让我有点摸不着头脑,有点心慌)如果是这样的话,攻击率可能会更高。..问:你知道最左边的前缀匹配吗?A:(突然想起面试官要问这个,怪自己刚才没有想到这个。)哦哦哦。这就是你刚才问的。在创建多列索引时,我们根据业务需要将使用频率最高的列放在最左边的where子句中,因为MySQL索引查询在检索数据时遵循最左前缀匹配原则,即最左在前,从联合索引的最左边开始匹配。所以当我们创建一个联合索引的时候,比如(key1,key2,key3),就相当于创建了三个索引(key1),(key1,key2)和(key1,key2,key3),这就是最左匹配原则。虽然一开始有点懵,没想到匹配最左边的前缀,但是面试官还是给了我指导。非常友好。4.索引下推,查询优化Q:您在线使用的是哪个版本的MySQL?A:我们的MySQL是5.7Q:你知道MySQL5.6对索引做了哪些优化吗?A:抱歉,我还没有了解到这件事。(后来查了一下,还有一个比较重要的:IndexConditionPushdownOptimization)IndexConditionPushdown(索引下推)MySQL5.6引入了索引下推优化,默认开启。使用SEToptimizer_switch='index_condition_pushdown=off';你可以关闭它。官方文档给出的例子和解释如下:在people表(zipcode,lastname,firstname)构成一个索引SELECT*FROMpeopleWHEREzipcode='95054'ANDlastnameLIKE'%etrunia%'ANDaddressLIKE'%MainStreet%';如果不使用索引下推技术,MySQL会通过zipcode='95054'从存储引擎中查询相应的数据返回给MySQL服务器,然后MySQL服务器会根据lastnameLIKE'%etrunia%'和addressLIKE'%MainStreet%'判断数据是否满足条件。如果使用索引下推技术,MYSQL会先返回匹配zipcode='95054'的索引,然后根据lastnameLIKE'%etrunia%'addressLIKE'%MainStreet%'判断索引是否满足条件。如果满足条件,则根据索引定位到相应的数据,如果不满足,则直接拒绝。通过索引下推优化,在like条件查询的情况下,可以减少返回表的数量。Q:你创建了那么多索引,有没有生效,或者你统计过你的SQL语句有没有使用索引查询?A:这个没有统计,除非遇到慢SQLTroubleshoot。Q:检查的时候,有什么方法可以知道是否有索引查询?A:可以通过explain查看SQL语句的执行计划,通过执行计划分析索引使用情况。Q:那什么情况下会出现明明创建了索引,执行的时候却没有传递索引呢?A:(我大概记得是跟优化器有关,不过这个问题一直没有很好的回答)查询优化器?一条SQL语句的查询,可以有不同的执行计划。至于最后选择哪个计划,需要通过优化器来选择,选择执行成本最低的计划。在一条单表查询语句真正执行之前,MySQL的查询优化器会找出执行该语句的所有可能方案,经过比较找出性价比高的方案。这种具有成本效益的解决方案就是所谓的执行计划。优化过程大致如下:1.根据搜索条件找到所有可能的索引2.计算全表扫描的代价3.计算使用不同索引执行查询的代价4.比较各种执行方案的代价,找到outthecost*来自**的Q:哦,暂时先问这么多关于索引的问题吧。您的在线数据的事务隔离级别是多少?A:(关于事务隔离级别的问题后面就不展开了)我感觉是因为我的回答不够好??。如果我能回答这些指标性的问题,他还会问更多的问题,我怕会被虐得更惨。5.总结&感悟以上是面试中关于指标部分知识的问题以及我整理的答案。我感觉这次面试我能回答大概70%的关于索引的知识,但是我能正确回答的内容只有50%左右,大概是50%。看来我对索引还不够了解。通过这次面试,我发现像阿里这样的大公司,还是比较注重底层知识的。以前觉得索引最重要的就是问问Hash和B+的区别。没想到***问的是查询优化器。.***,不管你能不能通过这次面试,我都非常感谢能有这样一个机会让自己看到自己的不足。通过这次面试,我也收获了很多东西。快点!
