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),
group index skip scan是根据条件和聚合函数列以及distinct列,以及查找对应的联合索引进行判定能不能用group index skip scan,此中联合索引中聚合函数列或者distinct列之前的列为prefix列,即用来作为分组的依据的列,如果有多个除了第一列之外的范围列,那么选取碰到的第一个聚合函数列之前的列为前缀进行分组。
group index skip scan功能没有相关可以开启关闭的关键词,默认满足条件就可以利用,因此如果不想利用就要改变条件或者group by分组,只要不满足条件就不会利用联合索引。
表一:不能利用GROUP_INDEX_SKIP_SCAN的场所
场所cause说明sql语句涉及多张表not_single_table只能支持单张表sql语句带有rolluprollup表没有可用联合索引not_coveringsql语句带有ORDER BY DESCcannot_do_reverse_orderingsql语句不包含group_by或者DISTINCTnot_group_by_or_distinctsql语句不包含COUNT,SUM,AVG,MIN,MAX聚合函数not_applicable_aggregate_function查询条件生成了tree->mergesdisjuntive_predicate_present好比where c1=1 or c2>1,c1和c2属于差别索引查询条件既包含MIN/MAX列又包含非MIN/MAX列minmax_keypart_in_disjunctive_query见下面例子sql语句既带有distinct又带有min或者maxhave_both_agg_distinct_and_min_maxsql语句既带有distinct且distinct后面参数包含列和非列group_by后面跟的不是列而是表达式group_field_is_expression好比GROUP BY c1+1group by字段是联合索引的第一列group_attribute_not_prefix_in_index见下面例子distinct后面字段是派生表的列derived_tabledistinct后面字段是联合索引非前缀列或者非所有列select_attribute_not_prefix_in_indexdistinct后面字段必须是联合索引前缀列或者所有列group by前面的聚合函数的列不是连续的联合索引列no_nongroup_keypart_predicate见下面例子聚合函数(distinct column)字段是主键索引primary_key_is_clustered聚合函数列小于等于group by字段aggregate_column_not_suffix_in_idx见下面例子带有聚合函数的group by语句的条件不是聚合函数列之前一个列的等号条件non_equality_gap_attribute好比where c1>2 and c2>1 或者 where c1=2 and c2>1 见下面例子。而where c1>2 and c2=1是允许的带有聚合函数的group by语句且没有条件,聚合函数列大于group by的列no_nongroup_keypart_predicate见下面例子没有聚合函数但是有group by语句的条件带有非select和group by的条件列keypart_reference_from_where_clause好比where c1=1 or c3=1,见下面例子带有聚合函数的group by语句的sql涉及聚合函数之后的列keypart_after_infix_in_query见下面例子三、现实例子说明
接下来看几个例子来说明上面的代码。
greatsql> explain SELECT c1,c2,MIN(c3) FROM t1 where c1>1 and c2=1 GROUP BY c1;
从上面group index skip iscan的代码我们相识了组别跳跃扫描的利用条件和利用场景,以及利用规则,这个功能让一些涉及分组和聚合函数实行的时候直接读联合索引就可以很快得到分组数据,避免了无效列的读取,提高了效率,但sql利用限定比较多,因此创建联合索引和利用的时候要注意sql语句与联合索引的匹配才能用到这个功能。