【GreatSQL优化器-18】GROUP_INDEX_SKIP_SCAN

GreatSQL优化器之GROUP_INDEX_SKIP_SCAN

【GreatSQL优化器-18】GROUP_INDEX_SKIP_SCAN

一、GROUP_INDEX_SKIP_SCAN介绍

GreatSQL 优化器的分组索引跳跃扫描(GROUP Index Skip Scan) 是一种优化查询的技术,尤其在联合索引中用于减少扫描的无效行数。group by操作在没有合适的索引可用的时候,通常先扫描整个表提取数据并创建一个临时表,然后按照 group by 指定的列进行排序。在这个临时表里面,对于每一个group的数据行来说是连续在一起的。完成排序之后,就可以发现所有的groups,并可以执行聚集函数(aggregate function)。可以看到,在没有使用索引的时候,需要创建临时表和排序。在执行计划中通常可以看到“Using temporary; Using filesort”

GROUP索引跳跃扫描利用的是联合索引中非首列(非最左前缀)的索引列,来提高查询效率。例如,假如有个查询需求,需要查某个列的 distinct 值,或者 group by 之后的值 MIN()/MAX() 值,最简单的方式是扫描整个数据页,然后分组排序后,取 DISTINCT/MIN/MAX 值,但由于索引本身就有序并且完成了 group by 工作,如果可以直接借助于这个索引的有序性,那么扫描整个索引就可以避免二次排序的开销。这个功能支持带有聚合函数+GROUP BY或者聚合函数+DISTINCT或者DISTINCT的SQL使用。

这个功能类似于 INDEX_SKIP_SCAN,做一次对相同的 key 值进行 skip 动作,即可以跳过了索引上相同的段, 这样相比较与索引扫描而言,减少了很多的索引扫描,索引稀疏性越好,性能就会相对更好。

下面用一个简单的例子来说明GROUP_INDEX_SKIP_SCAN怎么应用在优化器。

CREATE TABLE t1(c1 INT, c2 INT, c3 INT, c4 INT);
CREATE UNIQUE INDEX i1_t1 ON t1(c1,c2,c3);
INSERT INTO t1 VALUES (1,1,1,1), (1,1,2,2), (1,3,3,3), (1,4,4,4), (1,5,5,5),
                      (2,1,1,1), (2,2,2,2), (2,3,3,3), (2,4,4,4), (2,5,5,5);
INSERT INTO t1 SELECT c1, c2, c3+5, c4+10  FROM t1;
INSERT INTO t1 SELECT c1, c2, c3+10, c4+20 FROM t1;
INSERT INTO t1 SELECT c1, c2, c3+20, c4+40 FROM t1;
INSERT INTO t1 SELECT c1, c2, c3+40, c4+80 FROM t1;
ANALYZE TABLE t1;

-- 下面的结果用到了group index skip scan,扫描方式是RANGE SCAN。
greatsql> explain SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | t1    | NULL       | range | i1_t1         | i1_t1 | 10      | NULL |    3 |   100.00 | Using index for group-by |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+--------------------------+

/* 运行过程:
1、先找到第一列的唯一值,得到结果为1和2
SELECT distinct c1 FROM t1; 
2、根据第一列的分组结果在分组内对c2执行范围扫描
SELECT c1, MIN(c2) FROM t1 WHERE c1 = 1;
SELECT c1, MIN(c2) FROM t1 WHERE c1 = 2;*/

-- 如果没有联合索引,那么这条sql内部要创建临时表用于数据的临时处理,扫描方式是全表扫描。可见用GROUP_INDEX_SKIP_SCAN方式执行groupby可以节省空间和开销,提升执行效率。

greatsql> DROP INDEX i1_t1 ON t1;
greatsql> explain SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra           |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  160 |   100.00 | Using temporary |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
二、get_best_group_min_max代码解释

group index skip scan是根据条件和聚合函数列以及distinct列,以及查找对应的联合索引进行判定能不能用group index skip scan,其中联合索引中聚合函数列或者distinct列之前的列为prefix列,即用来作为分组的依据的列,如果有多个除了第一列之外的范围列,那么选取遇到的第一个聚合函数列之前的列为前缀进行分组。

group index skip scan功能没有相关可以开启关闭的关键词,默认满足条件就可以使用,因此如果不想使用就要改变条件或者group by分组,只要不满足条件就不会使用联合索引。

int test_quick_select() {
  // 先判断GROUP_INDEX_SKIP_SCAN是否满足条件,不满足的话执行索引合并。
  AccessPath *group_path = get_best_group_min_max();
  // 不满足GROUP_INDEX_SKIP_SCAN执行索引合并,相关知识看之前知识介绍
}

AccessPath *get_best_group_min_max() {
  // 遍历表所有索引,找到联合索引
  for (uint cur_param_idx = 0; cur_param_idx < param->keys; ++cur_param_idx) {
    // 处理group by语句
    if (!join->group_list.empty()) {
      // 找到联合索引内的列字段相关mm tree
      if (tree) cur_tree = get_index_range_tree(cur_index, tree, param);
      // 该条件是否是等号条件或者IS NULL条件
          is_eq_range_pred = !(r
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值