索引概念:
- 它是帮助mysql高效获取数据的数据结构;
- 索引以某种方式指向数据,通过索引可以快速获取数据;
- 没有索引时,查找,只能遍历,O(N)的时间复杂度 (避免全表扫描);
- 建立了索引,查找速度就显著提高,一般是B+树索引,且索引像目录,可提高查询效率;
- 通过索引对数据进行排序,降低排序成本;
索引劣势:
- 索引本身是一张表,保存了主键与索引字段,并指向实体类的记录,所以其也要存储空间,一般放到磁盘
- 插入数据时也要更新索引,从而影响写入数据的效率
索引结构:
- 不同的存储引擎,它的索引是不一样的
- BTREE索引是最常见的,也是InnoDB引擎所支持的索引
hash索引缺点:
- hash不能够进行范围查找;
- hash键值对的形式使得其键只能用一个,导致只能主键查询,不能用其它字段建立索引查询;
- hash冲突(不论邻接法还是开链法)都有一定线性时间的查找,不一定比B+树索引快;
对于B树和B+树的相关内容见:B树、B+树详解。
索引分类:
- 单值索引:(单列索引)按照单列,一个表可以有多个;
- 唯一索引:索引值必须唯一,允许有空值;
- 复合索引:多个列一起构成索引;
索引语法:
- 可以在创建表时创建,也可以之后创建
- mysql中主键有默认的索引 PRIMARY
- 索引类型默认是BTREE
- 可以create,也可以alter
索引的设计原则:
- 对于查询频次高,且数据量比较大的表
- 针对 经常在where子句中出现的字段
- 尽量使用唯一索引,区分度高,索引效率高
- 并不是多多益善,在insert,update和delete也要维护
- 使用短字段的索引,节省空间
- 针对复合(联合)索引,创建一个组合索引,其所有子集(从左边连续),都有索引(最左前缀);
索引是越多越好吗:
- 数据量小的表不需要索引,建立会增加额外的开销
- 数据变更需要维护索引,因此需要更多的维护成本
- 索引本身需要空间
select *
;or
分隔开的条件,如果 or
前的条件中的列有索引,而后边的列中没有索引,那么涉及的索引都不会被用到;只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快。
就是索引本身就已经包含了 所要查询的列。
则此时就不用进行回表,直接返回就好
哈希索引、空间索引等索引都把存储索引列的值,所以mysql只能使用B-TREE来做覆盖索引
这里Extra,如果using index,就是覆盖索引(见上文)
主键是不需要加入聚集索引的,因为它本身就在索引的data中
这也引出一个问题,非聚集索引不一定回表(如果是覆盖索引,或者是主键)
MySQL 的覆盖索引与回表 - 知乎 (zhihu.com)这个写的不错, 忘记了看这个
什么时候发生覆盖索引
什么时候需要用覆盖索引
对于联合索引,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。
这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的。
如果遇到范围查询时,就停止匹配了
最左匹配的成因:mysql按照联合索引的顺序,以第一个字段排序,然后再这个基础上再按第二个字段排序,所以对于第二个字段,实际它是局部有序,整体无序的,所以不能跳过第一个字段,直接从第二个字段开始进行,所以最左匹配原则
举个例子:
如User表的name和city加联合索引就是(name,city)
select * from user where name=xx and city=xx ; //可以命中索引 select * from user where name=xx ; // 可以命中索引 select * from user where city=xx ; // 无法命中索引
- 如(name,city )和(name )这两个索引就是冗余索引,能够命中后者的查询肯定是能够命中前者的