Deduce A New EC Object.

诸位需要对于PostgreSQL中的EC(EquivalenceClass)类型以及 EM类型有一个初步的了解。了解查询引擎优化时候的相关数据结构的含义。虽然这些术语不是必须知道,但是对于这些术语的了解有助于对应PostgreSQL对于EC对象的推导有所帮助。

在函数 distribute_qual_to_rels 中的,1862 行中,当clause为subplan时候,我们创建了一个 restrictinfo: make_restrictinfo ,但是在接下来的语句中,我们判断该 restrictinfo 的mergeopfamilies时候,我们并为将该subplan中的 约束条件考虑进去(此处存在在优化可能,将subplan中的约束也考虑到,这样与fromlist中的进行同样考虑。)如本例中的:fromlist中的class.gno=”grade one” 与 subplan中的约束条件: student.classno= sub.classno。??? 是否是由于subplan为一个独立的部分????

if (restrictinfo->mergeopfamilies)
{
if (maybe_equivalence)
{

在process_equivalence函数中,当遍历完root->eq_classes后,我们会得到ec1和ec2两个变量的值。并根据ec1和ec2的值进行处理。

(1)当 ec1和ec2都不为null时候, 当 ec1 == ec2时候,表明这个两个EC对象是同一个等式。 例如: Col1= var1; Col1=Var;此时,将这个两个EC对 象合并; A= B和A=B的情况。 当ec1 != ec2时候,表明是两个不同的等式。此时将这个两个EC对象进行合并;Col1= var2; Col3 = var4;此时合并后的(合并到ec1中) Co11->em = col1->em —-> col3->em ; A= B和 C=D 合并后, (A,C) = (B,D)

(2)当ec1不为空时候,此时表明ec2为空,说明我们没有找到, 将em2添加到ec1中。例如: A= B 和 A=C 则合并后为A=(B=C).

( add item2 to ec1) em2 = add_eq_member(ec1, item2, item2_relids, item2_nullable_relids, false, item2_type);

(3) 当ec2不为空时候, (add item1 to ec2 ), 例如: A= B 和 D = B 则, (A=D)=B em1 = add_eq_member(ec2, item1, item1_relids, item1_nullable_relids, false, item1_type);

(4) 创建新的ec对象。

在sweep through过程中,通过两个循环遍历链表上的数据。eq_classes

ec
ec1 = ec2 = NULL;
em1 = em2 = NULL;
foreach(lc1, root->eq_classes)
{
EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
ListCell *lc2;/* Never match to a volatile EC */
if (cur_ec->ec_has_volatile)
continue;
/*
* The collation has to match; check this first since it’s cheaper
* than the opfamily comparison.
*/
if (collation != cur_ec->ec_collation)
continue;
/*
* A “match” requires matching sets of btree opfamilies. Use of
* equal() for this test has implications discussed in the comments
* for get_mergejoin_opfamilies().
*/
if (!equal(opfamilies, cur_ec->ec_opfamilies))
continue;
foreach(lc2, cur_ec->ec_members)
{
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
Assert(!cur_em->em_is_child); /* no children yet */
/*
* If below an outer join, don’t match constants: they’re not as
* constant as they look.
*/
if ((below_outer_join || cur_ec->ec_below_outer_join) && cur_em->em_is_const)
continue;
if (!ec1 && item1_type == cur_em->em_datatype && equal(item1, cur_em->em_expr))
{
ec1 = cur_ec;
em1 = cur_em;
if (ec2)
break;
}
if (!ec2 && item2_type == cur_em->em_datatype && equal(item2, cur_em->em_expr))
{
ec2 = cur_ec;
em2 = cur_em;
if (ec1)
break;
}
}
if (ec1 && ec2)
break;
}

因为已经将重复的em对象处理,因此在上述中找到一个相等的跳出循环进行进行处理即可,不用在进行后续的查找了。

在 generate_base_implied_equalities 函数中,我们将根据 EC中是否含有const变量来进行分类处理。当ec中含有const值时候,使用generate_base_implied_equalities_const来处理该ec,尝试产生推导后的等式。 当该ec中无相应的const值后,我们使用generate_base_implied_equalities_no_const来完成等式产生。

sc.cno = course.cno的EM对象的处理过程:

在 generate_base_implied_equalities_no_const 函数中,

ec2

例如本例中的:sc.cno 由于 sc 的rtindex为1, 故而会放在 prev_ems[1] 所指向的数组中。 而course.cno中的course的rtindex为5故而会放到 prev_ems[5]中。

在变量EC中的EM对象时候,当遇见prev_ems[x]中存在着EM对象时候,则我们可推导出现新的等式。 例如:当上图中的prev_em[5]中存在着 em1,em2,em3的等式后,则我们可以推导出: em1 = em2 , em1= em3, em2= em3这样的等式存在。 上述由 process_implied_equality 函数来完成。 而这也是数据库理论中的条件传递的功能。

prev_ems = (EquivalenceMember **)
palloc0(root->simple_rel_array_size * sizeof(EquivalenceMember *));

foreach(lc, ec->ec_members)
{
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc);
int relid;
Assert(!cur_em->em_is_child); /* no children yet */
if (!bms_get_singleton_member(cur_em->em_relids, &relid))
continue;
Assert(relid < root->simple_rel_array_size);
if (prev_ems[relid] != NULL)
{
EquivalenceMember *prev_em = prev_ems[relid];
Oid eq_op;
eq_op = select_equality_operator(ec,
prev_em->em_datatype,
cur_em->em_datatype);
if (!OidIsValid(eq_op))
{
/* failed… */
ec->ec_broken = true;
break;
}
process_implied_equality(root, eq_op, ec->ec_collation,
prev_em->em_expr, cur_em->em_expr,
bms_copy(ec->ec_relids),
bms_union(prev_em->em_nullable_relids,
cur_em->em_nullable_relids),
ec->ec_below_outer_join,
false);
}
prev_ems[relid] = cur_em;
}
pfree(prev_ems);
对于语法树中的每个quals对象,都会使用如下的语句来,创建一个 restrictinfo 对象。

restrictinfo = make_restrictinfo((Expr *) clause,
is_pushed_down,
outerjoin_delayed,
pseudoconstant,
relids,
outerjoin_nonnullable,
nullable_relids
);