【问题标题】:Fast, in-memory range lookup against +5M record table针对 +5M 记录表的快速内存范围查找
【发布时间】:2013-02-22 03:21:25
【问题描述】:

我有一个包含 +5M 静态记录的数据库表。简单结构:(开始 int,结束 int,结果 int)。所以我有一个特定的INT,我需要找到它对应的结果(int)。目前,查找表在数据库中,但它需要驻留在内存中,很可能在没有数据库访问权限的环境中。

我的解决方案需要在没有数据库访问的情况下在内存中执行此逻辑并且速度超快,因为我需要每秒处理 1000 次事务。该集合的大小略高于 50MB,因此我可以将整个内容放入内存并针对它运行范围查找,根据这篇文章:Doing a range lookup in C# - how to implement。但我不知道它会在这样的规模上表现如何。

  • 我是否在“启动时”预加载该表?它可能需要一段时间。
  • 有什么方法可以将表加载到某个 .dat 文件中并在运行时进行高效查找?

顺便说一句,我在 Azure 上,不确定使用存储表是否有助于查找...

【问题讨论】:

  • "我有一个数据库表" .. "但是我的解决方案需要在没有数据库访问权限的情况下执行这个逻辑" - 那么这些数据是如何进入内存的呢?你读过数据库,对吧?
  • 将它全部加载到内存中将是最快的。一切都取决于数据是否在变化。然后管理保存回数据库变得有点棘手,但如果它没有改变,那么只需缓存到内存中
  • @Keith:不一定。数据库有索引....
  • @MitchWheat - 抱歉,应该更清楚。目前,查找表在 DB 中,但它需要驻留在内存中,很可能在没有数据库访问权限的环境中。
  • 这仍然没有什么意义...要首先进入内存,您必须从某个地方读取它。

标签: c# performance azure lookup-tables


【解决方案1】:

您链接到的范围查找代码执行二进制搜索,因此性能将为O(log n)。我认为对于范围查找,您不能做得比这更好。 HashSet<T> 的查找时间为 O(1),但您不能使用该结构进行范围查找。

500 万条记录并不是一个巨大的数字。我建议您使用链接到您将在生产中使用的硬件上的代码来实现概念验证,并测量性能。

【讨论】:

  • 内存数据库呢?搜索会比二分搜索更快吗?或者使用什么搜索算法?
  • @Saurabh:任何内存数据库都会在数据之上提供一个抽象层来处理查询语义。与旨在很好地处理一个非常具体的查询的数据结构相比,总会有一些性能损失。如果性能是最重要的,那么 OP 的二进制搜索方法将比内存中的通用数据库更快。
  • 你知道BigOh的区别是多少
  • 谢谢 Eric,你建议我如何快速将该文件加载到 Range[] 中?
  • @enlightenedOne:您可以使用 ADO.Net 从表中选择数据并为每行创建一个 Range
【解决方案2】:

二分搜索非常快。对 50M 条记录进行二分搜索只需 27 次比较即可找到答案。只需将其加载到内存中并使用您链接的范围查找。

如果你发现它很慢,开始优化:

  • 将 Range 对象更改为 struct 而不是 class
  • 手动编写您自己的二进制搜索算法,该算法 (a) 直接实现相等比较器,而不是调用 IEqualityComparer,并且 (b) 在执行搜索时使用指针和其他不安全的技巧来禁用数组边界检查。

【讨论】:

  • 在搜索过程中,您可以避免跟随指向堆上 Range 对象的指针。这是一个公认的非常小的性能。改进。
  • Ummmm ... 2^17 只有 128K。 5000 万只需要 27 个探测器。
  • Range 结构的数组仍将存储在堆中。 stackoverflow.com/questions/1113819/…
  • 当然。一个访问数组的指针......然后你就有了你的结构。作为 ref 对象,它将是访问数组的 1 个指针......这为您提供了访问该位置的 ref 对象的第二个指针。
【解决方案3】:

您当然可以将它放在一个顺序文件中并在启动时加载它。 50 MB 将在不到一秒的时间内从磁盘中取出。即使您必须将其解析为文本文件,您也应该能够在另一秒钟内创建表格。当您使用 2 GHz(或更快)的处理器处理它们时,500 万条记录并没有那么大。

列表的二进制搜索是 O(log n),因此每次搜索最多可以进行 24 次探测。这将是非常快的。

加载测试这样的东西应该很容易。只需启动它,然后查看执行 1,000,000 次查找需要多长时间。比如:

var clock = Stopwatch.StartNew();
for (int i = 0; i < NumIterations; ++i)
{
    int val = GetRandomValueToSearchFor(); // however you do that
    Ranges.BinarySearch(val, RangeComparer);
}
clock.Stop();
// time per iteration is clock.TotalMilliseconds/NumIterations

这会让您找出查询该事物的绝对最快速度。我怀疑每秒处理数千笔交易不会有问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-29
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多