MySQL内核技术之“结果发送”

本节我们主要讨论COUNT的结果处理与发送。典型的SQL语句为:SELECT COUNT(*) FROM foo;

查询结果处理流程

结果累加调用链

JOIN::exec()--> 
do_select()--> 
sub_select()--> 
evaluate_join_record()--> 
end_send_group()--> 
init_sum_functions--> 
reset_and_add()--> 
aggregator_add()--> 
Item_sum_count::add()

返回结果调用链

JOIN::exec()--> 
do_select()--> 
sub_select()--> 
evaluate_join_record()--> 
end_send_group()--> 
send_data--> 
send_result_set_row()--> 
Item::send()--> 
Item_sum_count::val_int()

注意:上面的end_send_group实际上是evaluate_join_record()中的这行代码:rc= (*qep_tab->next_select)(join, qep_tab+1, 0);

整个逻辑是sub_select()中有个大循环,每次读出一条数据,然后进行evaluate_join_record()。在evaluate_join_record()中进行where判断等,然后调用end_send或者end_send_group进行最后处理。因为这里是COUNT因此,使用end_send_group()end_send_group调用reset_and_add进行累加。

发送完毕调用链(这个执行完客户端就有数据显示了)

dispatch_command()--> thd->send_statement_status()

多线程并发执行改造

现在我们来看看如何多结果处理流程进行改造。从上面分析可以看出,每次读出一条数据就要进入evaluate,调用end_send_group产看是否应该累加还是累加已经完毕。因此我们要在end_send_group加入新的逻辑,累加过程不变,但是累加完毕后,并不发送而是把结果放入select->m_parallel_results里,同时把done位置为true

而主线程要查看worker是否都完成了,即把结果放入select->m_parallel_results,如果是则进行所有的结果累加,还是加到item_sum中的count上。然后走正常的流程。

附录
MySQL的COUNT操作对应了Item_sum_count类,这个类是基于Item_sum类的。那么对应一个JOIN结构而言,里面包含了一个(其实是2个)Item_sum:分别是。Item_sum_count就被赋给了Item_sum这个成员变量。

执行的累加结果存在Item_sum_count中的count变量里,结束后被返回给客户端。因为没有GROUP BY,所以返回的结果只有一条记录。

改造的方法:因为一个JOIN对应了query的上下文,优化后的结果,如果同时被不同的thread执行,那么应该有多个count结果,而不是一个,这样我们就可以增加一个标志位为parallel,同时增加Item_sum_count中的member:count数组,其数量对应了多少个thread。每个thread执行的结果放在这对应的count中,执行完毕后worker thread退出,而由主thread统计结果并发送最后的count给client。

    原文作者:Michael
    原文地址: https://segmentfault.com/a/1190000011496773
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