聚合算法 mysql_MySQL内核技术之“聚合操作”

本文可以结合我的上一篇文章“结果发送”结合来看。因为上一篇文章着重针对COUNT操作的结果发送,文本继续以COUNT操作为例阐述MySQL的聚合操作。

简要来说调用关系:

JOIN::optimize-->

JOIN::make_join_plan()-->

JOIN::estimate_rowcount()-->

add_group_and_distinct_keys()-->

is_indexed_agg_distinct()-->

JOIN::make_sum_func_list()

make_sum_func_list函数如下:

bool JOIN::make_sum_func_list(List &field_list,

List &send_result_set_metadata,

bool before_group_by, bool recompute)

{

List_iterator_fast it(field_list);

Item_sum **func;

Item *item;

DBUG_ENTER("make_sum_func_list");

if (*sum_funcs && !recompute)

DBUG_RETURN(FALSE); /* We have already initialized sum_funcs. */

func= sum_funcs;

while ((item=it++))

{

if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item() &&

(!((Item_sum*) item)->depended_from() ||

((Item_sum *)item)->depended_from() == select_lex))

*func++= (Item_sum*) item;

}

if (before_group_by && rollup.state == ROLLUP::STATE_INITED)

{

rollup.state= ROLLUP::STATE_READY;

if (rollup_make_fields(field_list, send_result_set_metadata, &func))

DBUG_RETURN(TRUE); // Should never happen

}

else if (rollup.state == ROLLUP::STATE_NONE)

{

for (uint i=0 ; i <= send_group_parts ;i++)

sum_funcs_end[i]= func;

}

else if (rollup.state == ROLLUP::STATE_READY)

DBUG_RETURN(FALSE); // Don't put end marker

*func=0; // End marker

DBUG_RETURN(FALSE);

}

其中,*func++= (Item_sum*) item是赋值操作,即把对应的item直接转化成item_sum类赋值给func,即JOIN的sum_funcs(func= sum_funcs)。

这里的item是传入的field_list(join->all_fields),这个field_list是在yacc parse而来,即yacc.cc parse的时候就new出了对应的item_sum_count。

对MySQL的改动如何来做

因为我们加入了新的线程来并发执行,所以会在optimizer里new出新的JOIN。从JOIN的constructor可以看到:all_fields(select->all_fields),是直接通过select赋值的。如果新的线程对应的JOIN不改动的话,默认就要共享all_fields这个变量,肯定是不行的。

因此我们在创建JOIN后,要重置对应的sum_funcs和sum_funcs_end。我们可以参照make_sum_func_list的方法进行重置:

item_sum** func;

func= sum_funcs;

while ((item=it++))

{

if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item() &&

(!((Item_sum*) item)->depended_from() ||

((Item_sum *)item)->depended_from() == select_lex))

*func++= (Item_sum*) item;

}

使用item_sum_count自带的copy_or_same函数,来创建新的sum_funcs。同时也要reset sum_funcs_end:

sum_funcs_end= (Item_sum***) (sum_funcs + func_count + 1);

还有一点需要注意的是,在end_send_group中,如果结果为0会有如下调用,其中的no_rows_in_result()原代码用的是fields来调用,这样会把别的线程结果同时清零。我们需要把这里进行改动

// Calculate aggregate functions for no rows

List_iterator_fast it(*fields);

Item *item;

while ((item= it++))

item->no_rows_in_result();

类型判断

很多时候我们要判断聚合函数的类型。那么首先我们要先判断当前操作是否是聚合操作,然后再判断聚合操作的类型。

因为

Item类有一个纯虚函数: virtual enum Type type() const =0; 其对应的Type在该类中定义为:

enum Type {INVALID_ITEM= 0,

FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,

INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM,

COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,

PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,

FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,

SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,

PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM,

XPATH_NODESET, XPATH_NODESET_CMP,

VIEW_FIXER_ITEM};

进一步,Item_sum从Item派生出来,除了type()函数外,他还带有一个函数virtual enum Sumfunctype sum_func () const=0;。 在Item_sum中定义了Sumfunctype的类型:

enum Sumfunctype

{ COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,

AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC,

VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC

};

我们可以通过这些类型来判读当前具体的聚合操作。初次之外,我们还可以利用lex的一些helper函数来进行辅助判断,如is_single_grouped():

/**

@return true if this query block is implicitly grouped and returns exactly

one row, which happens when it does not have a HAVING clause.

*/

bool is_single_grouped() const

{

return m_agg_func_used &&

group_list.elements == 0 &&

m_having_cond == NULL;

}

该函数返回true的条件是没有group by,也没有have。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值