当无数的开发者努力构筑一座支撑千万级别数据传输的大桥,人们只有不断向前探索更快的数据获取方式这一条路可走。

设计网站指引(这样设计索引超人都没你快)(1)

MySQL

对高效检索数据的探索

大家可能都对海盗题材的影视、小说等多有了解。

设计网站指引(这样设计索引超人都没你快)(2)

藏宝图

故事中,总会有一个引得众多主角们争相夺取的藏宝图。这些藏宝图记载着宝藏存储的位置,如果将宝藏比作一个巨大的资源库,那么这张藏宝图其实可以算得上是一个古老的索引

索引是人类便于查找大量数据而建立的一种清单结构,它记载了真实数据存储的位置信息,比如一本新华字典。

设计网站指引(这样设计索引超人都没你快)(3)

新华字典

新华字典最前面的目录就是一种典型的索引结构。当我们要查询某个文字,我们会快速翻看目录部分,找到对应的页码,然后再去翻看字典的正文,寻找我们真正查询的内容。

不光是新华字典,任何工具书、文学读物、教材,甚至是说明书等都有对应的索引结构——目录

可以说,索引相伴于数据而生

然而,如今的信息爆炸时代,通信领域的飞速发展,3G、4G、5G......如何能够在如此之快的信道基建之上提高数据检索的速度,是信息技术行业最核心的课题之一。

从山寨到电商头牌

那个时候,新千年伊始,中华大地出现了一个改变国人消费行为的网站——淘宝网

设计网站指引(这样设计索引超人都没你快)(4)

淘宝

如今的淘宝网,“电商头牌”的地位无人撼动,其双十一创下的千万级别的业绩不仅仅是对业务架构健壮性的考验,同时其中一个重要的因素,就是可以支撑起千万级别点击搜索的“千万级别索引”。

设计网站指引(这样设计索引超人都没你快)(5)

海量的数据迫使淘宝的技术团队不得不摸索设计更加高效健壮的索引结构。这不仅需要考虑数据库的库表设计,业务场景,同时还需要考虑服务器的压力,CPU效率等等各方面因素。

在电商发展迅猛的这段时期,数据库的索引设计,一度成为高级软件开发工程师必须具备的重要技能之一。

MySQL 的索引设计方法

为了努力成为一名优秀的软件开发者,了解和使用索引只是基础,掌握其内部结构和设计方法才是核心技能。

在《高性能MySQL》一书中,清晰地阐述了索引的内部结构。不过令我十分感兴趣的是评判索引优劣的三星标准:

1、索引将相关记录放到一起可以获得一星。

2、索引中的数据顺序可以满足排序需求则获得二星。

3、索引中的列包含了查询中需要的全部列可获得三星。

设计网站指引(这样设计索引超人都没你快)(6)

高效索引

1、把相关数据放在一起

在 MySQL 的InnoDB引擎中,有一个叫做“聚簇索引”的概念。

聚簇索引,简单地说,就是将数据和主键放在一起而组成的数据结构

这样的索引符合前面提到的一星标准吗?答案是肯定的!

设计网站指引(这样设计索引超人都没你快)(7)

InnoDB的聚簇索引

这也是为什么我们小白经常听到:“用id直接查数据比较快”的原因,因为InnoDB表的主键和数据直接存放在一起呀!

2、索引顺序直接排序

在某些排序查询中,有时候可以利用索引数据组织结构。

在MySQL中,大多数场景下的索引结构是一棵 B 树。这种树结构,可以按照一定次序排序索引列,比如以数据表的主键为例,它就是一种从小到大排序的树结构。

设计网站指引(这样设计索引超人都没你快)(8)

B 树

那么既然索引已经按照一定的顺序排列的,那我们在给查询出来的数据进行排序的时候,为什么不直接利用索引排序呢?

顺着这个思路,在索引设计的时候,就要充分考虑某些常见业务场景的排序问题。比如按照国家、地区、年龄排序。

如果查询可以利用索引进行排序,那么在 EXPLAIN 执行计划的 type 列会出现 “index” 的字样。

但是注意,只有当索引列的顺序和 ORDER BY 子句的顺序完全一致,并且所有列的排序方向(DESC或ASC)都一样时,MySQL才能够使用索引来对结果进行排序。如果查询需要关联多张表,则只有当 ORDER BY 子句引用的字段全部为第一张表时,才能使用索引进行排序

3、索引包含查询所需的全部列

索引最高级的用法就是,索引包含了全部查询的列。

这种使用索引的方法叫做——覆盖索引。

我们知道,索引是一种数据结构,既然是数据结构,那么索引本身就具备了一定的存储能力。覆盖索引,其本质就是把索引当做了一种存储特定查询数据的存储结构,不需要我们回表获取额外的信息,就可以快速完成查询。

下面就是一个简单的索引覆盖查询的例子:

CREATE TABLE `teacher` ( `teacher_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '教师id', ... PRIMARY KEY (`teacher_id`), KEY `idx_name_salary_age` (`teacher_name`,`salary`,`age`) ) ENGINE=InnoDB

EXPLAIN SELECT t.`teacher_name`,t.`age`, t.`salary` FROM teacher t WHERE t.`salary` > 4000

可以看到,在查询中,我们利用了索引 idx_name_salary_age 的三个索引列,没有任何额外的数据获取。

如果使用了覆盖索引,在 EXPLAIN 的Extra 中会出现“Using index” 的字样。

在索引的设计中,能够考虑到覆盖索引的开发者通常是深刻理解业务场景的,但是,毕竟索引不可能存储所有的数据,因此虽然覆盖索引是性能优化的利器,但是并不可滥用。

对性能优化的目的是解决大部分常用场景的性能问题,如果我们的索引设计能够满足这样的需求,那么就可以算得上三星好索引!

索引之道任重,却不远

设计网站指引(这样设计索引超人都没你快)(9)

索引设计的理念有很多,除了上面介绍的三星标准相关的:聚簇、排序、覆盖,还有一些诸如压缩、哈希、前缀等各种设计技巧。

虽然这些内容看似很多,其实认真钻研不会需要太久的时间。

对于优秀的软件开发者来说,掌握高效索引的设计理念是一件稳赚不赔的买卖。不仅可以成为自己的永久竞争力,同时也不需要花太久的时间,只需要集中的一到两个月,就可以参悟索引设计之道。

可谓任重但道不远啊!相信有志向的小伙伴一定可以快速掌握这门技术能力的。

作为一名一线开发工作者,长期奔跑于漫长的职业开发马拉松上,真心希望能够帮助每一位渴望提升技术的程序员,做技术之路上的照明灯。

关注你想看的,去做你想做的!

往期精彩

《MySQL索引是如何让世界变得更快的》

《不会MySQL性能优化?21条最佳经验让HR对你刮目相看》

《对话式情景剖析,String被final修饰的真正原因!一篇足矣》

《注释有多重要,看了这一篇你还不重新思考一下吗?》

《那些还在B站发弹幕问“有人在吗”的人,求求你们别再犯二了》

,