我最近开始使用WPF应用程序。我将它连接到BaseX(基于XML)的数据库,并从中检索了大约一百万个条目。我想迭代条目,为每个条目计算一些东西,然后将其写回数据库:
IEnumerable<Result> resultSet = baseXClient.Query("...", "database");
foreach (Result result in resultSet)
{
...
}
问题:从未到达foreach的内部。 Query()方法返回得非常快,但是当到达foreach时,C#似乎对集合进行了SOMETHING,代码不会持续很长时间(至少10分钟,永远不会让它再运行)。 这里发生了什么? 我试图限制检索的项目数量。检索100.000结果时,会发生相同的事情,但代码会在大约10-20秒后继续。在检索完整的一百万个结果时,C#似乎永远被卡住了......
有什么想法吗? 问候
编辑:为什么会发生这种情况
正如你们中的一些人所指出的,这种行为的原因似乎是查询实际上仅在调用Enumerable中的Enumerator上的MoveNext()
时进行评估。我的数据库似乎无法一次返回一个值,而是一次返回整个一百万个数据集。我将尝试切换到另一个数据库(Apache Lucene,如果可能的话,因为它具有良好的全文搜索支持)并编辑此帖子以告知您是否更改了任何内容。
PS:是的,我知道有一百万个结果很多。这不是用于实时使用,它只是准备数据的一个步骤。虽然我没想到代码会在几秒钟内运行,但我仍然对数据库中的性能不佳感到惊讶。
编辑:解决方案所以我将XML数据库迁移到了Apache Lucine。奇迹般有效!当然Lucine是一个基于文本的数据库,不适合每个用例,但对我来说它创造了奇迹。可以在几秒钟内迭代超过一百万个条目,每个循环获取一个条目 - 工作得非常好!
答案 0 :(得分:5)
让我猜一下 - 你在创建rsultSet时没有加载数据,但是当它第一次被访问(延迟执行),加载一百万个条目时,你只需要花很多时间将它们反序列化到内存中。
欢迎使用XML数据库的低效率。
答案 1 :(得分:3)
一百万的东西都很多......所以任何获得那么多项目的操作都需要花费大量的时间。它看起来像你使用的库不会延迟检索项目,直到它是绝对必要的 - 所以你看到所有项目隐藏在“foreach”声明背后的影响。
会发生什么:
“foreach”不是单个操作,而是对IEnumerable和IEnumerator的几次调用:IEnumerable.GetEnumerator,重复调用IEnumerator.MoveNext。
第一次调用GetEnumerator
可以通过延迟执行(最常见的LINQ查询编写方式)或立即执行(这似乎是您的集合的情况)来实现。
调用MoveNext也可以触发立即执行整个查询,即使您只询问单个项目或每个调用只能获得单个项目。即大多数LINQ查询只从迭代器中获取一个下一项。
答案 2 :(得分:2)
这里的答案都指出了你对foreach(延迟执行)感知问题的原因,而不是可能的解决方案。我不确定这个数据库是否支持它,但是一个解决方案可能是尝试以较小的批量分页结果,而不是一次获取整个数据块。
另一种方法是编写一个执行必要计算的数据库查询,这样您的数据库就不需要在任何地方发送100万条记录。 (同样,不确定这个数据库是否支持)
答案 3 :(得分:0)
要强制在foreach之前计算查询,请调用resultSet上的ToList函数。 (如果问题是数据库永远存在,不会解决您的问题)
答案 4 :(得分:-1)
您是否尝试过更传统的for循环来查看是否可行?
IEnumerable<Result> resultSet = baseXClient.Query("...", "database");
for (int x =0; x < resultSet.Count; x++)
{
Result result = resultSet[x];
...
}