【问题标题】:.Net Persisting Large Lists and Keeping data up to date in near realtime.Net 持久性大列表和近乎实时地保持数据最新
【发布时间】:2011-01-24 17:57:42
【问题描述】:

好的,请稍等,因为这有很多层次,尽管阅读所有这些内容可能需要一些时间,但我认为我们所有人提出的答案将对整个社区非常有用。话虽如此,让我设置问题:

我有一个 C# .Net 桌面应用程序(Windows 窗体,但我认为它也可以是 WPF),它是一个销售订单输入和管理系统。我遇到的问题是我需要在应用程序中使用的最重要的数据列表之一相当大(大约 15k 条记录,并且还在增长)并且不断变化,我想保留列表内存与数据库同步,而不是每 2 秒或其他时间轮询数据库。该应用程序也不是单实例,因此应用程序需要的所有这些列表都从数据库中带入内存,并在每个实例中保存一次。

好的,既然你已经看到了困境,让我们看看我们是否能想出一个解决方案。

我的想法:

如果我们能够使用 .NET 4.0(我可以),我认为在内存中只保留一组数据的答案是使用内存映射文件。虽然从表面上看是本垒打,但管理起来要复杂得多,而且可能有点矫枉过正。想法?

为了将数据库中的数据负载保持在最低限度,我正在考虑将各种列表保存到用户 PC 上某个特殊文件夹中的 XML 文本文件中,然后使用一个最终的 XML 文件来跟踪 XML 文件和他们的日期。在应用程序启动时,执行对数据库的单个调用,获取表/列表的列表以及每个的“最后更新日期”。对于具有相同上次更新日期的每个 XML 文件,我可以从 XML 文件加载而不是查询数据库。至于过期的列表,我可以查询自拥有日期以来的更改,然后加载 XML 文件,然后提交更改。这样,我不得不等待的唯一更改很可能是来自更频繁更新的列表的更改,而不是所有表/列表。好吧,我承认我不是最擅长解释事物,但我认为您应该能够将其形象化。

至于实时保持最新状态,我正在考虑使用插入和更新触发器(不会发生删除)来调用 SP,这就是我有点模糊的地方,以某种方式传递插入的/updated 信息到应用程序订阅的 WCF 服务,并通过 WCF 回调将更新推送到客户端。现在我认为这应该一切正常,但是,例如,这不会导致应用程序的 3 个实例同时更新内存中的相同变化吗? WCF 服务是否只能将更新发送到每台客户端 PC 的一个实例?能区分吗?

提前感谢您对此提出的任何想法、意见和意见。我将保留“奖励”一个答案至少 48 小时,因为我想让每个人都有机会投入 2 美分,让这个线程对未来更有用...

【问题讨论】:

  • 缓存在你的 wcf 服务层吗?
  • 请告诉我“15k”和“ComboBox”是不同的东西。
  • 您应该能够使用 WCF 的 net-tcp 绑定让服务器向连接的客户端推送有关表更新的更改通知,这至少可以解决您的轮询问题。应用程序的不同实例应该有自己的内存中数据副本和自己的 WCF 连接,因此在您尝试持久化之前应该没问题。
  • @Tridus - 我会看看你在说什么,但假设我有几个列表,15k 一个是最大的,但其他的更短但有 mor 列。当用户还打开了 Outlook 和其他一些东西时,拥有 3 到 4 个实例,每个实例都有自己的集合,不会很容易使只有 2 或 3 GB 内存的 PC 拥塞吗?
  • @Wonko the Sane - 更多地将其视为自动完成而不是 DropDownList。用户键入大部分名称或 id,如果内置自动完成逻辑未找到匹配项,则代码隐藏会进行匹配...另外,请记住数据绑定是虚拟化的。

标签: c# .net sql wpf wcf


【解决方案1】:

我看不到将数据库保存在内存中的好处。数据库的意义在于成为一个数据库。

您将不得不在您的应用程序中重现多用户数据库功能。

这似乎是一个没有胜利的提议。把它留给微软。而是制作一个使用 sql server 的所有功能的 n 层应用程序。然后,当您有一个可用的测试版时,寻找应用程序中运行缓慢并从那里移动的部分。

