来源
什么是索引
索引基础
- 基础:在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。一个索引对应一个B+树,所以一张表至少对应一个B+树
- 索引模型:hash表(适用于等值查询,比如 Memcached 及其他一些 NoSQL 引擎。拉链法解决同hash)、有序数组(适用于静态存储引擎)、搜索树
索引类型:
- 主键索引:叶子节点存储的是整行数据,在InnoDB中,也被称为聚簇索引(clustered index)
- 非主键索引:叶子节点存储的是主键,在InnoDb中,也被称为二级索引(secondary index)
- 区别:使用主键索引,只需要查询一棵B+树;普通索引则需要回表(先得到主键,然后去主键B+树查找数据)
索引维护
- 为了保证B+树的有序性,新插入数据可能在末尾也可能需要其他数据移动位置。而递增插入则可以很容易保证有序
- 索引因删除、页分裂等原因导致数据页有空洞
- 建议使用自增主键
- 由于自增主键(便于有序插入)及存储空间一般比业务字段少,因此一般使用自增id作为主键。
- 二级索引的叶子是主键,如果采用自增主键比唯一字段做主键占的存储空间较小
- 适合使用业务字段做主键:只有一个索引并且该索引必须是唯一索引,即KV场景
索引分类:
覆盖索引:当非主键索引的叶子节点的数据即是我们需要数据,那么就不需要回表,即这个索引 "覆盖" 了我们的需求
联合索引:两个或者多个字段来建立索引,这种索引符合覆盖索引规则
- 前缀原则:在搜索时不一定使用定义索引的全部字段,使用它的部分字段。使用联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符。例如 index(name,age) 可以使用name字段,也可以使用name+age(要用到age,name必须全,不能部分),或者使用部分name(like查询,"xxx%"),单独使用age没有索引
- 索引下推:在不满足最左原则时,但仍然用到了联合索引的字段。这时候先用符合最左前缀用索引去查找,然后在对剩下的联合索引的字段进行判断,然后在回表(没有索引下推则是回表之后再判断联合索引的字段)。即索引下推可以减少回表次数
字符串索引
前缀索引:使用字符串的前n个字符(根据最左原则,只能使用前面的,如果后面的才有区分度,可以倒着存储或者增加一个hash值存储)作为索引。如果使用前缀索引,用不上覆盖索引,需要回表(不确定是否满足)
引相关命令
- index (cloumn) 一般放在建表()的末尾
- 重建主键索引:不论是删除主键还是创建主键,都会将整个表重建。所以使用 alter table T engine=InnoDB;
- 重建普通索引流程:alter table T drop index k; alter table T add index(k);
索引的选择
唯一索引:索引列的值必须是唯一的,可以允许为空值。主键索引是唯一索引,但唯一索引不一定是主键索引
普通索引:没有任何限制条件的索引
查询区别?
对于普通索引来说,查找到第一个满足条件的记录后,还需要查找记录,直至碰到不满足的条件;
对于唯一索引来说,查找到第一个满足条件的记录后,就会停止继续检索
总结:两种查询虽然不一样,但性能微乎其微。因为引擎是按页读的,
更新(增改)区别?
change buffer
- 什么是?如果数据所在数据页在内存中,直接更新;否则在不影响数据一致性的前提下,InnoDB将这些更新操作缓存在change buffer,就不需要从磁盘读。change buffer可以持久化。即通过减少磁盘随机IO来提速
- merge:将 change buffer 中的操作执行到原数据页,得到最新结果的过程。发生在下次从磁盘加载该数据页到内存页时或者MySQL后台定时任务执行、正常关闭MySQL
- 只有普通索引才能使用change buffer
- change buffer 用的是 buffer pool 里的内存。通过参数
innodb_change_buffer_max_size来动态设置。值为50时表示其大小最多只能占用 buffer pool 的 50%。 - 适合写多读少(常见场景:账单、日志等)
更新的目标页在内存中
更新的目标页在磁盘中
change buffer 和 redo log
建议
- 如果大量数据插入慢,内存命中率低,考虑是否是因为唯一索引影响了
MySQL选错索引?
优化器选择索引会根据 扫描行数、是否回表、是否涉及临时表、是否排序等因素 基数:一个索引上不同值的数量。值越大,这个索引的区分度越好 重置表的统计信息(索引扫描行数等):analyze table tt
查看表上的索引信息:show index from tt;