CJobGroupExpressionExploration类作为Explore group expression optimization job,主要负责创建给定组表达式的逻辑重写。请注意,组探索作业需要为基础组中的每个组表达式运行组表达式探索作业(Responsible for creating the logical rewrites of a given group expression. Note that a group exploration job entails running a group expression exploration job for each group expression in the underlying group)。

ORCA优化器浅析——CJobGroupExpressionExploration探究_windows


首先介绍一点:如图每个 Group【代码中体现为CGroup】 保存的是逻辑等价的GroupExpression【代码中体现为CGroupExpression】;而GroupExpression作为表达式在Cascades中的管理器,真正的优化单元。这里的CJobGroupExpressionExploration就是用于执行GroupExpression Exploration(主要负责推导等价的逻辑表达式)的任务单元。CJobGroupExpressionExploration继承自CJobGroupExpression,而CJobGroupExpression继承自CJob类。

状态流图

CJobGroupExpression使用JSM实现了逻辑状态机,其状态流转如下图所示。由void CJobGroupExpressionExploration::Init(CGroupExpression *pgexpr)函数对CJobGroupExpression实例进行初始化,首先调用父类CJobGroupExpression::Init(pgexpr)函数,其实就是设置父类中的m_pgexpr = pgexpr,以及m_fChildrenScheduled和m_fXformsScheduled为true;调用m_jsm.Init函数初始化逻辑状态机,然后会设置状态机每个状态下执行的函数,如下所示:

// set job actions
	m_jsm.SetAction(estInitialized, EevtExploreChildren);
	m_jsm.SetAction(estChildrenExplored, EevtExploreSelf);
	m_jsm.SetAction(estSelfExplored, EevtFinalize);

ORCA优化器浅析——CJobGroupExpressionExploration探究_规则集_02


ORCA优化器浅析——CJobGroupExpressionExploration探究_规则集_03

ScheduleJob

首先介绍ScheduleJob,该函数是创建调度CJobGroupExpression任务的API(Schedule a new group expression exploration job)。该函数通过JobFactory的PjCreate函数创建CJob::EjtGroupExpressionExploration类型任务,也就是CJobGroupExpression任务,调用Init函数进行初始化,最后通过CScheduler的Add函数建立新建的任务与当前类任务实例的父子关系,并加入到任务等待队列waiting list中。

void CJobGroupExpressionExploration::ScheduleJob(CSchedulerContext *psc, CGroupExpression *pgexpr, CJob *pjParent){
	CJob *pj = psc->Pjf()->PjCreate(CJob::EjtGroupExpressionExploration);
	// initialize job
	CJobGroupExpressionExploration *pjege = PjConvert(pj);
	pjege->Init(pgexpr);
	psc->Psched()->Add(pjege, pjParent);
}

EevtExploreChildren

首先看在estInitialized状态下,调用的函数EevtExploreChildren。该函数首先看父类CJobGroupExpression的m_fChildrenScheduled是否为true,如果为true说明已经调度过子任务,可以转移到下一个状态;否则,将CGroupExpression m_pgexpr状态设置为CGroupExpression::estExploring,说明正在Exploring,调用ScheduleChildGroupsJobs函数。

CJobGroupExpressionExploration::EEvent CJobGroupExpressionExploration::EevtExploreChildren(CSchedulerContext *psc, CJob *pjOwner) {	
	CJobGroupExpressionExploration *pjgee = PjConvert(pjOwner); // get a job pointer
	if (!pjgee->FChildrenScheduled()) // m_fChildrenScheduled
	{
		pjgee->m_pgexpr->SetState(CGroupExpression::estExploring);
		pjgee->ScheduleChildGroupsJobs(psc);
		return eevExploringChildren;
	}else{
		return eevChildrenExplored;
	}
}

ScheduleChildGroupsJobs函数的作用时为所有子groups都调度exploration任务。注意这里的 m_pgexpr->Arity()代表该表达式关联的子group的数量,而[]号也被CGroupExpression重载过。详细细节可以看CGroupExpression实现。

void CJobGroupExpressionExploration::ScheduleChildGroupsJobs(CSchedulerContext *psc) {
	ULONG arity = m_pgexpr->Arity();
	for (ULONG i = 0; i < arity; i++)
		CJobGroupExploration::ScheduleJob(psc, (*(m_pgexpr))[i], this);
	SetChildrenScheduled();
}

从开头的图中我们看到,Group0中的Selection,Join是等价的Group Expression,作为Group0的子Group Expression。因此,每个Group Expression又引用了其他的Group,作为这个表达式的子Group。所以这里的ScheduleChildGroupsJobs会为Group Expression的子groups都调度起CJobGroupExploration任务。

EevtExploreSelf

当子group都Explored之后,进入了estChildrenExplored状态,状态机开始调用EevtExploreSelf函数。首先查看父类的m_fXformsScheduled Xform是否已经应用过了,如果是,进入下一个状态eevSelfExplored;否则需要调用ScheduleApplicableTransformations函数。

CJobGroupExpressionExploration::EEvent CJobGroupExpressionExploration::EevtExploreSelf(CSchedulerContext *psc, CJob *pjOwner){	
	CJobGroupExpressionExploration *pjgee = PjConvert(pjOwner); // get a job pointer
	if (!pjgee->FXformsScheduled()) { // m_fXformsScheduled
		pjgee->ScheduleApplicableTransformations(psc);
		return eevExploringSelf;
	}else{
		return eevSelfExplored;
	}
}

