This commit is contained in:
Cachuela 2023-09-25 18:20:14 +08:00
parent e34d970937
commit 6cf5ecbfeb
2 changed files with 71 additions and 51 deletions

View File

@ -34,26 +34,33 @@
/* A "clump" of already-joined relations within gimme_tree */
typedef struct {
// 关联的关系信息
RelOptInfo* joinrel; /* joinrel for the set of relations */
// 关联的大小
int size; /* number of input relations in clump */
} Clump;
static List* merge_clump(PlannerInfo* root, List* clumps, Clump* new_clump, bool force);
static bool desirable_join(PlannerInfo* root, RelOptInfo* outer_rel, RelOptInfo* inner_rel);
static List* merge_clump(PlannerInfo* root, List* clumps, Clump* new_clump, bool force);// 静态函数——合并关联的 Clump 结构体列表
static bool desirable_join(PlannerInfo* root, RelOptInfo* outer_rel, RelOptInfo* inner_rel);// 静态函数——确定连接两个关系是否是合适的
/*
* geqo_eval
*
* Returns cost of a query tree as an individual of the population.
*/
/*
PlannerInfoGene* tour
*/
Cost geqo_eval(PlannerInfo* root, Gene* tour, int num_gene)
{
MemoryContext mycontext;
MemoryContext oldcxt;
RelOptInfo* joinrel = NULL;
Cost fitness;
int savelength;
struct HTAB* savehash;
MemoryContext mycontext;// 创建一个内存上下文,用于存储 GEQO 相关数据
MemoryContext oldcxt;// 用于保存当前内存上下文
RelOptInfo* joinrel = NULL;// 初始化关联的关系信息
Cost fitness;// 存储查询执行计划的适应度(成本)
int savelength;// 保存当前关联的关系表列表的长度
struct HTAB* savehash;// 保存当前的关系表哈希表
/*
* Create a private memory context that will hold all temp storage
@ -65,8 +72,9 @@ Cost geqo_eval(PlannerInfo* root, Gene* tour, int num_gene)
* be freed even if we abort via ereport(ERROR).
*/
mycontext = AllocSetContextCreate(
// 创建一个内存上下文,用于存储 GEQO 相关数据
CurrentMemoryContext, "GEQO", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(mycontext);
oldcxt = MemoryContextSwitchTo(mycontext); // 切换到新的内存上下文
/*
* gimme_tree will add entries to root->join_rel_list, which may or may
@ -83,14 +91,14 @@ Cost geqo_eval(PlannerInfo* root, Gene* tour, int num_gene)
*
* join_rel_level[] shouldn't be in use, so just Assert it isn't.
*/
savelength = list_length(root->join_rel_list);
savehash = root->join_rel_hash;
AssertEreport(root->join_rel_level == NULL, MOD_OPT, "");
savelength = list_length(root->join_rel_list);// 获取当前关联的关系表列表的长度
savehash = root->join_rel_hash;// 保存当前的关系表哈希表
AssertEreport(root->join_rel_level == NULL, MOD_OPT, "");// 使用断言确保当前的关联关系级别为空
root->join_rel_hash = NULL;
root->join_rel_hash = NULL;// 清空当前关系表哈希表
/* construct the best path for the given combination of relations */
joinrel = gimme_tree(root, tour, num_gene);
joinrel = gimme_tree(root, tour, num_gene);// 调用 gimme_tree 函数获取关联的关系树
/*
* compute fitness
@ -98,20 +106,20 @@ Cost geqo_eval(PlannerInfo* root, Gene* tour, int num_gene)
* XXX geqo does not currently support optimization for partial result
* retrieval --- how to fix?
*/
fitness = ((Path*)linitial(joinrel->cheapest_total_path))->total_cost;
fitness = ((Path*)linitial(joinrel->cheapest_total_path))->total_cost;// 获取最便宜的路径的总代价
/*
* Restore join_rel_list to its former state, and put back original
* hashtable if any.
*/
root->join_rel_list = list_truncate(root->join_rel_list, savelength);
root->join_rel_hash = savehash;
root->join_rel_list = list_truncate(root->join_rel_list, savelength);// 恢复关系表列表的长度
root->join_rel_hash = savehash;// 恢复关系表哈希表
/* release all the memory acquired within gimme_tree */
(void)MemoryContextSwitchTo(oldcxt);
MemoryContextDelete(mycontext);
(void)MemoryContextSwitchTo(oldcxt);// 切换回原始的内存上下文
MemoryContextDelete(mycontext);// 删除新创建的内存上下文
return fitness;
return fitness;// 返回计算的适应度值
}
/*
@ -138,9 +146,12 @@ Cost geqo_eval(PlannerInfo* root, Gene* tour, int num_gene)
* generated plans.
*/
RelOptInfo* gimme_tree(PlannerInfo* root, Gene* tour, int num_gene)
/*
便使
*/
{
GeqoPrivateData* priv = (GeqoPrivateData*)root->join_search_private;
List* clumps = NIL;
GeqoPrivateData* priv = (GeqoPrivateData*)root->join_search_private;// 获取 GEQO 的私有数据
List* clumps = NIL;// 创建一个关联的关系表列表
int rel_count;
/*
@ -155,7 +166,7 @@ RelOptInfo* gimme_tree(PlannerInfo* root, Gene* tour, int num_gene)
* joins might still fail due to semantics, but we should always be able
* to find some join order that works.
*/
clumps = NIL;
clumps = NIL;// 初始化关系表列表
for (rel_count = 0; rel_count < num_gene; rel_count++) {
int cur_rel_index;
@ -163,16 +174,16 @@ RelOptInfo* gimme_tree(PlannerInfo* root, Gene* tour, int num_gene)
Clump* cur_clump = NULL;
/* Get the next input relation */
cur_rel_index = (int)tour[rel_count];
cur_rel = (RelOptInfo*)list_nth(priv->initial_rels, cur_rel_index - 1);
cur_rel_index = (int)tour[rel_count];// 获取当前关联的关系索引
cur_rel = (RelOptInfo*)list_nth(priv->initial_rels, cur_rel_index - 1);// 根据索引获取当前关系的信息
/* Make it into a single-rel clump */
cur_clump = (Clump*)palloc(sizeof(Clump));
cur_clump->joinrel = cur_rel;
cur_clump->size = 1;
cur_clump = (Clump*)palloc(sizeof(Clump));// 分配内存以存储当前的关联关系信息
cur_clump->joinrel = cur_rel;// 设置当前关联的关系信息
cur_clump->size = 1;// 设置关系大小为1
/* Merge it into the clumps list, using only desirable joins */
clumps = merge_clump(root, clumps, cur_clump, false);
clumps = merge_clump(root, clumps, cur_clump, false);// 调用 merge_clump 函数将当前关联关系合并到列表中
}
if (list_length(clumps) > 1) {
@ -184,7 +195,7 @@ RelOptInfo* gimme_tree(PlannerInfo* root, Gene* tour, int num_gene)
Clump* clump = (Clump*)lfirst(lc);
fclumps = merge_clump(root, fclumps, clump, true);
}
}// 强制合并关联关系列表
clumps = fclumps;
}
@ -193,9 +204,9 @@ RelOptInfo* gimme_tree(PlannerInfo* root, Gene* tour, int num_gene)
ereport(ERROR,
(errmodule(MOD_OPT),
errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE),
errmsg("failed to join all relations together")));
errmsg("failed to join all relations together"))); // 如果无法将所有关联关系连接在一起,则报告错误
return ((Clump*)linitial(clumps))->joinrel;
return ((Clump*)linitial(clumps))->joinrel;// 返回最终的关联的关系表
}
/*

View File

@ -32,21 +32,28 @@
#include "optimizer/geqo_random.h"
#include "optimizer/geqo_selection.h"
static int gimme_pool_size(int nr_rel);
static int gimme_number_generations(int pool_size);
static int gimme_pool_size(int nr_rel);//根据关系数nr_rel计算池大小
static int gimme_number_generations(int pool_size);//根据池大小计算生成的代数数量
/* define edge recombination crossover [ERX] per default */
#if !defined(ERX) && !defined(PMX) && !defined(CX) && !defined(PX) && !defined(OX1) && !defined(OX2)
#define ERX
#endif
/*
*/
/*
* geqo
* solution of the query optimization problem
* similar to a constrained Traveling Salesman Problem (TSP)
*/
RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)// GEQO遗传查询优化算法主函数
{
// 定义GEQO的私有数据结构和变量
GeqoPrivateData priv;
int generation;
Chromosome* momma = NULL;
@ -55,7 +62,7 @@ RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
Pool* pool = NULL;
int pool_size, number_generations;
#ifdef GEQO_DEBUG
#ifdef GEQO_DEBUG// 根据宏定义,为特定的交叉方法分配额外的数据结构
int status_interval;
#endif
Gene* best_tour = NULL;
@ -74,19 +81,19 @@ RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
#endif
/* set up private information */
root->join_search_private = (void*)&priv;
root->join_search_private = (void*)&priv;// 设置PlannerInfo中的私有数据
priv.initial_rels = initial_rels;
/* initialize private number generator */
geqo_set_seed(root, u_sess->attr.attr_sql.Geqo_seed);
geqo_set_seed(root, u_sess->attr.attr_sql.Geqo_seed);// 设置GEQO的随机种子
/* set GA parameters */
pool_size = gimme_pool_size(number_of_rels);
pool_size = gimme_pool_size(number_of_rels);// 根据输入计算池大小和生成代数数量
number_generations = gimme_number_generations(pool_size);
#ifdef GEQO_DEBUG
status_interval = 10;
#endif
// 为GEQO池分配内存并初始化
/* allocate genetic pool memory */
pool = alloc_pool(root, pool_size, number_of_rels);
@ -97,7 +104,7 @@ RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
sort_pool(root, pool); /* we have to do it only one time, since all
* kids replace the worst individuals in
* future (-> geqo_pool.c:spread_chromo ) */
#ifdef GEQO_DEBUG
#ifdef GEQO_DEBUG// 在调试模式下记录池统计信息
elog(DEBUG1,
"GEQO selected %d pool entries, best %.2f, worst %.2f",
pool_size,
@ -106,9 +113,10 @@ RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
#endif
/* allocate chromosome momma and daddy memory */
momma = alloc_chromo(root, pool->string_length);
momma = alloc_chromo(root, pool->string_length);// 为父代染色体momma和daddy分配内存
daddy = alloc_chromo(root, pool->string_length);
// 根据所选的交叉方法,为额外的数据结构分配内存
#if defined(ERX)
#ifdef GEQO_DEBUG
elog(DEBUG2, "using edge recombination crossover [ERX]");
@ -153,9 +161,9 @@ RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
/* my pain main part: */
/* iterative optimization */
for (generation = 0; generation < number_generations; generation++) {
for (generation = 0; generation < number_generations; generation++) {// GEQO算法的主循环用于代数迭代
/* SELECTION: using linear bias function */
geqo_selection(root, momma, daddy, pool, u_sess->attr.attr_sql.Geqo_selection_bias);
geqo_selection(root, momma, daddy, pool, u_sess->attr.attr_sql.Geqo_selection_bias);// 执行父代选择和基于所选方法的交叉操作
#if defined(ERX)
/* EDGE RECOMBINATION CROSSOVER */
@ -188,10 +196,10 @@ RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
#endif
/* EVALUATE FITNESS */
kid->worth = geqo_eval(root, kid->string, pool->string_length);
kid->worth = geqo_eval(root, kid->string, pool->string_length);// 评估子代染色体的价值
/* push the kid into the wilderness of life according to its worth */
spread_chromo(root, kid, pool);
spread_chromo(root, kid, pool);// 将子代染色体传播到池中以用于下一代
#ifdef GEQO_DEBUG
if (status_interval && !(generation % status_interval))
@ -199,7 +207,7 @@ RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
#endif
}
#if defined(ERX) && defined(GEQO_DEBUG)
#if defined(ERX) && defined(GEQO_DEBUG)// 在调试模式下打印池的状态
if (edge_failures != 0)
elog(LOG, "[GEQO] failures: %d, average: %d", edge_failures, number_generations / edge_failures);
else
@ -270,14 +278,14 @@ RelOptInfo* geqo(PlannerInfo* root, int number_of_rels, List* initial_rels)
* The default is based on query size (no. of relations) = 2^(QS+1),
* but constrained to a range based on the effort value.
*/
static int gimme_pool_size(int nr_rel)
static int gimme_pool_size(int nr_rel)// 用于根据关系数计算池大小的函数
{
double size;
int minsize;
int maxsize;
/* Legal pool size *must* be at least 2, so ignore attempt to select 1 */
if (u_sess->attr.attr_sql.Geqo_pool_size >= 2)
if (u_sess->attr.attr_sql.Geqo_pool_size >= 2)// 检查配置中是否设置了特定的池大小
return u_sess->attr.attr_sql.Geqo_pool_size;
size = pow(2.0, nr_rel + 1.0);
@ -302,10 +310,11 @@ static int gimme_pool_size(int nr_rel)
* sure that less-fit individuals get pushed out of the breeding
* population before the run finishes.
*/
static int gimme_number_generations(int pool_size)
static int gimme_number_generations(int pool_size)// 根据池大小计算生成代数数量的函数
{
// 检查配置中是否设置了特定的代数数量
if (u_sess->attr.attr_sql.Geqo_generations > 0)
return u_sess->attr.attr_sql.Geqo_generations;
return pool_size;
return pool_size;// 使用池大小作为默认的代数数量
}