索引是个啥?
索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。
索引的一个主要目的就是加快检索表中数据,亦即能协助信息搜索者尽快的找到符合限制条件的记录ID的辅助数据结构。
在 MySQL 中,主要有四种类型的索引,分别为:B-Tree 索引,Hash 索引,Fulltext 索引和 RTree 索引,
索引的特点
索引能够提高查询的速度
为啥索引能够提高查询的速度呢?
平常我们说建立索引,其实就是把数据根据表中一列或者多列进行排序,然后制作了一个目录,就相当于我们查字典时,根据前面的拼音目录去检索,而不是一页一页的去找,这时间差距可不是一点半点,我们说建立索引就是编写字典时建立目录,而根据索引查新就是根据字母目录查询字。
比如执行下面的sql语句:
select * from student where name='吕布';
如果没有对name列建立索引,MySQL会先遍历双向链表,找到数据所在的页,由于不是根据主键查询,只能遍历所在页的单链表,一条一条的查找name是吕布的同学,毫无疑问,这样的操作时极慢的。
如果有了索引呢,只需要通过目录就可以很快地定位到对应的页上了
索引会降低删除,更新,插入的效率
前面说过,索引就相当于一个数据的目录,那这个目录不是凭空产生的呀,它是需要去维护的,这个维护的操作就是在进行删除,更新,插入数据的同时,还需要更新索引,这都是需要消耗资源的。
索引的底层数据结构是B+树,是一种矮矮胖胖的树,B+树是一颗平衡树,如果我们对这颗树增删改的话,那肯定会破坏它的原有结构。
要维持平衡树,就必须做额外的工作。正因为这些额外的工作开销,导致索引会降低增删改的速度。
最左匹配原则
最左匹配原则是针对联合索引来说的,最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。列的排列顺序决定了可命中索引的列数。
例如:比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,因为c字段是一个范围查询,它之后的字段会停止匹配。
哈希索引
Hash 索引在 MySQL 中使用的并不是很多,目前主要是 Memory 存储引擎使用,而且在 Memory 存储引擎中将 Hash 索引作为默认的索引类型。所谓 Hash 索引,实际上就是通过一定的 Hash 算法,将需要索引的键值进行 Hash 运算,然后将得到的 Hash 值存入一个 Hash 表中。然后每次需要检索的时候,都会将检索条件进行相同算法的 Hash 运算,然后再和 Hash 表中的 Hash 值进行比较并得出相应的信息。哈希索引虽然比b+索引高得多,但是它也有以下致命缺点:
- Hash 索引仅仅只能满足“=”,“IN”和“<=>”查询,不能使用范围查询;
由于 Hash 索引所比较的是进行 Hash 运算之后的 Hash 值,所以 Hash 索引只能用于等值的过滤,而不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证还和 Hash 运算之前完全一样。 - Hash 索引无法利用索引完成排序操作;
由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且** Hash 值的大小关系并不一定和 Hash 运算前的键值的完全一样**,所以数据库无法利用索引的数据来避免任何和排序运算; - Hash 索引不能利用部分索引键查询;
对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并之后再一起计算 Hash 值,而不是单独计算 Hash 值,所以当我们通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用到; - Hash 索引在任何时候都不能避免表扫描;
前面我们已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash 运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,而且由于存在不同索引键对应相同 Hash 值的可能,所以即使我们仅仅取满足某个 Hash 键值的数据的记录条数,都无法直接从Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较而得到相应的结果。 - Hash 索引遇到大量 Hash 值相等的情况后性能并不一定就会比 B-Tree 索引高;
对于选择性比较低的索引键,如果我们创建 Hash 索引,那么我们将会存在大量记录指针信息存与同一个 Hash 值相关连。即哈希碰撞,这样要定位某一条记录的时候就会非常的麻烦,可能会浪费非常多次表数据的访问,而造成整体性能的地下。
怎么合理利用索引?
- 较频繁的作为查询条件的字段应该创建索引
- 唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
唯一性太差的字段主要是指哪些呢?如状态字段,类型字段等等这些字段中存方的数据可能总共就是那么几个几十个值重复使用,每个值都会存在于成千上万或是更多的记录中。对于这类字段,我们完全没有必要创建单独的索引的 - 更新非常频繁的字段不适合创建索引
- 不会出现在 WHERE 子句中的字段不该创建索引