高性能Mysql——创建高性能的索引

文章目录

  • 索引类型
  • 高性能的索引策略
      • 独立的列
      • 前缀索引和索引选择性
      • 多列索引
      • 覆盖索引
      • 使用索引扫描来做排序
      • 重复索引和冗余索引

索引类型

我们知道,索引的实现有很多种,在Mysql中,索引是在引擎中实现的,所以没有统一的索引类型标准。

B-Tree索引
关于这方面的索引原理,参考我之前写的文章伸缩自如的ElasticSearch——数据库索引原理。

哈希索引
基于哈希表的实现,只有精确匹配索引所有列的查询才有效。
哈希索引只适用于某些特定的场合,比如数据仓库应用中有一种经典的“星型”schema,需要关联很多查找表,哈希索引就非常适合表的需求。

其他一些索引我们不多做介绍了。

索引是最好的解决方案吗?
索引并不总是最好的解决方案,一般来说,对于非常小的表,大部分情况全表扫描更加有效。

高性能的索引策略

独立的列

我们通常会看到一些查询不当的使用索引,或者使得Mysql无法使用已有的索引。

如果查询中的列不是独立的,那么Mysql就不会使用索引。

什么是独立的列呢?独立的列是指,索引列不能是表达式的一部分,也不能是函数的参数。

比如下面这个查询无法使用user_id列的索引:

select user_id from user_info where user_id+1=5;

Mysql无法自动解析这个方程user_id+1=5,所以不会使用索引。
下面是另一种错误:

select date_col where to_days(date_col)<=10;

我们应当始终将索引列单独放在比较符号的一侧

前缀索引和索引选择性

有时候需要索引很长的字符列,这会让索引变得大且慢。一个策略是模拟哈希索引,但有时候这样做还不够,有个办法和之前学习的blobtext的排序很像:索引开始的部分字符。

这种前缀索引的方式,可以大大节约索引的空间,但是会降低索引选择性。索引选择性是指,不重复的索引和数据表总数目的比值,当然可以知道,1:1的时候,前缀索引的能完全区分字符列。
Mysql规定:对于blobtext还有很长的varchar类型,必须使用前缀索引。

为了找出最佳的前缀索引的长度,可以使用下面的方式计算索引选择性:
高性能Mysql——创建高性能的索引_第1张图片
left(city,3)是取的city这个列的前3个字符。我们可以看到,当前缀长度达到6的时候,再增加前缀长度,选择性提升的幅度已经很小了(越接近1越好)。

既然找到了最合适的前缀长度,下面掩饰如何创建前缀索引:

ALTER TABLE sakila.city_demo
ADD INDEX `city_index`(`city`(6));

多列索引

多列索引不是为每个列创建独立的索引,也不能按照错误的顺序创建多列索引。

先来看第一个问题,为什么不是为多个列创建独立的索引。
在多个列上创建独立的单索引,大部分情况下并不能提高Mysql的查询性能。
我们来看看一个例子。

select film_id,actor_id from film_actor
where actor_id=1 or film_id =1;

在Mysql老版本里,会使用全表扫描。
不过在Mysql5.0之后的版本中,引入了一种叫“索引合并”的策略,一定成都上可以使用表上的多个单索引。不过,这种情况更多的时候说明,表上的索引建立的很糟糕。

再来看另一个问题,索引列的顺序。正确的顺序依赖于使用该索引的查询是什么样的,并且需要考虑如何更好的满足排序和分组的需要。

在一个多列B-Tree索引中,索引列的顺序意味着索引首先按照左列进行排序,然后是第二列…
这样,索引才可以按照升序和降序进行扫描,以满足order bygroup bydistinct等要求。

由此可见索引的顺序至关重要。一个重要的经验法则是:将索引选择性最高的列放在最前列

高性能Mysql——创建高性能的索引_第2张图片

覆盖索引

这节的内容,之前也在伸缩自如的ElasticSearch——数据库索引原理中提到了,不做赘述。

覆盖查询都具有以下两个特点:

  • 查询中的所有字段都属于一个索引;
  • 查询所返回的所有字段也都属于同一索引内。

使用索引扫描来做排序

Mysql有两种方式生成有序的结果:

  • 排序操作
  • 按索引顺序扫描

只有当索引的列顺序与Order by子句的顺序完全一致时,并且排序的方向只能是一种(asc/desc)Mysql才能使用索引来做排序(最左前缀原则)
如果查询需要关联多张表,那么只有当Order by子句全是第一个表的列时,才能使用索引排序。
范围查询不会走索引查询(不是不会走索引),比如user_id in (x,x)以及 where id>1

最左前缀原则举例:比如 index(id,name,telephone),那么,order by id或者order by id,name都是满足最左前缀的,但是 order by name,telephone是不满足的。


重复索引和冗余索引

重复索引是指在相同的列上按照相同的顺序创建的相同类型的索引。应该避免这样创建重复索引,发现以后也应该立即移除。
有时会在不经意间创建了重复的索引,例如下面的代码:

CREATE TABLE test(
    ID INT NOT NULL PRIMARY KEY,
    A INT NOT NULL,
    B INT NOT NULL,
    UNIQUE(ID),
    INDEX(ID)
) ENGINE=InnoDB;

一个经验不足的用户可能是想创建一个主键,先加上唯一限制,然后再加上索引以供查询使用。事实上,MySQL的唯一限制和主键限制都是通过索引实现的,因此,上面的写法实际上在相同的列上创建了三个重复的索引。通常并没有理由这样做,除非是在同一列上创建不同类型的索引来满足不同的查询需求。

冗余索引和重复索引有一些不同。如果创建了索引(A,B),再创建索引(A)就是冗余索引,因为这只是前一个索引的前缀索引。因此索引(A,B)也可以当做索引(A)来使用(这种冗余只是对B-Tree索引来说的)。但是如果再创建索引(B,A),则不是冗余索引,索引(B)也不是,因为B不是索引(A,B)的最左前缀。另外,其他不同类型的索引(例如哈希索引或者全文索引)也不会是B-Tree索引的冗余索引,而无论覆盖的索引列是什么。
高性能Mysql——创建高性能的索引_第3张图片
上图两个例子,index(a)是index(a,b)的前缀索引,但是如果ab索引的值很大,就有必要建立一个index(a)加快查询。
而第二个index(a,id)则是完全没有必要的,因为index(a)会自动添加一个主键信息,相当于是index(a,id),但没有必要建立index(a,id)。

你可能感兴趣的:(数据库)