二、表设计原则之索引设计

313 阅读4分钟

索引设计

1.索引个数控制

建立合适的索引可以极大提升查询的性能,但一个表上的索引不是越多越好,索引多了严重影响增删改性能。在某些情况下,例如向临时表大批量导入数据,我们往往会先删除索引,等到数据导入完毕再创建必要的索引。

2.索引字段选择

(1)一般选择 where 与 order by 条件中出现的字段作为索引字段的候选;

(2)字段必须是选择性(或称离散度、区分度)较高的字段,即该字段的取值范围较大,一个反例:性别就不适合作为索引字段。在选择性很小的字段上建立索引,查询时用不上反过来却影响了更新性能。注意,复合索引的选择性取决于所有字段组合后的值,而不是看每一个单独的字段;

(3)如果一个查询的 where、order by 与 select 相关字段都在索引中,即索引全覆盖,该查询性能将会很高,因为所需数据都在索引中,无需访问表数据;

注:索引全覆盖的查询,explain 时 Extra 列会出现 Using index。

3.索引字段排序

按照先 whereorder by 最后 select 字段的顺序排列索引字段,如果有多个 order by 字段,必须严格按照它
们的先后顺序排列。如果一个复合索引的所有字段都在 where 条件中且都是精确匹配(=),那么这个复合索引内的字段
顺序是无关紧要的,因为数据库查询引擎将所有字段组合后的值作为一个整体查找索引,而不是分级查找

4.最左匹配原则

假设我们为表 T 的 a、b、c 三个字段创建了一个复合索引 IDX(a, b, c),那么下列 SQL 与索引 IDX 的关系如下:

序号SQL可利用IDX
1select d from T where a=x and b=y and c=z是 (a, b, c)
2select d from T where a=x and b=y是 (a, b)
3select d from T where a=x是 (a)
4select d from T where b=y and c=z
5select d from T where b=y
6select d from T where a=x and c=z是 (a)
7select d from T where c=z
8select d from T where a=x order by b, c是 (a, b, c)
9select d from T where a=x order by b是 (a, b)
10select d from T where a=x order by c, b是 (a)
11select d from T where a=x order by c是 (a)
12select a, b, c from T where a=x and b=y全覆盖 (a, b, c)
13select a, b, c from T where a=x order by b全覆盖 (a, b, c)
14select d from T where a=x and b>y and c=z是 (a, b)
15select d from T where a=x and b>y order by c是 (a, b)
从索引的第一个字段开始检查 SQL 中的 where 与 order by 条件,如果相应条件不存在则终止检查。
我们看到第 12368910111213 句 SQL都可以匹配到 IDX 的全部或部分字段,
因此可利用索引,其中第 1213 句实现了索引全覆盖性能达到最佳;
而第 457 句 SQL 匹配 IDX 的第一个字段 a就失败了,无法利用索引。
只要在索引的某个字段上有范围查询(<,>,<=,>=,IN,OR,LIKE 等不是=的操作)条件,
最左匹配终止,后续的字段就无法用来过滤或排序了。
因此,第 1415句 SQL 只能利用到 IDX 的(a, b)两个字段。
可以利用索引的最左匹配原则减少索引数量。例如,我们定义了(a, b, c)索引,就没有必要再定义(a, b)与(a)索引。

5.索引与主键

InnoDB 存储引擎为每一个非主键索引在索引树的叶子节点上额外存储了主键,如果定义了索引 IDX(f),就等同于定义了一个复合索引 IDX(f, PK)。但是查询分析器并不知道这个“潜规则”,有些可以走索引的场合却走了排序。因此,强烈建议所有非主键索引都在末尾显式添加主键字段,这不会带来额外的成本,但对查询分析器更加友好。

注:唯一索引是个例外,绝不能将主键加到它的末尾。为什么?

6.唯一索引

如果索引字段数据具有唯一性(除 null 外),强烈建议将其定义为唯一索引,这样不仅可以提升查询性能,还能强制约束业务数据不重复。

  • [ 萱儿AXW ]