mysql索引详解

索引

简介

  1. 索引是对数据库表中一列或多列的值进行排序的一种数据结构。其可以快速访问数据库表中的特定信息。

  2. 索引一般以文件形式存在磁盘中(也可以存储在内存中),存储索引的原理即以空间换时间,数据库在未添加索引时是对表进行全局扫描,建立索引后,会将索引的key放在某种数据结构上(B树,B+树)

索引的优缺点

优点:

  1. 建立索引的列可以保证行的唯一性,生成唯一的rowid
  2. 建立索引可以有效的缩短数据的检索时间
  3. 建立索引可以加快表与表之间的连接
  4. 为用来排序或者是分组的字段添加索引可以加快分组和排序顺序

缺点

  1. 创建索引和维护索引需要时间成本
  2. 创建索引和维护索引需要空间成本,每一条索引都要占据数据库的物理存储空间,数据量越大,占用空间越多
  3. 会降低表的增删改的效率,因为每次增删改索引需要进行动态维护索引文件

索引的分类和创建

基本索引类型

  1. 普通单列索引:仅加速查询
  2. 复合多列索引
  3. 唯一索引:加速查询+列值唯一(可以有null)
  4. 主键索引:加速查询+列值唯一(不可以有null)
  5. 全文索引:对文本的内容进行分词,进行搜索

索引创建的基本语句

create table table_name [col_name data type] [unique|fulltext] [index|key][index_name](col_name[length])[asc|desc]

使用alter table 来创建索引
alter table table_name add index index_name(列1,列2...)创建普通索引
alter table table_name add unique index_name(列1,列2...)创建唯一索引
alter table table_name add primary key (列1,列2...)创建主键

使用create来创建索引
create index index_name on table_name(列1,列2...)创建普通索引
create unique index index_name on table_name(列1,列2...)创建唯一索引
删除索引
drop index index_name on table_name
使用索引需要注意的问题
  1. 不要索引列上使用相关的函数或者计算
  2. like以%开头则不会使用索引
  3. 最左前缀原则
  4. not in <>会导致索引失效
  5. 隐式转换会导致索引失效

哪些情况不应该使用索引

  1. 数据唯一性差的字段,不要使用索引,因为如果一个字段的重复次数太多,先遍历该字段的值,再去取数据行,和直接使用全表扫描区别不大
  2. 频繁更新的字段不要使用索引,频繁更新会导致索引也会频繁更新,降低写的效率
  3. 字段如果不在where语句中出现,则不要添加索引
  4. 数据量少的表不用添加索引
  5. 如果有范围查询,则最好将范围查询放在最后面

数据库建立索引常用规则

  1. 表的主键,外键必须有索引
  2. 数据量超过300的表应该有索引
  3. 经常与其他表进行连接的表,在连接字段上应该建立索引
  4. 经常出现在where子句中的字段应该建立索引
  5. 索引应该建立在选择性高的字段上
  6. 索引应该建立在小字段上
  7. 频繁进行数据操作的表,不要建立太多的索引
  8. 删除无用的索引,避免对执行计划造成负面影响

索引的访问