ScheduleApplicableTransformations函数首先从m_pgexpr中获取到CLogical操作符的规则集,然后拿操作符的规则集和逻辑变换集合取与,得到操作符Exploration阶段需要的规则,然后通过父类的ScheduleTransformations函数使用每个规则对m_pgexpr进行转换

//---------------------------------------------------------------------------
//	@function:
//		CJobGroupExpressionExploration::ScheduleApplicableTransformations
//	@doc:
//		Schedule transformation jobs for all applicable xforms
//---------------------------------------------------------------------------
void CJobGroupExpressionExploration::ScheduleApplicableTransformations( CSchedulerContext *psc) {
	// get all applicable xforms
	COperator *pop = m_pgexpr->Pop();
	CXformSet *xform_set = CLogical::PopConvert(pop)->PxfsCandidates(psc->GetGlobalMemoryPool());

	// intersect them with required xforms and schedule jobs
	xform_set->Intersection(CXformFactory::Pxff()->PxfsExploration());
	xform_set->Intersection(psc->Peng()->PxfsCurrentStage());
	ScheduleTransformations(psc, xform_set);
	xform_set->Release();

	SetXformsScheduled();
}
void CJobGroupExpression::ScheduleTransformations(CSchedulerContext *psc, CXformSet *xform_set){
	// iterate on xforms
	CXformSetIter xsi(*(xform_set));
	while (xsi.Advance()){
		CXform *pxform = CXformFactory::Pxff()->Pxf(xsi.TBit());
		CJobTransformation::ScheduleJob(psc, m_pgexpr, pxform, this);
	}
}

一个表达式,可能对应多个规则。Cascades的设计中,使用集合来管理规则。工程实现中,GPORCA使用位图来管理规则。规则的集合分两类:Exploration Set 用于Exploration的规则;Implementation Set 用于Implementation的规则。
每个操作符,都存有自己需要的规则ID构成的规则的子集,这里面包括了逻辑变换和实现变换的规则。

  • Exploration阶段,拿操作符的规则集和逻辑变换集合取与,得到操作符这个阶段需要的规则
  • Implementation阶段,拿操作符的规则集和实现变换集合取与,得到操作符这个阶段需要的规则集

    GPORCA通过规则工程管理规则集,包括Exploration和Implementation。上图中,0和1有8列,表示规则集。为了简单,我们假设CLogicalGet需要的规则ID是4。LogicalGet所在的行,左边的规则集记录了LogicalGet需要的规则。可以看到第四位被设置为1,可以知道LogicalGet需要ID为4的规则进行转换。Exploration所在的行的规则集,表示所有的规则的集合。5,6,7,8位被设置为1,所以Exploration的规则集是ID为{5,6,7,8}的规则集。同样的,Implementation的规则集为{1,2,3,4}

规则匹配:Exploration优化阶段,LogicalGet和Exploration的规则集取与的结果为空集,所以直接跳过;Implementation阶段,取与的结果是4,是CXformGet2TableScan的ID,所以应用这个规则

EevtFinalize

在EevtFinalize状态下执行的函数EevtFinalize很简单,仅仅是将m_pgexpr状态改为了CGroupExpression::estExplored

CJobGroupExpressionExploration::EEvent CJobGroupExpressionExploration::EevtFinalize(CSchedulerContext *, CJob *pjOwner){	
	CJobGroupExpressionExploration *pjgee = PjConvert(pjOwner); // get a job pointer
	pjgee->m_pgexpr->SetState(CGroupExpression::estExplored);
	return eevFinalized;
}

CJobGroupExpression类

CJobGroupExpression类作为Abstract superclass of all group expression optimization jobs,主要包含3个成员变量,即BOOL m_fChildrenScheduledBOOL m_fXformsScheduledCGroupExpression *m_pgexpr。CJobGroupExpression类实际就实现了如下两个函数,其中最重要的是ScheduleTransformations函数,该函数会遍历形参xform_set中的ExformId,并通过CXformFactory获取对应的CXform,最终使用CJobTransformation::ScheduleJob函数创建新Transformation任务。

//---------------------------------------------------------------------------
//	@function:
//		CJobGroupExpression::Init
//	@doc:
//		Initialize job
//---------------------------------------------------------------------------
void CJobGroupExpression::Init(CGroupExpression *pgexpr) {
	m_fChildrenScheduled = false; m_fXformsScheduled = false;
	m_pgexpr = pgexpr;
}
//---------------------------------------------------------------------------
//	@function:
//		CJobGroupExpression::ScheduleTransformations
//	@doc:
//		Schedule transformation jobs for the given set of xforms
//---------------------------------------------------------------------------
void CJobGroupExpression::ScheduleTransformations(CSchedulerContext *psc, CXformSet *xform_set){
	// iterate on xforms
	CXformSetIter xsi(*(xform_set));
	while (xsi.Advance()){
		CXform *pxform = CXformFactory::Pxff()->Pxf(xsi.TBit());
		CJobTransformation::ScheduleJob(psc, m_pgexpr, pxform, this);
	}
}

Exploration(主要负责推导等价的逻辑表达式)和Implementation(主要负责把逻辑表达式转化为物理表达式)都是把一个表达式,转换为另一个等价的表达式,统称为Transformation;转换是基于规则进行的,称为基于规则的优化(Role Based Optimization,RBO)。因此CJobGroupExpressionExploration和CJobGroupExpressionImplementation类都会生成CJobTransformation任务。

ORCA优化器浅析——CJobGroupExpressionExploration探究_microsoft_04


ORCA优化器浅析——CJobGroupExpressionExploration探究_Group_05