创建索引原则
- 尽量选择区分度高的列作为索引,区分度的公式是
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 in
、not exist
、!=
- like, 百分号在前:
where col like "%xxxx"
- 单独引用复合索引里非第一位置的索引列
- 不要将空的变量值直接与比较运算符(符号)比较, 应使用 IS NULL 或 IS NOT NULL 进行比较
@todo 待整理: 导致索引失效的可能情况