即索引的访问规则,什么时候索引的访问可能会失效等。

  1. 全值匹配:索引中所有列进行匹配(即和复合索引中的所有列进行匹配)
  2. 匹配最左前缀:
    • 对于复合索引而言,在使用复合索引时,必须用到索引的第一个字段
    • 对于索引的第一个字段,用like时,左边必须是固定值,通配符只能出现在左边,即最左边不能是%
    • 如果在索引第一个字段前加了函数,则索引会被抑制
    • 最左前缀原则使得查询时,不需要在查询语句中写出全部的索引列,但是必须满足最左原则
  3. 匹配范围值:匹配范围值也要遵循最左原则
  4. 不能跳过索引中的列:即在利用索引进行查找时,例如复合索引为三个索引列,则不能只使用AC而跳过B,这样会导致索引失效
  5. 如果查询中某个索引列为范围查询,则该列后的索引列将不会生效(IN不算范围查询

索引的数据结构与索引的建立技巧(需要注意聚簇索引等是索引的建立技巧)

在MySQL中索引的数据结构一般为B+树和哈希索引

无论是innodb还是myisam都是采用的B+树作为索引的数据结构

mysql的索引又分为聚簇索引和非聚簇索引(二级索引)

B+树索引和哈希索引的比较

mysql中只有memory引擎才支持哈希索引,该索引在哈希表中只包括哈希值和行指针。即先将键计算为哈希值,然后在表中存放哈希值和行指针,哈希索引采用拉链法来解决哈希冲突

  1. 哈希索引适合做等值查询,但是不能进行范围查询
  2. 哈希索引不能利用索引完成排序
  3. 哈希索引不支持多列联合索引的最左匹配规则(即哈希索引不支持部分索引列的匹配查找)
  4. 如果有大量重复键值存在的情况下,哈希索引的效率会很低,因为存在哈希碰撞的问题。
聚簇索引

所谓聚簇索引是指主键索引文件和数据文件为同一份文件,聚簇索引主要用在innodb存储引擎,该索引实现方式中,B+树的叶子节点上的data是数据本身,key为主键,如果是一般索引那么data中为对应的主键

优点:

  1. 将相关数据保存在一起,索引的顺序其实实际数据保存的顺序。
  2. 数据访问快,将索引和数据保存在同一个文件中(B+树)因此其获取数据的速度比普通索引的速度快
  3. 使用覆盖索引扫描的查询可以直接使用页节点中的主键

缺点:

  1. 聚簇索引插入速度严重依赖于插入的顺序,如果是按照主键的顺序进行插入则速度很快,但是如果是随机插入则更新聚簇索引列的代价很高,因为会innodb会将每个被更新的行移动到新的位置。
  2. 同时基于聚簇索引的表在插入新行,或者主键被更新导致需要移动行时,可能面临页分裂的问题,
  3. 所谓页分裂是指如果将新的行插入一个已经满了的页面,则存储引擎会将该页分裂为两个页面。页分裂操作导致表占用更多的磁盘空间。

对于聚簇索引,最好采用自增的主键值,应尽量使用连续增长的值(自增),而不要是随机值

非聚簇索引

非聚簇索引分为两种,一种是innodb的,其和聚簇索引的区别在于,其在data域中存放的是对应的主键值

所以在对二级索引(非主键索引)进行查询时,在找到对应的叶子节点后,通过查找到对应的主键再去聚簇索引中查找相应的数据行。(使用主键值作为数据的好处在于,如果数据行发生移动,不用更新相应的行指针

myisam的非聚簇索引

myisam的数据分布实际就是数据的插入顺序,即在Myisam中数据的插入顺序就是数据的排列顺序,myisam的索引也是采用B+树的结构,不过其页中存放的是指向数据表中改行的指针

myisam的主键索引与非主键索引结构相同,只不过主键索引索引值唯一且不为空。

总之,聚簇索引相对非聚簇索引而言,聚簇索引查找数据不用回行查找,其查找效率更高,但是主键选取最好和数据无关,而使得数据的插入是顺序插入,最好避免随机的聚簇索引

覆盖索引

sql如果只需要通过索引就可以返回查询所需要的数据,而不必回表查询查询数据,则称此时该索引为覆盖索引,索引是高效找到行的一个方法,当能够通过检索索引就可以读取想要的数据时,那就不需要再用到数据表中读取行了。(如果一个索引包含或者覆盖了满足查询语句中字段与条件的数据就叫做覆盖索引),说白了,就是需要查询的数据就在索引文件中

不是所有类型的索引都可以成为覆盖索引的,覆盖索引必须要存储索引的列,而哈希索引、空间索引、全文索引等不存储索引的列

mysql查询优化器在执行查询前会判断,当前是否有一个索引能进行覆盖,假设索引覆盖了where条件中的字段,但是不是整个查询涉及的字段,也会回表查询。

可以采用覆盖索引进行索引进行优化的几种情况:

  1. 无where条件的查询优化,如果经常查找某个列,可以将此列作为索引
  2. 有时可能查询包括了所有的数据列,则可以通过延迟关联的方式来使用覆盖索引p173

覆盖索引与二级索引

如果要查询的就是表的主键,则当使用二级索引时,在查找到表的主键就停止,不用再去聚簇索引查找

压缩索引和前缀索引

myisam中使用前缀压缩来减少索引的大小,从而可以将更多的索引放入内存中。

如果索引列的长度很大,也可以通过只使用该索引列开始的部分字符来作为索引列,这样可以大大节约索引空间,提高索引的效率。

前缀索引的建立原则,即使用多长的前缀?

  1. 索引的选择性:(不重复的索引值即基数)/数据表中的记录总数,(不重复的索引值指所有索引列中不重复列的个数)
  2. 完整列的选择性:(distinct 列名,其实就是该列的基数)/记录总数
  3. 尽量选择索引选择性约等于完整列选择性的前缀(即分别计算各个前缀的索引选择性),但是还是要综合索引列的分布情况
多列索引的顺序问题

在一个多列的B/B+树索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列。。。

顺序选择的经验法则:将选择性最高的列放在索引的最前列。(即索引的基数要高,即这一个列中不重复的元素多)

上面这种方法是一种通用方法,但是也要考虑到经常查询的条件/排序/分组等情况,如果经常用排序/分组,或者经常用某个列来进行查询,则应该将该列放在前面

使用索引来做排序

由于索引本身就是排序的,索引可以用索引来做排序,即将索引列放在order by后面即可。同样最好能够让索引去覆盖待查询的列,这样也可以避免查询一次索引就得回表查询一次记录。

即让索引即用于排序,也用于查询,从而避免回表查询

当多列索引用于排序时,需要注意的是也要遵守最左前缀原则(用于排序的所有索引字段的排序方向必须相同),即order by后面的列要遵循最左前缀原则,但是也有一个特例,就是例如索引(A,B,C),那么如果A在where中被指定为一个常量,则order by后可以从B开始(但是不能从C开始)(注意区分和group by的区别)

重复索引和冗余索引
  1. 重复索引:在相同的列上按照相同的顺序创建相同的索引(索引类型不同不算,例如一个是普通索引,一个是全局索引)
  2. 冗余索引:如果创建了索引(A,B),再创建索引(A)就是冗余索引,(只针对B/B+树索引而言)因为对于(A,B)而言,A可以作为前缀索引来使用,冗余索引一般都发生在为表添加新索引的时候,
    • 一般而言最好扩展已有的索引,例如,已经有了A索引,那么如果想要(A,B)索引,不是添加一个新索引,而是将A扩展成(A,B),而不是添加新的索引。
    • 但是需要注意,扩展索引也不能让索引太长,因为这样会导致索引的长度过大,占用更多空间,影响查询性能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值