likes
comments
collection
share

「MySQL」比较冷门的Index Merge

作者站长头像
站长
· 阅读数 30

分享一个冷门的sql优化小技巧,主要看好多讲索引type都不带上这个。这里讲一下基本概念以及优化分享。

瞎聊

最近翻了翻八股,大部分聊explain的时候会忽略index merge,这个在我日常调优的时候经常会遇到,对于概念只能说有一个大概的了解,这次做一个总结归纳哈。 「MySQL」比较冷门的Index Merge

type类型介绍

  • system:仅一行数据
  • const:表中最多存在一个匹配行。常用于primary key或者唯一索引
  • eq_ref:对于前面表的行组合,从该表中读取一行。
  • ref :对于前面表的行组合,在此表的索引中可以匹配到多行。
  • eq_or_null:和null类似,增加了null值的比较。
  • index_merge:索引合并优化。使用了两个以上的索引,最后取交集或者并集
  • unique_subquery:替代了eq_ref的一些子查询unique_subquery
  • index_subquery:类似unique_subquery,区别是唯一索引和非唯一索引的区别
  • range: 索引范围查询,常见于使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()或者like等运算符的查询中。
  • index: 该联接类型与 ALL 相同,除了只有索引树被扫描。
  • all: 全表扫描 整体的一个执行情况排序,一般来说,得保证查询至少达到range级别,最好能达到ref。 system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

index merge介绍

官网链接:dev.mysql.com/doc/refman/…

「MySQL」比较冷门的Index Merge

索引合并访问方法检索具有多个 range扫描的行并将其结果合并为一个。此访问方法仅合并来自单个表的索引扫描,而不合并跨多个表的扫描。合并可以生成其基础扫描的并集、交集或交集的并集。

这个怎么说呢你看到英文应该就能猜的大概,mysql是会走多个索引的,然后将多个索引的结果进行合并

一般是三种类型:

  • Using intersect(...) :交集

    key_part1 = const1 AND key_part2 = const2 ... AND key_partN = constN
    
  • Using union(...) : 并集

    key_part1 = const1 OR key_part2 = const2 ... OR key_partN = constN
    
  • Using sort_union(...) :有序并集

    SELECT * FROM tbl_name
    WHERE key_col1 < 10 OR key_col2 < 20;
    

这三个索引优化都是可以控制开关的可以通过SELECT @@optimizer_switch进行查看。

大致原理介绍

参考文献:mysql.taobao.org/monthly/202…

由于实在看不懂c了,这里就偷懒截图了。大致流程我简述一下, 计算走每一个索引的代价,如果条件符合还会计算多个索引的代价计算。 然后从上面计算出一个最优的方式去执行。

原文:

  1. 计算 table scan cost
  2. 分配 PARAM 结构,初始化相关字段
  3. 对表上每个可用的 key,加入 param.key[] 数组,其中每个 key_part,对应一个 KEY_PART 对象(param.key_parts数组)
  4. 考虑是否能使用覆盖索引,首先调用find_shortest_key()函数,选择KEY::key_length最小的可用索引。接着计算索引扫描代价,比较是否比 table scan 代价更低。
  5. 考虑各种 range scan
  6. 调用get_mm_tree()函数,根据 ON/WHERE 携带的条件,构建 range tree。
  7. get_best_group_min_max() 尝试为 group by 构建 QUICK_GROUP_MIN_MAX_SELECT。
  8. get_best_skip_scan(),对于单表非 group by,尝试构建 skip scan
  9. get_key_scans_params()函数对 PARAM.key[] 中的 key,依次调用 check_quick_select,计算得到的行数 found_records 和代价 cost。选择更低代价的 range,创建 TRP_RANGE 结构。
  10. get_best_ror_intersect
  11. get_best_disjunct_quick,计算 index merge union 的代价
  12. make_quick(),找到最优的 best_trp 后,创建 QUICK_SELECT_I 对应的子类对象,设置给JOIN_TAB

简单实践

「MySQL」比较冷门的Index Merge

「MySQL」比较冷门的Index Merge trace不重要,主要是想说明一下,索引合并是要计算代价的,计算代价也是需要成本的。这个说法是来源《高性能MySQL》 「MySQL」比较冷门的Index Merge

但是,一般来说,建立区分度高的联合索引肯定好。但是有2个点也是需要考虑,

  1. 索引也是需要空间的
  2. 你在这个表创立的初期,很难预测以后产品会将哪个作为重点,比如在下,压错过几次。所以我加索引相对而言比较保守,是先加单个字段的索引,后期根据慢查询统计建立适当的索引。

在此期间,会经常看到索引合并的例子,但是这个也是经常被忽视的一个点,特此整理一下

参考文档

转载自:https://juejin.cn/post/7396580330704486434
评论
请登录