一. 索引是什么?
索引(key or “键”)是储存引擎用于快速找到记录的一种数据结构。这是索引的基本的功能,除此之外索引还有一些其他的属性。
举一个简单的例子:一本书里面有若干页,一页对应一个页码。如果想寻找这本书里关于作者信息的一些内容,如果没有索引的帮助,那么只能从页码为1的页,一行一行的去检索是不是你想看到的有关作者信息的内容,一直到最后一页的最后一行,这就是常说的全表扫描。但是如果我们使用了索引,那么我们如果想去找到作者信息相关的内容的话,只需要先去查询索引,由索引指向的页码跳转到相应的地方,这样大大提高了查询的效率。数据库里的索引也一样。(当然这取决于数据量的大小,如果是一个数据很小的表,那么可能使用索引的查询效率还不如全表查询来的快。在mysql里我们不需要担心这样的问题,mysql的查询优化器会在执行查询时先计算各种查询方式的代价,会自动的选择代价最低的方式进行查询)
二. 如果使用了orm,是否需要关心索引?
需要。orm是对象关系映射工具,是一个可以生产符合逻辑,合法的查询(大多数时候),但是索引的高性能的实现是复杂且方方面面受影响的。区区orm很难兼顾到各个方面。
三. 索引的类型
mysql里,索引的实现是在储存引擎层,而不是服务层。所以不同的储存引擎即使索引类型相同,具体实现也不完全相同。
1. B Tree
储存引擎以不同的方式使用b tree索引,性能不同各有优劣。
1.Myisam: 前缀压缩技术,使得索引更小,通过数据的物理地址引用到被索引的行。
2.Innodb: 使用原格式数据进行存储,通过主键引用到被索引的行。
但是特别的指出Myisam是只支持表锁的,用在不需要高并发的场景上使用。
b tree一般意味着数据都是顺序存储的。所以适合查找范围数据。索引对多个值进行排序的依据是create table 语句中定义索引时序的顺序。
b tree之所以可以增加查找速度是因为,储存引擎不需要在进行全表扫描来获取需要的数据,取而代之的是从索引的根结点向下直到找到对应的叶子结点,要么记录不存在。
b tree的高度与数据量的大小息息相关。
键前缀查找只适用于最左前缀的查找
索引匹配对下面的查询有效
1.全值匹配
索引中的所有列进行匹配。
2.匹配最左原则
index(a,b,c) 只能匹配到 a,b,c | a,b | a。
3.匹配列前缀
只匹配列前缀,比如 1以J开头的a字段。like "J%" 但是"%K"不能匹配到索引。
4.匹配范围值
比如name为allen和name为barrymore之间的人。
5.精准匹配某一列并范围匹配另外一列
name="alex" and address like "J%"
索引覆盖
通常可以支持只通过访问的索引的查询,即查询只需要访问索引,而不需要通过数据行。通过联合索引的形式实现。
了解了上面的信息我们知道了:索引的顺序十分重要
2.哈希索引
基于哈希表实现,储存引擎会对所有的索引列计算一个哈希码,不同键值计算出来的哈希码不一样。哈希吗储存在索引中勇士哈希表中保存指向每个数据行的指针。
只有Memory引擎显式支持哈希引擎,Memory引擎支持的是非唯一的索引。如果多个列的哈希值相同,那么索引会链表的形式存放多个记录到哈希条目中。因为索引自身只需要储存对应的哈希值,所以索引的结构十分紧凑。因为基于哈希表,所以对等值查询的速度十分的快。
但是哈希索引的缺点也十分明显:无法排序,不支持部分索引匹配查找(始终是全部的索引列的值通过计算得出去匹配的),只支持等值查询,如果有数量不少的键重复或者数据量大而造成的哈希冲突,会直接影响到数据库处理数据的能力。
innodb中的自适应哈希索引
innodb在使用时如果发现某些索引被使用的频繁时,他会在内存中基于b-tree索引之上再创建一个哈希索引,这样可以实现哈希索引的快速查找。这是一个内部的自动的无法控制的行为。不过如果有必要可以关闭这个功能。
在不同的储存引擎中实现隐式哈希索引(创建自定义哈希索引)
如果当前使用的储存引擎不支持哈希索引但是又想使用哈希索引,那么就可以模拟innodb的自适应哈希索引来创建一个。这样就可以享受到哈希索引的便利了。
实现思路:
在b树的基础上创建一个伪哈希索引,这跟真正的哈希索引不是一回事,还是使用b树进行查找,只是他使用的哈希值而不是键本身进行索引查找,只需要在where语句手动指定哈希函数即可。
举个例子:需要存储大量url,并且要求根据url查询对应的列,如果使用b树对url列进行索引那么这个内容就会很大,因为url本身是非常长的。正常情况下是这样进行查询
select id from url where url="http://www.baidu.com"
这时候我们可以通过实现一个自定义的哈希索引来优化这部分查询,删除原来的索引列,新增一个url_crc的列并增加它的索引,使用crc32函数做哈希,就可以通过下面的查询方式进行查询了
select id from url where url="http://www.baidu.com" and url_crc=CRC32("http://www.baidu.com")
这样做的性能相比上面的查询方式性能是非常高的,查询优化器会自动选择这个性能性很高的基于url_crc的索引列来完成查找,即使发生哈希冲突这样的查询也是非常效率的。
查询根据哈希值做快速的整数比较就能找到被索引的条目,再根据url列指定的信息就可以快速筛选出来,相比与完整的字符串筛选快了非常的多。
这样做的缺点就是需要维护哈希值,需要使用触发器,也可以通过手动维护。
3.空间数据索引(R树)
Myisam支持空间数据索引,可以存储地理数据,但是PostgreSql会做的更好。
4.全文索引
它是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接的比较索引中的值。全文索引更类似于搜索引擎做的事情,而不是简单的where匹配。关于全文索引我们会单独来讲。
5.聚集索引 辅助索引
聚集索引/主键索引/聚簇索引 叶子节点里存放的是行记录。
如果定义了主键,那么主键就是聚集索引。
如果没有主键,那么第一个非空唯一的列就为聚集索引
如果都没有那么innodb会自动创建一个隐藏列row_id为聚集索引。
辅助索引/二级索引/普通索引叶子结点存放的是键值。需要回表查询才能拿到行数据。辅助索引比聚集索引更慢,可以考虑创建联合索引来达到索引覆盖的效果,去掉回表查询的操作,直接在索引列中拿到数据。
四.索引的优点
1.索引大大减少了需要扫描的数据量。
2.索引可以帮助避免创建临时表和排序。
3.索引可以将随机i/o变为顺序i/o。
五.索引的缺点
1.更新表也要更新索引文件。
2.索引文件占用储存空间。
~Tip:
1.很多重复的内容没必要使用索引。
2.非常小的表没必要使用索引。
六. 如何调试索引
使用mysql 的explain进行查询sql的执行计划。
这篇文章我们了解了索引的基本相关知识,接下来我们会讲到如何实现高性能的索引。