Featured image of post MySql索引

MySql索引

2892 words

为啥MySQL InnoDB 选择B+tree作为索引的数据结构?

  • B+Tree vs B Tree:
    • B+Tree只有叶子节点存储数据,而B Tree索引和数据都存,这样会导致在相同的条件下,B Tree的一个数据节点能够存储的索引减少,导致B Tree的深度会较长,从而造成IO时间较长,性能较差。
    • B+Tree 的叶子节点是用双链表进行连接的,进行范围查询较为方便。
  • B+Tree vs 二叉树
    • 对于二叉树来说,有可能会退化成时间复杂度为O(n)的(对于插入操作一直插入大的或一直小的)。
    • 对于二叉树来说,仅仅能存储一个索引,会导致层数增加,从而导致IO时间较长。
  • B+Tree vs Hash
    • 对于Hash来说,Hash不能进行范围查询

啥时候使用索引?

  • 字段有限制的,适合当索引。
  • 经常用于WHERE查询条件的字段。
  • 经常用ORDER BY 和GROUP BY的字段。
  • 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间, 避免回表,提高查询效率。

啥时候不使用索引?

  • 字段中存在大量重复数据,不需要创建索引。
  • WHERE条件,GROUP BY,ORDER BY 里用不到的字段。
  • 经常需要更新的表,查询频率较小的表。
  • 字段中存在大量重复数据,不需要创建索引。
  • 表数据较少的不用创建索引,数据较少时全表查询效率已经很高了,如果加入索引会增加存储压力。

啥时候索引会失效?

  • 不符合最左匹配原则的。
  • 模糊查询用%x和%x%的。
  • 将索引加入计算的表达式中。
  • 将索引加入函数中。
  • 在WHERE从句中的输入为字符串,但是字段的属性为INT类型。
  • WHERE 子句中的 OR

在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。(解决方案:可以采让全部都是)

有啥优化索引的方法?

  • 前缀索引优化

使用前缀索引是为了减小索引字段大小,可以增加一个索引页中存储的索引值,有效提高索引的查询速度。在一些大字符串的字段作为索引时,使用前缀索引可以帮助我们减小索引项的大小。

  • 覆盖索引优化

我们可以建立一个联合索引,即「分组ID、名称、价格」作为一个联合索引。如果索引中存在这些数据,查询将不会再次检索主键索引,从而避免回表。

  • 主键索引最好是自增的

如果我们使用自增主键,那么每次插入的新数据就会按顺序添加到当前索引节点的位置,不需要移动已有的数据,当页面写满,就会自动开辟一个新页面。因为每次插入一条新记录,都是追加操作,不需要重新移动数据,因此这种插入数据的方法效率非常高。

如果我们使用非自增主键,由于每次插入主键的索引值都是随机的,因此每次插入新的数据时,就可能会插入到现有数据页中间的某个位置,这将不得不移动其它数据来满足新数据的插入,甚至需要从一个页面复制数据到另外一个页面,我们通常将这种情况称为页分裂。页分裂还有可能会造成大量的内存碎片,导致索引结构不紧凑,从而影响查询效率。

  • 防止索引失效

如果索引失效的话,那么这个索引将会失效,这个索引将会不起作用。

  • 索引最好设置为NOT NULL

第一原因:索引列存在 NULL 就会导致优化器在做索引选择的时候更加复杂,更加难以优化,因为可为 NULL 的列会使索引、索引统计和值比较都更复杂,比如进行索引统计时,count 会省略值为NULL 的行。

第二个原因:NULL 值是一个没意义的值,但是它会占用物理空间,所以会带来的存储空间的问题,因为 InnoDB 存储记录的时候,如果表中存在允许为 NULL 的字段,那么行格式 (opens new window)中至少会用 1 字节空间存储 NULL 值列表。

啥是索引?

索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足 特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构 上实现高级查找算法,这种数据结构就是索引。(可以类比书籍的目录,简单来说就是用于快速检索数据的数据结构)

不同存储引擎支持的索引结构

索引 InnoDB MyISAM Memory
B+tree索引 支持 支持 支持
Hash 索引 不支持 不支持 支持
R-tree 索引 不支持 支持 不支持
Full-text 5.6版本之后支持 支持 不支持

索引分类

  • 按照数据结构分类
索引结构 描述
B+Tree索引 最常见的索引类型,大部分引擎都支持 B+ 树索引
Hash索引 底层数据结构是用哈希表实现的, 只有精确匹配索引列的查询才有效, 不支持范围查询
R-tree (空间索引) 空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少
Full-text(全文索引) 是一种通过建立倒排索引,快速匹配文档的方式。类似于Lucene,Solr,ES
  • 按照物理存储分类
分类 含义 特点
聚集索引(ClusteredIndex) 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据 必须有,而且只有一个
二级索引(SecondaryIndex) 将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键 可以存在多个
  • 按照字段特性分类
分类 含义 特点 关键字
主键索引 针对于表中主键创建的索引 默认自动创建, 只能有一个 PRIMARY
唯一索引 避免同一个表中某数据列中的值重复 可以有多个 UNIQUE
常规索引 快速定位特定数据 可以有多个
全文索引 全文索引查找的是文本中的关键词,而不是比较索引中的值 可以有多个 FULLTEXT
  • 按照字段个数分类

分为单列索引和联合索引

索引设计原则

  • 1 针对于数据量较大,且查询比较频繁的表建立索引。
  • 2 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索 引。
  • 3 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
  • 4 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
  • 5 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间, 避免回表,提高查询效率。
  • 6 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增 删改的效率。
  • 7 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。

MySQL单表不要超过2000W行,靠谱吗?

  • 这个不是靠谱的,因为MySQL的行数与这个数据的大小有关系,对于不同的数据大小自然有不同的评判标准,我们应该根据B+树不能超过3层和具体的业务等等来进行判断。

哪种count性能最好?

count(*) = count(1) > count(主键字段) > count(普通字段)

  • count(1)、 count(*)、 count(主键字段)在执行的时候,如果表里存在二级索引,优化器就会选择二级索引进行扫描。
  • count(1) == count(*)的原因是 InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.
  • count(1) 和count(*) 比count(主键字段)高效的原因是前两者不用判断是否为null
  • 不要使用 count(字段) 来统计记录个数,因为它的效率是最差的,会采用全表扫描的方式来统计。如果你非要统计表中该字段不为 NULL 的记录个数,建议给这个字段建立一个二级索引。

为啥InnoDB要通过遍历的方式来计数?

  • 因为InnoDBInnoDB 存储引擎是支持事务的,同一个时刻的多个查询,由于多版本并发控制(MVCC)的原因,InnoDB 表“应该返回多少行”也是不确定的

如何优化count(*)?

  • 可以采用近似值。 浏览器的搜索就是采用这个的。
  • 采用额外表保存计数值。
使用 Hugo 构建
主题 StackJimmy 设计