【发布时间】:2014-08-03 23:41:21
【问题描述】:
我编写的搜索功能的速度有问题。功能步骤如下:
- 函数以两个表名参数开始,一个起点和一个目标
- 然后该函数遍历表列组合列表(50,000 长)并检索与起始点表关联的所有组合。
- 然后该函数循环遍历每个检索到的组合,并且对于每个组合,它再次遍历表列组合列表,但这次查找与给定列匹配的表。
- 最后,函数循环遍历从上一步检索到的每个组合,并针对每个组合检查表是否与目标表相同;如果是,它会保存它,如果不是,它会调用自己,并从该组合中传入表名。
该功能的目的是能够跟踪表之间的链接,其中链接是直接的或具有多个分离度。递归级别是一个固定的整数值。
我的问题是,每当我尝试为两个级别的搜索深度运行此函数(现阶段不敢尝试更深入)时,作业都会耗尽内存,或者我失去耐心。我等了 17 分钟,然后作业内存不足一次。
每张表的平均列数为 28,标准差为 34。
这是一个图表,显示了可以在表之间建立的各种链接的示例:
这是我的代码:
private void FindLinkingTables(List<TableColumns> sourceList, TableSearchNode parentNode, string targetTable, int maxSearchDepth)
{
if (parentNode.Level < maxSearchDepth)
{
IEnumerable<string> tableColumns = sourceList.Where(x => x.Table.Equals(parentNode.Table)).Select(x => x.Column);
foreach (string sourceColumn in tableColumns)
{
string shortName = sourceColumn.Substring(1);
IEnumerable<TableSearchNode> tables = sourceList.Where(
x => x.Column.Substring(1).Equals(shortName) && !x.Table.Equals(parentNode.Table) && !parentNode.Ancenstory.Contains(x.Table)).Select(
x => new TableSearchNode { Table = x.Table, Column = x.Column, Level = parentNode.Level + 1 });
foreach (TableSearchNode table in tables)
{
parentNode.AddChildNode(sourceColumn, table);
if (!table.Table.Equals(targetTable))
{
FindLinkingTables(sourceList, table, targetTable, maxSearchDepth);
}
else
{
table.NotifySeachResult(true);
}
}
}
}
}
编辑:分离出 TableSearchNode 逻辑并添加属性和方法以确保完整性
//TableSearchNode
public Dictionary<string, List<TableSearchNode>> Children { get; private set; }
//TableSearchNode
public List<string> Ancenstory
{
get
{
Stack<string> ancestory = new Stack<string>();
TableSearchNode ancestor = ParentNode;
while (ancestor != null)
{
ancestory.Push(ancestor.tbl);
ancestor = ancestor.ParentNode;
}
return ancestory.ToList();
}
}
//TableSearchNode
public void AddChildNode(string referenceColumn, TableSearchNode childNode)
{
childNode.ParentNode = this;
List<TableSearchNode> relatedTables = null;
Children.TryGetValue(referenceColumn, out relatedTables);
if (relatedTables == null)
{
relatedTables = new List<TableSearchNode>();
Children.Add(referenceColumn, relatedTables);
}
relatedTables.Add(childNode);
}
提前感谢您的帮助!
【问题讨论】:
-
这可能会有所帮助,如果我没记错的话,尾部调用不会淹没堆栈——但我可能大错特错。 blogs.msdn.com/b/clrcodegeneration/archive/2009/05/11/…(免责声明 - 我是商科专业的)
-
我正在更详细地研究这一点,但有一条评论是,如果性能是一个大问题,您可能需要考虑删除所有 LINQ 调用。
-
@nicholas 出于兴趣,您从哪里读到过 LINQ 必然比替代方案慢?
-
@EricScherrer 非常感谢您提供的链接。不幸的是,因为每个函数都可以在一个循环中多次调用自己,我发现我无法模仿这些示例; 然而,我将
if (!table.Table.Equals(targetTable))更改为if (table.Table.Equals(targetTable))并交换了内部语句,因此递归调用是最后一个语句。我不确定这在执行时如何转化。如果你有更好的方法,请告诉我。顺便说一句,我已经在所有可能的方面都犯了可怕的错误(进程吃了 1.5gb 的 RAM),所以别担心 :) -
您正在浪费时间以所有这些小方法优化代码。您将获得持续的加速,但即使是 10 倍也无济于事。您需要一种具有较低渐近成本的全新算法。
标签: c# linq search recursion tree