enter
This commit is contained in:
parent
e34d970937
commit
6cf5ecbfeb
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
函数接收一个查询规划器(PlannerInfo)和一个遗传算法的代表性基因序列(Gene* 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;// 返回最终的关联的关系表
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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;// 使用池大小作为默认的代数数量
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue