MySQL-03a-索引-高效使用索引

创建索引原则

  • 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录
  • 限制索引的长度, 尤其是 FULLTEXT索引, 比如只在VARCHAR字段的前20字节做索引;
  • 字符类型和数字类型作为索引的性能差别,肯定是用数字类型索引更好。
  • 用字符串做索引扫描是否会有性能损耗?两者的主要差别就在于,字符类型有字符集的概念,每次从存储端到展现端之间都有一个字符集编码的过程。而这一过程主要消耗的就是CPU资源;对于In-memory的操作来说,这是一个不可忽视的消耗。如果要固化到具体测试结果,我们这边的经验数据是20%,具体值还是和环境和数据有关系。此外,latin1 和 UTF8 之间也有10%左右的性能差别。
  • 时间加索引的话,性能上 TIMESTAMP > DATETIME

高效使用索引

  • 使用覆盖索引(对于非主键的查询条件), 符合覆盖索引的情况:
    • 如果用到了联合索引, 联合索引用到的列, 恰好也是要查询的列( select colA, 且已经在colA创建了联合索引)
    • 这种也是走覆盖索引: select 主键 where 非主键列=X

查询尽量使用到索引,避免使用全表扫描

MySQL中能够使用索引的典型场景:

  • 匹配全值(Match the full value),Where条件中所有列都有索引, 且使用的是= 或者IN。
  • 匹配值的范围查询(Match a range of values),Where条件中所有列都有索引, 且使用的是范围条件。例 where id > 10 and id < 25
  • 使用了联合索引, 且匹配最左前缀(Match a left most prefix),仅仅使用联合索引中的最左边列进行查找,比如在 col1+col2+col3 字段上的联合索引能够被包含col1、(col1+col2)、(col1+col2+col3)的等值查询利用到,可是不能够被col2、(col2+col3)的等值查询利用到;
  • 匹配列前缀(Match a column prefix),仅仅使用索引中的第一列,并且只包含索引第一列的开头一部分进行查找。select title from film_text where title like 'AFRICAN%';
  • 如果列名是索引,那么使用 column_name is null 可以使用索引

注意不同类型的索引对性能有影响

  • 对于频繁写入的情景, 普通索引比唯一索引更快 // why ?
  • 对于查询的情况, 非聚簇索引比聚簇索引多一次回表, 如何避免非聚簇索引的回表?

避免会索引失效的操作

  • 在索引上使用函数: select * from trade where month(data) = 7
  • 索引的类型转换: 字段定义类型varchar, 但是查询语句用 where id > 7, 相当于给id索引加上了CAST函数(隐式类型转换总是低精度类型→高精度类型)
  • 以下where 都不会用到索引: <>not innot exist!=
  • like, 百分号在前: where col like "%xxxx"
  • 单独引用复合索引里非第一位置的索引列
  • 不要将空的变量值直接与比较运算符(符号)比较, 应使用 IS NULL 或 IS NOT NULL 进行比较

@todo 待整理: 导致索引失效的可能情况