【讨论】:

  • 它已经在工作了,我只是想让它比今天更有效率。我不想将数据库持久化在应用程序的内存中,只是一个客户对象列表(例如(int id,字符串名称)),用于组合框和其他查找需求。
  • 你已经让它作为一个 n 层工作,但是下拉很慢,因为它们必须从数据库中读取很多东西?
  • 不,下拉菜单很快,因为我正在使用虚拟化数据的控件。它绑定可见的项目,但将滚动条设置为满时的数量。虚拟化控件可以在明显减速之前处理数百万条记录。
  • 虚拟化数据听起来不错。那么究竟是什么问题。您是否担心用户查看页面时数据会发生变化?
  • 部分。更有可能将客户添加到系统中并分配给代表,然后通过电话或电子邮件告知他们可能就在其中,当然代表希望立即进行更改。同样,客户的数据更改...
【解决方案2】:

实现这一目标的一种方法,也许是最好的方法是通过日记。

要实现这一点,请将日志表与您需要在每个客户端上保持更新的数据库表相关联。该表的主键是时间戳。每当任何客户端在(例如)客户表中更新或插入一行时,它也会在日志表中添加一行,指示已添加或更新的客户的主键。

然后每个客户端都可以通过查询日志表找到更改列表,找到主键大于或等于客户端上次查询(客户端跟踪)的时间戳的所有行。对客户表的简单连接获取所有新的和更新的行。然后,客户端将这些行合并到其客户表的本地副本中。

您说您不想每 2 秒或其他任何时间访问数据库。对此的三个想法。

首先,原型应该足够简单,并确定是否每 2 秒访问一次数据库实际上是您需要解决的问题。

第二次:每 2 秒一次?在我看来,这听起来像是一种由对魔法的信念驱动的需求,而不是由实际的业务需求驱动的需求。而如果是业务需求驱动的话,我会担心更深层次的问题,比如:假设用户执行一个涉及客户的交易需要超过 2 秒,如果在交易过程中客户行发生变化会发生什么?

最后:即使您最终确实需要实现广播模型,广播的起点也将是需要发送给客户端的项目的工作队列。日记是一个很好的起点。

Protip:不要忘记实施从日记帐表中清除旧条目的日终流程。

【讨论】:

  • 采用广播方式与内存映射文件相结合会不会导致客户端PC上的网络利用率和内存使用率最低?将更改实时推送给客户会带来更多可能性吗?总的来说,如果触发广播方法的触发器以某种方式失败,我同意你的日记方法。
【解决方案3】:

我的程序有类似的需求,但我的解决方案是构建延迟加载数据库对象的类(因为它们是需要的),甚至部分用于一些更重要和更大的项目(只是主键和开头的名字)。然后,每当我正在查看的数据库项未初始化(只是 PK 和名称)或仍然为空时,我都会转到数据库并急切地加载该对象和其他几个同类对象。

如果你有一个包含 15k 项的 UI 元素,那么你的程序将几乎无法被人类使用(也可能根本不显示任何内容,只将其保存在列表中)。您应该考虑使用搜索对话框或类似的东西。

【讨论】:

  • 我使用虚拟化列表的控件,因此整个列表永远不会一次真正绑定......我目前正在做类似你的事情,但我不得不经常检查变化,如果所有客户端都在检查,那么糟糕......
  • 那么你应该重新考虑你的应用程序的设计。您的用户可以使用数据的子集吗? (那样他们也会更有效率)
  • 有些用户需要这一切,但大多数只是获得“他们的”客户。例如,如果客户总数为 15k,则给定的销售代表可能只能获得 250~300 个分配的客户,而高管将看到所有客户。此外,所有用户都可以查看基本信息并搜索任何客户。
  • 大约 75 个活跃用户和 15~20 个不经常使用的用户。我现在担心的是服务器和客户端 PC 硬件不太好,在升级之前我想找到最好的方法来做到这一点。
  • 系统在处理过时信息方面的弹性如何?在会话期间一段数据更改的频率如何?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-15
  • 2012-03-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多