5

我最近启动了一个 WPF 应用程序。我将它连接到 BaseX(基于 XML)数据库并从中检索到大约一百万个条目。我想遍历条目,为每个条目计算一些东西,然后将其写回数据库:

IEnumerable<Result> resultSet = baseXClient.Query("...", "database");
foreach (Result result in resultSet) 
{
    ...
}

问题:永远无法到达 foreach 的内部。Query() 方法返回的速度非常快,但是当达到 foreach 时,C# 似乎对集合做了一些事情,代码不会持续很长时间(至少 10 分钟,永远不要让它再运行)。这里发生了什么?我试图限制检索到的项目数量。当检索 100.000 个结果时,会发生同样的事情,但代码会在大约 10-20 秒后继续。当检索完整的一百万个结果时,C# 似乎永远卡住了......

有任何想法吗?问候

编辑:为什么会发生这种情况 正如你们中的一些人指出的那样,这种行为的原因似乎是查询实际上只在MoveNext()调用 Enumerable 内的 Enumerator 时才被评估。我的数据库似乎无法一次返回一个值,而是一次返回整个一百万个数据集。我将尝试切换到另一个数据库(Apache Lucene,如果可能的话,因为它有很好的全文搜索支持)并编辑这篇文章,让你知道它是否改变了任何东西。
PS:是的,我知道一百万个结果很多。这并不意味着实时使用,它只是准备数据的一个步骤。虽然我没想到代码会在几秒钟内运行,但看到数据库中的性能如此糟糕,我仍然感到惊讶。

编辑:解决方案所以我将 XML 数据库迁移到 Apache Lucine。奇迹般有效!当然,Lucine 是一个基于文本的数据库,它并不适合所有用例,但对我来说它创造了奇迹。可以在几秒钟内迭代超过一百万个条目,每个循环获取一个条目 - 效果非常好!

4

5 回答 5

5

让我问一下 - 创建 rsultSet 时您不会加载数据,而是在首次访问它时(延迟执行),并加载一百万个条目时,您只需花费大量时间将它们反序列化到内存中。

欢迎来到 XML 数据库的低效率。

于 2012-07-02T18:50:22.250 回答
3

一百万的任何东西都很多......所以任何获得这么多项目的操作都需要花费大量时间。看起来您使用的库不会推迟检索项目,直到绝对必要 - 所以您会看到将所有项目隐藏在“foreach”语句后面的影响。

发生什么了:

“foreach”不是单个操作,而是对 IEnumerable 和 IEnumerator 的多次调用:IEnumerable.GetEnumerator,重复调用 IEnumerator.MoveNext。

第一次调用GetEnumerator可以通过延迟执行(编写 LINQ 查询的最常见方式)或立即执行(您的集合似乎就是这种情况)来实现。

对 MoveNext 的调用也可以触发整个查询的立即执行,即使您只要求单个项目,或者每个调用都只能获得单个项目。即,大多数 LINQ 查询只从迭代器中获取下一项。

于 2012-07-02T19:00:33.917 回答
2

这里的答案都指向您感知到的 foreach 问题(延迟执行)的原因,而不是可能的解决方案。我不确定这个数据库是否支持它,但一种解决方案可能是尝试以较小的批次对结果进行分页,而不是一次获取整个数据块。

另一种方法是编写一个执行必要计算的数据库查询,这样您的数据库就不需要在任何地方发送 100 万条记录。(同样,不确定这个数据库是否支持)

于 2012-07-02T19:21:02.103 回答
0

要强制在 foreach 之前评估查询,请在结果集上调用 ToList 函数。(如果问题是数据库永远占用,则不会解决您的问题)

于 2012-07-02T18:51:06.323 回答
-1

您是否尝试过更传统的 for 循环来查看是否可行?

IEnumerable<Result> resultSet = baseXClient.Query("...", "database");
for (int x =0; x < resultSet.Count; x++)
{
    Result result = resultSet[x];
    ...
}
于 2012-07-02T18:49:47.983 回答