来源
教学视频来源:黑马程序员 MySQL数据库入门到精通,从mysql安装到mysql高级、mysql优化全囊括
简介
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特点查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高价查找算法,这种数据结构就是索引。
使用索引可以提高查询速度,比如查找年龄是45的用户
注: 上述二叉树索引结构只是一个示意图,并不是真正的索引结构
优点:
-
提高查询性能:索引可以大大减少查询数据的扫描量,从而提高查询效率。通过使用索引,数据库可以更快地定位和检索所需的数据。
-
加速排序操作:如果查询中包含排序操作,索引可以加快排序的速度。通过使用索引,数据库可以快速定位并返回排序结果。
-
提高数据唯一性:可以在索引中定义唯一性约束,确保表中的数据不重复。
-
支持快速聚合操作:对于包含聚合函数的查询,索引可以提供更快的结果计算和返回。
缺点:
-
占用存储空间:索引需要占用额外的存储空间。随着索引的增加,数据库的存储需求也会增加。
-
增加写操作的开销:当对表进行插入、更新和删除操作时,索引也需要进行相应的更新。因此,索引会增加写操作的开销,对性能产生一定的影响。
-
维护索引需要时间:当表中的数据发生变化时,索引也需要相应地进行维护。这会导致写操作的延迟增加。
-
不适用于所有情况:对于某些小型表或者数据分布不均匀的表,使用索引可能不会带来明显的性能提升,甚至可能降低查询性能。
索引结构
MySQL中的索引是在存储引擎层实现的,不同的存储引擎有不同的结构,主要包含一下几种:
InnoDB存储引擎使用的是B+tree索引结构。原因是:
- 相对于二叉树,层级更少,搜索效率更高
- 对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低。
- 相对于Hash索引,B+tree支持范围匹配及排序操作
索引分类
在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:
聚集索引选取规则:
- 如果存在主键,主键索引就是聚集索引
- 如果不存在主键,将使用第一个唯一索引作为聚集索引
- 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引
索引语法
创建索引
dart
create [unique | fulltext] index index_name on table_name(index_col_name,...)
查看索引
dart
show index from table_name
删除索引
dart
drop index index_name on table_name
通常主键为主键索引,如果使用主键来查询数据会比使用其他字段查询的速度会更快。如果需要使用其他字段来进行查询时,当数据量过大时,可以通过创建索引来提示查询效率。
注: 当数据量过大时,构建索引也会花费一些时间
索引使用
查看使用了哪些索引
我们在执行查询语句时,可以在查询语句前面加上explain
关键字,来查看该查询语句使用了哪些索引
使用原则
最左前缀法则
如果索引了多列(联合索引,由多个列组成的索引),要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。
如果查询条件没有按照索引的最左前缀顺序提供,MySQL将无法充分利用索引,可能会导致全表扫描或部分索引扫描,从而影响查询性能。
如果跳过某一列,索引将部分失效(后面的字段索引失效)
例如,如果您创建了一个复合索引 (col1, col2, col3):
- 只使用col1列,索引生效
- 使用col1,col2 索引生效
- 全部都使用(字段的顺序不一定是col123,也可以是col321),索引生效
- 使用col1、3,只有col1的索引生效
范围查询
联合索引中,出现范围查询(大于、小于),范围查询右侧列的索引失效。大于等于这种的会生效
例如下面这条sql,后面的 and sex = '男'
是不会生效
dart
select * from student where profession = '软件工程' and age > 23 and sex = '男'
索引列运算
不要在索引列上进行运算操作,索引将失效。
字符串
字符串类型字段使用时,不加引号,索引将失效。这里指的是字符串类型的数字
模糊查询
如果是头部模糊匹配,索引失效,比如:
dart
explain select * from student where name like '%四'
or连接的条件
用or
分割的条件,如果or
前的条件中有列索引,而后面的列中没有索引,那么涉及的索引都不会被用到
数据分布影响
在执行查询时,MySQL会进行评估,如果使用索引比全表扫描更慢,则不适用索引
前缀索引
当字段类型为字符串时,有时候需要索引很长的字符串,这会让索引变得很大,查询时浪费大量的磁盘IO,影响查询效率。
此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。
语法
dart
// index_name:索引名称 table_name:表名 column:列 n:指定几个字符
create index index_name on table_name(column(n))
前缀长度
可以根据索引的选择性来决定,而选择性是指不重复的索引值和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。
计算方式示例
dart
select count(distinct name) / count(*) from student;
判断应该截取几个字符
dart
select count(distinct substring(name,1,10)) / count(*) from student;
通过修改截取的字符串长度来计算几个字符比较合适后就可以创建前缀索引了,比如:create index index_name_3 on student(name(3))
单例索引与联合索引的选择问题
- 单列索引:一个索引只包含单个列
- 联合索引:一个索引包含了多个列
在业务场景中,如果存在多个查询条件,考虑针对查询字段建立索引时,建议建立联合索引,而非单例索引。
索引设计原则
- 针对数据量较大(几十万数据),且查询比较频繁的表建立索引
- 针对于常作为查询条件、拍下、分组操作的字段建立索引
- 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高
- 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立索引
- 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率
- 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改查的效率
- 如果索引列不能存储null值,请在创建表时使用not null约束它。当优化器知道每列是否包含null值时,它可以更好的确定哪个索引更有效的用于查询。