phpmysql网站源码分享,php+mysql网站开发项目式教程 源码

大家好,关于phpmysql网站源码分享很多朋友都还不太明白,今天小编就来为大家分享关于php+mysql网站开发项目式教程 源码的知识,希望对各位有所帮助!

总览

聚合函数(AggregateFunction)顾名思义,就是将一组数据进行统一计算,常常用于分析型数据库中,当然在应用中是非常重要不可或缺的函数计算方式。比如我们常见的COUNT/AVG/SUM/MIN/MAX等等。本文主要分析下该类函数实现的一些框架,不涉及到每个函数的详尽分析。聚合函数(AggregateFunction)实现的大部分代码在item_sum.h和item_sum.cc。

下面我们看一下代码,聚合函数(AggregateFunction)有哪些类型:

enumSumfunctype{\nCOUNT_FUNC,//COUNT\nCOUNT_DISTINCT_FUNC,//COUNT(DISTINCT)\nSUM_FUNC,//SUM\nSUM_DISTINCT_FUNC,//SUM(DISTINCT)\nAVG_FUNC,//AVG\nAVG_DISTINCT_FUNC,//AVG(DISTINCT)\nMIN_FUNC,//MIN\nMAX_FUNC,//MAX\nSTD_FUNC,//STD/STDDEV/STDDEV_POPorDISTINCT\nVARIANCE_FUNC,//VARIANCE/VAR_POPandVAR_SAMPorDISTINCT\nSUM_BIT_FUNC,//BIT_AND,BIT_ORandBIT_XOR\nUDF_SUM_FUNC,//userdefinedfunctions\nGROUP_CONCAT_FUNC,//GROUP_CONCATorGROUP_CONCATDISTINCT\nJSON_AGG_FUNC,//JSON_ARRAYAGGandJSON_OBJECTAGG\nROW_NUMBER_FUNC,//Windowfunctions\nRANK_FUNC,\nDENSE_RANK_FUNC,\nCUME_DIST_FUNC,\nPERCENT_RANK_FUNC,\nNTILE_FUNC,\nLEAD_LAG_FUNC,\nFIRST_LAST_VALUE_FUNC,\nNTH_VALUE_FUNC\n};\n

类Item_sum是聚合函数的基类。接下来我们继续看一下总体和主要的聚合函数具体在代码中的类结构和继承关系,

COUNT/SUM/AVG/STD/VAR函数

MIN/MAX函数

BIT_OR/BIT_AND/BIT_XOR函数

不带GROUPBY聚合

下面我们来介绍下如何工作的,先来看看不带GROUPBY的聚合过程。该过程借助了一个辅助类Aggregator,而GROUPBY并不使用该辅助类。

在优化阶段,需要进行setup,比如初始化distinct或者sorting需要Temptable或者Temptree结构,方便下阶段的聚合函数。具体根据不同函数有不同的实现。

JOIN::optimize–>\nJOIN::make_tmp_tables_info–>\nsetup_sum_funcs–>\nItem_sum::aggregator_setup–>\nAggregator_simple::setup–>\nItem_sum::setup–>\n

在执行阶段,结果输出函数end_send_group调用init_sum_functions来对该SQL查询的所有SUM函数进行聚合计算。

JOIN::exec()–>\ndo_select()–>\nsub_select()–>\nevaluate_join_record()–>\nend_send_group()–>\ninit_sum_functions–>forallsumfunctions\nreset_and_add()–>\naggregator_clear()/aggregator_add()–>\nItem_sum_xxx::clear()/Item_sum_xxx::add()\n

在计算distinct聚合时候,还需要必须实现aggregator::endup(),因为Distinct_aggregator::add()只是通过某种方式采集了unique的行,但是并未保存,需要在这个阶段进行保存。这个过程也可以理解,因为在Distinct聚合过程中(add),实际上无法判断是否为唯一。当然这个不适用于GROUPBY场景,因为GROUPBY场景本身就是通过临时表解决了唯一的问题。

带GROUPBY聚合

MySQL对于带GROUPBY的聚合,采用了使用Temptable的方式保存了(GROUPBYKEY,AGGRVALUE)。

JOIN::exec()–>\ndo_select()–>\nsub_select()–>\nevaluate_join_record()–>\nsub_select_op()–>\nQEP_tmp_table::put_record–>\nend_update–>\ninit_tmptable_sum_functions/update_tmptable_sum_func–>//每个groupby的key都会调用至少一次\nreset_sum_func–>Item_sum_xxx::reset_field()/Item_sum_xxx::update_field()\n

Item_sum继承Item_result_field,意味着该类作为计算函数的同时,也保存输出的结果。具体可以看对应Item_sum_xxx::val_xxx的实现,该函数负责对上层结果或者客户端结果进行输出。

但是,对于特殊聚合函数如AVG/STD/VAR_POP等函数,在累加过程中,临时保存的变量值有多个,实际的输出结果必须通过加工处理,尤其是在GROUPBY的场景下,多个临时变量需要保存到Temptable中,下次累加的时候取出来,直到最终结果输出。因此,需要额外的辅助Item_result_field类,帮助该聚合函数进行最终结果输出。下图为各个辅助Item_result_field的继承关系。

举例来说,对于Item_avg_field类的最终结果(SELECTAVG(c1)FROMt1GROUPBYc2)则需要通过Item_avg_field::val_xxx计算后进行输出,如:

doubleItem_avg_field::val_real(){\n//fix_fields()nevercallsforthisItem\ndoublenr;\nlonglongcount;\nuchar*res;\nif(hybrid_type==DECIMAL_RESULT)returnval_real_from_decimal();\nfloat8get(&nr,field->ptr);\nres=(field->ptr+sizeof(double));\ncount=sint8korr(res);\nif((null_value=!count))return0.0;\nreturnnr/(double)count;\n}\n

调用的堆栈如下:

10x0000000003380a3finItem::send\n30x00000000036a82d4inQuery_result_send::send_data\n50x0000000002ba7a7dinevaluate_join_record\n70x0000000002ba51e7insub_select_op\n90x0000000002ba4928indo_select\n00x0000000003549600inItem_avg_field::save_in_field_inner\n20x0000000002b239e0infill_record\n40x0000000003773357inQuery_result_insert::store_values\n60x0000000002bb001finend_send\n80x0000000002bc3debinQEP_tmp_table::end_send\n100x0000000002ba5572insub_select\n120x0000000002b9e571inJOIN::exec\n

聚合函数的优化

不带where子句的简单COUNT在简单求计数统计时候(SELECTCOUNT(*)FROMt1),Server层和Innodb层实现了handler::ha_records用于直接返回准确的计数。由于加了WHERE子句会调用evaluate_join_record评估是否该返回行否和统计条件。详细调用堆栈如下:

10x0000000002a19b4ainhandler::ha_records\n30x0000000002bb1389inend_send_count\n50x0000000002b9e571inJOIN::exec\n

无GROUPBY的MIN/MAX单行优化如果恰好对index所在的列求MIN/MAX,而且只返回一行没有GROUPBY的情况下,那么这个是可以进行优化的,可以看执行计划的Extra信息变成Selecttablesoptimizedaway而非使用Usingtemporary。

mysql>explainselectmin(c1)fromttt;\n+—-+————-+——-+————+——+—————+——+———+——+——+———-+——————————+\n|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|\n+—-+————-+——-+————+——+—————+——+———+——+——+———-+——————————+\n|1|SIMPLE|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL|Selecttablesoptimizedaway|\n+—-+————-+——-+————+——+—————+——+———+——+——+———-+——————————+\n1rowinset,1warning(0.00sec)\n

因此结果会在优化阶段就已经计算完毕返回到上层,堆栈如下:

10x00000000032bb4bcinhandler::ha_index_first\n30x0000000002a168ceinopt_sum_query\nusingIndexRangeScanIterator+QUICK_GROUP_MIN_MAX_SELECTUsingindexforgroup-by\nexplainselectmin(c2)fromttt2groupbyc1;\n+—-+————-+——-+————+——-+—————+——+———+——+——+———-+————————–+\n|id|select_type|table|partitions|type|possible_keys|key|key_len|ref|rows|filtered|Extra|\n+—-+————-+——-+————+——-+—————+——+———+——+——+———-+————————–+\n|1|SIMPLE|t1|NULL|range|c1|c1|4|NULL|2|100.00|Usingindexforgroup-by|\n+—-+————-+——-+————+——-+—————+——+———+——+——+———-+————————–+\n

详细堆栈如下:

20x00000000029f34d4inQUICK_GROUP_MIN_MAX_SELECT::reset\n40x0000000002ba5c88insub_select\n1index_first/index_next_different\n30x0000000002a65c51inIndexRangeScanIterator::Init\n60x0000000002b9e571inJOIN::exec\n

综述

综上所述,本篇文章主要从源码层面对MySQL8.0实现的聚合函数(AggregateFunction)进行了一下简要的分析。聚合函数(AggregateFunction)在无GROUPBY的情况下,利用定义成员变量保存对应计算结果的中间值,在有GROUPBY的情况下利用了TempTable来保存对应的GROUPBY的键和聚合值,另外还介绍了一些聚合函数(AggregateFunction)的优化方式。当然这里面还有两类重要的聚合就是ROLLUP和WINDOWS函数,由于篇幅限制,未来篇章会单独介绍。希望该篇文章能够帮助广大读者了解MySQL聚合函数(AggregateFunction)的实现原理。

作者:悟道之客

如果你还想了解更多这方面的信息,记得收藏关注本站。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平