12

我有一个 asp.net-mvc 网站,人们管理着一个项目列表。基于某种算法,我可以判断一个项目是否过时。当用户登录时,我希望它显示陈旧项目的数量(类似于我在收件箱中看到许多更新时)。

计算陈旧项目的算法有点慢,所以如果每次用户登录,我必须:

  1. 对他们是所有者的所有项目运行查询
  2. 运行 IsStale() 算法
  3. 显示 IsStale = true 的计数

我的猜测是这会很慢。此外,在所有项目编写时,我都必须重新计算上述内容以查看是否更改。

我的另一个想法是创建一个表并在几分钟内运行一个作业来计算陈旧的项目并将最新的计数存储在这个指标表中。然后在用户登录时查询。问题是我仍然必须保持该表同步,如果它每分钟只重新计算一次,如果人们更新项目,它不会在一分钟后改变值。

有什么想法可以用一种快速、可扩展的方式来支持这个收件箱概念,以提醒用户要查看的项目数量吗?

4

5 回答 5

10

第一步始终是正确的需求分析。假设我是项目经理。我登录到系统,它将我唯一的项目显示为准时。一位开发人员来到我的办公室,告诉我他的活动有延迟。我选择开发人员的活动并更改其持续时间。系统仍然显示我的项目准时,所以我很高兴地离开了工作。

如果我在凌晨 3:00 接到客户的电话,要求我解释为什么项目不再准时,您认为我会有什么感觉?显然,很惊讶,因为系统并没有以任何方式警告我。为什么会这样?因为我必须等待 30 秒(为什么不只等待 1 秒?)才能让下一次运行计划作业来更新项目状态。

那不可能是一个解决方案。即使运行该IsStale()过程需要 30 秒,也必须立即向用户发送警告。向用户显示loading...图像或其他任何内容,但要确保用户拥有准确的数据。

现在,关于实施,没有什么可以逃避上一个问题:当影响某些到期日期的事情发生变化时,您将不得不运行该过程。但是,您可以做的不是不必要地运行该过程。例如,您提到您可以在用户登录时运行它。如果 2 个或更多用户登录并看到同一个项目并且没有更改任何内容怎么办?没有必要运行该过程两次。

更重要的是,如果您确保在用户更新项目时运行该流程,您将不需要在任何其他时间运行该流程。综上所述,与“轮询”方案相比,这种模式有以下优点和缺点:

