248 lines
7.5 KiB
C++
248 lines
7.5 KiB
C++
/* -------------------------------------------------------------------------
|
||
*
|
||
* stream_cost.cpp
|
||
* functions used to calculate stream plan costs.
|
||
*
|
||
*
|
||
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
|
||
* Portions Copyright (c) 1994, Regents of the University of California
|
||
*
|
||
* src/gaussdbkernel/porcess/stream/stream_cost.cpp
|
||
*
|
||
* -------------------------------------------------------------------------
|
||
*/
|
||
|
||
#include <math.h>
|
||
#include <pthread.h>
|
||
#include "access/hash.h"
|
||
#include "optimizer/cost.h"
|
||
#include "optimizer/dataskew.h"
|
||
#include "optimizer/planner.h"
|
||
|
||
void parallel_stream_info_print(ParallelDesc* smpDesc, StreamType type)
|
||
{
|
||
char* distri_type = NULL;
|
||
|
||
if (NULL == smpDesc)
|
||
return;
|
||
|
||
/* 设置流类型标签。*/
|
||
switch (smpDesc->distriType) {
|
||
case REMOTE_DISTRIBUTE:
|
||
distri_type = "REDISTRIBUTE";
|
||
break;
|
||
|
||
case REMOTE_SPLIT_DISTRIBUTE:
|
||
distri_type = "SPLIT REDISTRIBUTE";
|
||
break;
|
||
|
||
case REMOTE_BROADCAST:
|
||
distri_type = "BROADCAST";
|
||
break;
|
||
|
||
case REMOTE_SPLIT_BROADCAST:
|
||
distri_type = "SPLIT BROADCAST";
|
||
break;
|
||
|
||
case LOCAL_DISTRIBUTE:
|
||
distri_type = "LOCAL REDISTRIBUTE";
|
||
break;
|
||
|
||
case LOCAL_BROADCAST:
|
||
distri_type = "LOCAL BROADCAST";
|
||
break;
|
||
|
||
case LOCAL_ROUNDROBIN:
|
||
distri_type = "LOCAL ROUNDROBIN";
|
||
break;
|
||
|
||
default:
|
||
if (type == STREAM_BROADCAST)
|
||
distri_type = "BROADCAST";
|
||
else
|
||
distri_type = "REDISTRIBUTE";
|
||
break;
|
||
}
|
||
|
||
/* 打印日志。*/
|
||
elog(DEBUG1,
|
||
"Stream cost: SMP INFO: sendDop: %d, receiveDop: %d, distribute type: %s",
|
||
SET_DOP(smpDesc->producerDop),
|
||
SET_DOP(smpDesc->consumerDop),
|
||
distri_type);
|
||
}
|
||
|
||
/*
|
||
* cost_stream
|
||
* computer cost of stream a RepOptInfo object
|
||
*/
|
||
void cost_stream(StreamPath* stream, int width, bool isJoin)
|
||
{
|
||
const double startup_cost_broadcast = 0.0;
|
||
|
||
// 断言:流和子计划不能为空
|
||
AssertEreport(stream != NULL && stream->subpath != NULL, MOD_OPT, "The stream or subplan is invalid");
|
||
|
||
// 设置启动成本为广播的启动成本
|
||
stream->path.startup_cost = startup_cost_broadcast;
|
||
// 累加子计划的启动成本到流的启动成本
|
||
stream->path.startup_cost += stream->subpath->startup_cost;
|
||
// 设置流的总成本为子计划的总成本
|
||
stream->path.total_cost = stream->subpath->total_cost;
|
||
// 设置流的成本为子计划的启动成本
|
||
stream->path.stream_cost = stream->subpath->startup_cost;
|
||
|
||
// 计算生产者和消费者数据节点的数量
|
||
unsigned int producer_num_datanodes = bms_num_members(stream->path.distribution.bms_data_nodeids);
|
||
unsigned int consumer_num_datanodes = bms_num_members(stream->consumer_distribution.bms_data_nodeids);
|
||
|
||
// 调用compute_stream_cost函数计算流的成本
|
||
compute_stream_cost(stream->type,
|
||
stream->subpath->locator_type,
|
||
PATH_LOCAL_ROWS(stream->subpath),
|
||
stream->subpath->rows,
|
||
stream->path.multiple,
|
||
width,
|
||
isJoin,
|
||
stream->path.distribute_keys,
|
||
&stream->path.total_cost,
|
||
&stream->path.rows,
|
||
producer_num_datanodes,
|
||
consumer_num_datanodes,
|
||
stream->smpDesc,
|
||
stream->skew_list);
|
||
|
||
return;
|
||
}
|
||
|
||
List* get_max_cost_distkey_for_hasdistkey(PlannerInfo* root, List* subPlans, int subPlanNum,
|
||
List** subPlanKeyArray, Cost* subPlanCostArray, Bitmapset** redistributePlanSetCopy)
|
||
{
|
||
Cost* keyCostArray = NULL;
|
||
int counter = 0;
|
||
int maxCostIndex = 0;
|
||
int subPlanIndex = 0;
|
||
List* redistributeKeyIndex = NULL;
|
||
|
||
/*
|
||
* subplan有多个分发键,找出子计划的最大成本分配键。
|
||
*/
|
||
keyCostArray = (Cost*)palloc0(sizeof(Cost) * subPlanNum);
|
||
|
||
while (counter < subPlanNum) {
|
||
List* keyIndex = subPlanKeyArray[counter];
|
||
|
||
if (keyIndex == NULL) {
|
||
counter++;
|
||
continue;
|
||
}
|
||
|
||
for (subPlanIndex = 0; subPlanIndex < subPlanNum; subPlanIndex++) {
|
||
if (equal(subPlanKeyArray[subPlanIndex], keyIndex)) {
|
||
if (subPlanIndex < counter) {
|
||
keyCostArray[counter] = 0;
|
||
break;
|
||
} else {
|
||
keyCostArray[counter] += subPlanCostArray[subPlanIndex];
|
||
}
|
||
}
|
||
}
|
||
|
||
counter++;
|
||
}
|
||
|
||
/*
|
||
* 得到每个redistributekey的最大代价
|
||
*/
|
||
for (counter = 0; counter < subPlanNum; counter++) {
|
||
if (keyCostArray[maxCostIndex] < keyCostArray[counter]) {
|
||
maxCostIndex = counter;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 使用最大成本重分发键设置其他每个子计划
|
||
*/
|
||
redistributeKeyIndex = subPlanKeyArray[maxCostIndex];
|
||
for (subPlanIndex = 0; subPlanIndex < subPlanNum; subPlanIndex++) {
|
||
if (!equal(subPlanKeyArray[subPlanIndex], redistributeKeyIndex)) {
|
||
*redistributePlanSetCopy = bms_add_member(*redistributePlanSetCopy, subPlanIndex);
|
||
}
|
||
}
|
||
|
||
pfree_ext(keyCostArray);
|
||
keyCostArray = NULL;
|
||
return redistributeKeyIndex;
|
||
}
|
||
|
||
/*
|
||
* 我们需要得到子计划的最大成本分配键作为其他子计划的最终重分发键。
|
||
*/
|
||
List* get_max_cost_distkey_for_nulldistkey(PlannerInfo* root, List* subPlans, int subPlanNum, Cost* subPlanCostArray)
|
||
{
|
||
Plan* subPlan = NULL;
|
||
int counter = 0;
|
||
int maxCostIndex = 0;
|
||
List* redistributeKeyIndex = NULL;
|
||
|
||
/*
|
||
* 找到具有最大成本的重新分发键。
|
||
*/
|
||
for (counter = 0; counter < subPlanNum; counter++) {
|
||
if (subPlanCostArray[maxCostIndex] < subPlanCostArray[counter]) {
|
||
maxCostIndex = counter;
|
||
}
|
||
}
|
||
|
||
/* 如果没有分发键,我们应该选择具有最大成本的分发键。 */
|
||
subPlan = (Plan*)list_nth(subPlans, maxCostIndex);
|
||
redistributeKeyIndex = make_distkey_for_append(root, subPlan);
|
||
return redistributeKeyIndex;
|
||
}
|
||
|
||
/*
|
||
如果找不到分布键,则根据偏差构造分布键索引。
|
||
如果subplan的targetlist没有空闲,我们应该选择前三个目标条目
|
||
的var为分发键。
|
||
*/
|
||
List* make_distkey_for_append(PlannerInfo* root, Plan* subPlan)
|
||
{
|
||
List* grplist = NIL;
|
||
List* subPlanKeyArray = NIL;
|
||
const int defaultDistkeyNum = 3;
|
||
|
||
/* 使用目标列表构建分组子句。 */
|
||
grplist = make_groupcl_for_append(root, subPlan->targetlist);
|
||
if (grplist != NIL) {
|
||
double multiple;
|
||
List* distkeys = NIL;
|
||
|
||
/* 根据偏差获取分发键。 */
|
||
distkeys = get_distributekey_from_tlist(root, subPlan->targetlist, grplist, subPlan->plan_rows, &multiple);
|
||
if (distkeys != NIL)
|
||
subPlanKeyArray = distributeKeyIndex(root, distkeys, subPlan->targetlist);
|
||
|
||
list_free_ext(grplist);
|
||
list_free_ext(distkeys);
|
||
} else {
|
||
/* 选择变量的前三个目标项作为分发键。 */
|
||
int distkeynum = 0;
|
||
ListCell* teCell = NULL;
|
||
|
||
foreach (teCell, subPlan->targetlist) {
|
||
TargetEntry* teEntry = (TargetEntry*)lfirst(teCell);
|
||
Node* node = (Node*)teEntry->expr;
|
||
|
||
if (!teEntry->resjunk && IsTypeDistributable(exprType(node))) {
|
||
subPlanKeyArray = lappend_int(subPlanKeyArray, teEntry->resno);
|
||
distkeynum++;
|
||
|
||
if (distkeynum <= defaultDistkeyNum)
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return subPlanKeyArray;
|
||
} |