mysql性能优化之创建高性能索引

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33661044/article/details/79422432

索引对性能的优化十分重要,是对查询优化最有效的手段。
一、索引的类型
索引是在存储引擎层而不是服务层实现的。不同存储引擎的索引工作方式不一样。
1、B-Tree索引
它使用的是B-Tree数据结构来存储数据。b-tree索引能够加快访问数据的速度,因为存储引擎不在需要进行全表扫描来获取需要的数据,取而代之的是从索引的根节点开始进行搜索。根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下查找。通过比较节点页的值和要查找的值就可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。
索引对多个值进行排序的依据是create table语句中定义索引时列的顺序。

  • 全值匹配。和索引中的所有列进行匹配
  • 匹配最左前缀。只使用索引的第一列
  • 匹配列前缀。只匹配某一列的值开头部分。
  • 匹配范围值。
  • 精确匹配某一列并范围匹配另一列
  • 只访问索引的查询
    1.1 B-Tree索引的限制
  • 如果不是按照索引的最左列开始查找,则无法使用索引。
  • 不能跳过索引中的列。
  • 如果查询有某个列的范围查询,则其右边所有列都无法使用索引优化查找。
    到这里我们发现,索引列的顺序是多么重要,这些限制和索引列的顺序有关。在优化性能的时候可能需要使用相同的列但顺序不同的索引来满足不同类型的查询需求。
    二、哈希索引
    哈希索引(hash index)基于哈希表实现,只有精确匹配索引所有列的查询才能有效。对每一行索引列都会计算一个HashCode。哈希码是一个较小的值,哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。
    哈希索引也有它 的限制
  • 哈希索引只包含哈希值和行指针,而不存储字段值。
  • 哈希索引数据并不按照索引值顺序存储,所以无法用于排序
  • 哈希索引也不支持部分索引列匹配查找,因为哈希索引始终使用索引列的全部内容计算哈希值。
  • 哈希索引只支持等值比较查询,包括=、IN()、<=>也不支持任何范围查询。
  • 访问哈希索引的数据非常快,除非有很多哈希冲突(不同的索引列值却有相同的哈希值)。当出现哈希冲突时候,存储引擎必须遍历链表中所有的行指针,逐行进行比较,直到找到所有符合条件的行。
  • 如果哈希冲突很多的话,一些索引维护操作的代价也会很高。
    三、索引的优点
    索引可以让服务器快速的定位到表的指定位置。但这并不是索引唯一的作用。最常见的b-tree索引,按照顺序存储数据,所以mysql可以用来做order by和 group by操作。
    索引大大减少了服务器需要扫描的数据量。索引可以帮助服务器避免顺序和临时表。索引可以将随机I/O变为顺序I/O。
    对于非常小的表,大部分情况下简单的全表扫描更高效。对于中到大型的表,索引就非常有效。但对于特大型的表,建立和使用索引的代价将随之而来。
    四、高性能索引策略
  • 独立的列。
    是指索引列不能是表达式的一部分,也不是函数的参数。例如:select xxx from xxx where id + 1 = 5;mysql无法自动解析这个方程,我们应该简化where条件的习惯,始终将索引列单独放在比较符号的一侧。
  • 前缀索引和索引选择性。
    有时候需要索引很长的字符列,这会让索引变得大且慢,我们要选择足够长的前缀以保证较高的选择性,同时又不能太长(以便节约空间)前缀应该足够长,以使得前缀索引的选择性接近于索引整个列。找到合适的前缀长度后通过alter table test add key(city(7));创建索引
  • 多列索引
    在多个列上建立独立的单列索引并不能提高mysql的查询特性。mysql5.0和更新版本引入了一种叫做索引合并的策略,一定程度上可以使用表上的多个单列索引来定位指定的行。可以通过参数optimizer_switch来关闭索引合并功能。也可以使用ignore index提示让优化器忽略某些索引。
  • 选择合适的索引列顺序
    当不考虑排序和分组时,将选择性最高的列放到索引最前列。这时候索引只是优化where条件的查找。
  • 聚簇索引
    聚簇索引不是一种索引类型,而是一种数据存储方式。Innodb的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。它的数据行实际上在同一个结构中保存了B-Tree索引和数据行。
  • 覆盖索引
    通常大家会根据where条件来创建合适的索引,不过这只是索引优化的一个方面。如果一个索引包含或者说覆盖所有要查询的字段的值,我们就称之为覆盖索引。
    五、总结
    在选择索引和编写利用这些索引的查询时,有三个原则始终牢记
    • 单行访问是很慢的
      可以使用索引创建位置引用提升效率
    • 按顺序访问范围数据是很快的
      1、顺序I/O不需要多次磁盘寻道,2、若果按照顺序索引,那么就不需要额外的排序操作,并且group by查询也无需再做排序和行按组进行聚合计算
    • 索引覆盖查询很快。
      如果一个索引包含了查询需要的所有列,那么存储引擎就不要回表查找行。这避免了大量的单行访问。

六、如何判断一个系统创建的索引是合理的?
按照响应时间来对查询进行分析。找到那些消耗时间最长的查询或者那些给服务器带来最大压力的查询,然后检查这些查询的schema 、sql和索引结构,判断是否扫描了太多的行。

七、应该选择那些列作为索引?
- select update delete 语句的where从句中的列
- 包含在order by group by distincr中的字段联合索引
- 多表join的关联列
索引列的顺序又应该是怎么样的呢
索引按照从左向右的顺序执行
- 区分度最高的列放在联合索引的最左侧
- 尽量把字段长度小的列放在联合索引的最左侧
- 使用最频繁的列放在联合索引的左侧
避免建立冗余索引和重复索引比如:
index(a、b、c)、index(a、b)、index(a)
primary key(id)、index(id)、unique index(id);
对于频繁查询优先考虑使用覆盖索引(包含所有查询字段的索引)可以避免innodb表进行索引的二次查找、可以把随机I/O变为顺序IO加快查询效率
尽量避免使用外键
不建议使用外键约束、但一定在表与表之间的关联键上建立索引、外键会影响父表和子表的写操作从而降低性能

猜你喜欢

转载自blog.csdn.net/qq_33661044/article/details/79422432