优点

  • 没有预定的工作
  • 没有不需要的进程运行(这是有争议的,因为您可以dirty在项目上设置一个标志,并且只有在它是时才运行它true
  • 没有不需要的dirty值查询
  • 用户将始终被告知项目的当前和真实状态(这是迄今为止在所提供的任何解决方案中要解决的最重要的项目)

缺点

  • 如果用户更新了一个项目,然后在几秒钟内再次对其进行更新,则该进程将运行两次(在轮询模式中,该进程甚至可能不会在该期间运行一次,具体取决于它已安排的频率)
  • 更新项目的用户将不得不等待该过程完成

更改为以与 StackOverflow 类似的方式实现通知系统的方式,这是一个完全不同的问题。我猜您与用户和项目之间存在多对多的关系。最简单的解决方案是将单个属性添加到这些实体之间的关系(中间表):

基数:一个用户有很多项目。一个项目有很多用户

这样,当您运行该过程时,您应该Has_pending_notifications使用新结果更新每个用户。例如,如果用户更新了一个项目并且它不再准时,那么您应该设置为true所有用户Has_pending_notifications字段,以便他们了解情况。同样,将其设置为false项目准时(我知道您只是想确保在项目不再准时时显示通知

以 StackOverflow 为例,当用户阅读通知时,您应该将标志设置为false. 确保您不使用时间戳来猜测用户是否已阅读通知:登录并不意味着阅读通知

最后,如果通知本身足够复杂,您可以将其从用户和项目之间的关系中移开,并采用如下方式:

基数:一个用户有很多项目。一个项目有很多用户。一个用户有很多通知。通知有一个用户。一个项目有很多通知。通知有一个项目。

我希望我说的有些道理,或者给你一些更好的主意:)

于 2012-03-15T22:58:59.710 回答
6

您可以执行以下操作:

  1. 为每个用户记录添加一个日期时间字段,表示上次完成慢速计算的时间。称之为LastDate
  2. 为每个项目添加一个布尔值来表示是否必须列出它。称呼它:已选择
  3. 当您运行慢程序集时,您会更新选定的文件
  4. 现在,当用户登录LastDate是否足够接近现在时,您将使用最后一次慢速计算的结果,并且只需将所有项目选择为true。否则你会再次缓慢计算。上述过程是最佳的,因为它仅在实际需要时才重新计算缓慢的过程,同时以固定的时间间隔运行过程......有浪费时间的风险,因为用户可能不会使用计算结果。
于 2012-03-14T19:46:32.670 回答
3

使字段“陈旧”。运行一条 SQL 语句,使用 stale=0 AND 的所有记录更新 stale=1(该算法返回 true)。然后运行一条 SQL 语句,选择 stale=1 的所有记录。

这将快速工作的原因是因为 SQL 解析器,如 PHP,如果前半部分返回 true,则不应执行 AND 语句的后半部分,从而使其非常快速地遍历整个列表,检查所有记录,尝试如果还没有过时,就让它们过时。如果它已经过时,则不会执行该算法,从而节省您的时间。如果不是,则运行算法以查看它是否已过时,然后将 stale 设置为 1。

然后,第二个查询只返回 stale=1 的所有过时记录。

于 2012-03-12T04:48:03.767 回答
0

你可以这样做:

每次用户访问项目时,在数据库中更改时间戳。当用户登录时,拉取他们所有的项目。检查时间戳并将其与今天的日期进行比较,如果它早于 n 天,则将其添加到过时列表中。我不相信比较日期会导致任何缓慢的逻辑。

于 2012-03-12T04:48:10.970 回答
0

我认为在考虑数据库和代码之前需要解决基本问题。其中最主要的是:“为什么 IsStale() 很慢?”

从其他地方的评论中可以清楚地看出,这很慢的概念是不可协商的。这个计算不在你的掌控范围内吗?结果对缓存有抵抗力吗?什么级别的变化会触发重新计算。

过去编写了调度系统,有两种类型的更改:可能发生在松弛范围内的更改和导致级联调度更改的更改。同样,有两种类型的重建:全部重建和本地重建。完全重建是显而易见的;本地重建会尽量减少对其他预定资源的“损害”。

这是问题的症结所在:如果您在每次更新时都进行完全重建,那么您可能会看到从更改时间到计划稳定时间的 30 分钟延迟。(我的经验是基于我对 ERP 系统重建时间的经验以及非常复杂的工作量)。

如果您的系统的实际情况是此类任务需要 30 分钟,那么为您的用户设定即时满足的设计目标与事情的基本事实背道而驰。但是,您可能能够比重建更快地检测到调度不一致。在这种情况下,您可以向用户显示“计划已超限,重新计算新的结束时间”或类似的东西......但我怀疑如果您有很多不同用户同时输入的计划更改,系统会降级连续显示该通知。但是,您至少获得了一个优势,即您可以在一段时间内为下一次重建批量更改发生。

正是由于这个原因,我看到的大多数调度问题实际上并没有进行实时重新计算。在 ERP 情况下,有一个调度主管负责车间的调度,任何更改都会通过他们汇集。“主”计划在每个班次之前重新生成(班次为 12 小时,因此每天两次),并且在班次期间,通过“本地”修改来处理延迟,直到下一个 12 小时块才改变主计划。

在更简单的情况下(软件设计),计划每天更新一次以响应当天的进度报告。第二天早上的 Scrum 中传来了坏消息以及更新的日程安排。

长话短说,我在想也许这是一个“未提出问题”的时刻,需要对假设提出挑战。如果重新计算足够大以至于连续更新是不切实际的,那么将期望与现实保持一致就可以了。要么算法需要工作(针对局部变化进行优化),要么硬件场需要扩展,要么需要重新校准对“真相”的预期时间。

坦率地说,一个更精确的答案需要更多的细节,而不是“仅仅假设一个昂贵的过程”,因为不可能知道对该过程的正确攻击点。

于 2012-03-21T17:12:19.333 回答