我正在玩一個基本的表達式樹優化器來構建查詢計劃。在解析樹時,我可以根據我可以分配給每個操作的權重來決定如何構建它。詳盡搜索/生成表達式樹的每個組合
如果我有一個簡單的樹,有2個關於如何執行動作的選擇,我希望能夠生成樹的兩個變體,然後可以比較每個的權重以查看哪些是最高效。
例如,下面的代碼會允許我來構建表達式樹的兩個變化加入操作:一個帶有MergeJoinExpression
,一個具有NestedLoopJoinExpression
class Customer
{
public int Id { get; set; }
}
class Orders
{
public int Id { get; set; }
public int CustomerId { get; set; }
}
class MergeJoinExpresion : JoinExpression
{
}
class NestLoopJoinExpresion : JoinExpression
{
}
class Visitor : ExpressionVisitor
{
public List<Expression> GetPlans(Expression expr)
{
// ???
}
override VisitJoin(JoinExpression join)
{
// For this join, I can return the following (trite example)
// return MergeJoinExpresion
// return NestLoopJoinExpresion
return base.VisitJoin(join);
}
}
我如何構建,將產生每個方法樹的變種並將它們還給我?
class Program
{
static void Main(string[] args)
{
var query = from c in customers
join o in orders on c.Id equals o.CustomerId
select new
{
CustomerId = c.Id,
OrderId = o.Id
};
var plans = new Visitor().GetPlans(query);
}
}
誰能告訴我怎樣才能修改Visitor
GetPlans
類的方法來產生這些變化?
編輯 - 是這樣的:
class Visitor : ExpressionVisitor
{
private List<Expression> exprs = new List<Expression>();
public List<Expression> GetPlans(Expression expr)
{
Visit(expr);
return exprs;
}
override VisitJoin(JoinExpression join)
{
// For this join, I can return the following (trite example)
// return MergeJoinExpresion
// return NestLoopJoinExpresion
var choices = new Expression[] { MergeJoinExpresion.Create(join), NestLoopJoinExpresion.Create(join) };
foreach(var choice in choices)
{
var cloned = Cloner.Clone(choice);
var newTree = base.VisitJoin(cloned);
exprs.Add(newTree);
}
return base.VisitJoin(join);
}
}
不確定訪問者是否是最好的方式。 VisitJoin必須返回它生成的多個變體。所有呼叫者必須支持多種變體,並且他們自己可能會生成多種變體無論如何,加入計劃通常不是以這種簡單的窮舉方式完成的,因爲時間複雜性將呈指數級增長。 – usr
這個連接只是我能想到的一個非常簡單的例子中最簡單的例子。我使用表達式樹來生成不同的計劃 - 並且需要一種生成每個可能結果的方法(無論它是用於Join還是別的)。所以問題是如何生成不同版本的樹,可以在生成期間生成訪問節點。這是我可以仔細檢查,我選擇的查詢計劃是最好的,通過檢查一個詳盡的搜索... – Jack
我想你可以使它的工作,如果你讓訪問者的方法返回IEnumerable而不是表達式。 –
usr