【问题标题】:Doing DB Queries Verus Storing Items in A collection?做数据库查询 Verus 在集合中存储项目?
【发布时间】:2011-08-22 15:25:12
【问题描述】:

我正在尝试制作一个提醒系统,并且我正在使用石英进行日程安排。但是我想出了几种可能的方法来做我需要做的事情,但我不确定最好的方法是什么以及如何测试它。

基本上我有一个提醒系统,用户可以设置提醒。它就像谷歌日历。您设置活动的日期和时间,然后通过说“提前 15 分钟提醒我”来设置提醒

所以你可以在 2011 年 5 月 10 日上午 9:59 举办一个活动,你可以说提醒我“15 分钟前”

那就是 5 月 10 日上午 10:44。

我将在托管环境中。 (我的站点和调度会在同一个环境甚至同一个解决方案中运行。所以它不会让浏览我站点的用户减慢很多。)

我也在使用 nhibernate 和 fluent nhibernate 来进行数据库查询。我正在为我的网站使用 asp.net mvc 3。

选项 1。

每分钟进行一次数据库查询,并获取应在该分钟内发出的所有提醒。这当然意味着每分钟查询一次数据库,对于共享环境来说可能过于密集。

选项 2。

每 5 分钟进行一次数据库查询,并获取应在该 5 分钟块内发送的所有提醒,并将它们存储在一个集合(即内存)中,然后每分钟检查哪些提醒需要发送出去。

这当然会减少完成的查询量,但不确定这是否会占用大量内存。

选项 3

与选项 2 相同,但每 15 分钟发送一次查询并存储在集合中。

这当然意味着更少的数据库查询,但更多的存储在内存中。

选项 4

每 15 分钟执行一次数据库查询,获取该块中的所有提醒并立即将其触发。

这意味着它们不会在内存中存储很长时间并减少查询量。但是,根据用户设置提醒的时间,电子邮件可能会比他们设置的更早到达。

例如,他们说在上午 10:44 提醒我。我会让我的调度程序从上午 10:00 开始,它会从上午 10:00 到上午 10:15,然后是上午 10:15 到上午 10:30,然后是上午 10:30 到上午 10:45。

因此,电子邮件实际上会比预期提前 14 分钟到达。

【问题讨论】:

    标签: c# performance scheduling shared-hosting quartz.net


    【解决方案1】:

    这是我将如何解决这个问题。

    • 在数据库层,我将创建一个简单的队列。该消息列表还将包括发送时间。查询此列表时,下一项将位于顶部。

    • 消息代理将查询此列表并处理顶部项目或休眠直到列表中的顶部项目到期。

    这种技术的一个优点是您不需要代理代理在检查队列时应用业务规则。如果您希望它每分钟唤醒一次(例如检查是否有需要发送的新消息),那么您只需确保此队列每分钟始终有一个事件(此事件可能具有不发送的类型一条消息,一条“唤醒”消息没有目标)。代理将唤醒并执行检查。然后,如果您想应用更复杂的调度规则,它们很容易。您不必重新编码代理,您只需更改放入队列中的消息即可。 (例如,系统使用率高时每 10 分钟检查一次,系统使用率低时每 20 分钟检查一次,并在夜间备份期间停止检查)。这一切都可以在不更改代理上的代码的情况下完成(和更改)。


    一个简单的现实世界示例

    QueueTable
    ----------
    ID int
    deliverTime datetime
    nagCount int
    expireTime datetime
    active bool
    processed datetime (null)
    ' maybe some audit stuf...
    ' content of the message -- or external link
    ' etc
    

    START:代理拨打这样的电话

    SELECT TOP 1 * 
    FROM QueueTable
    WHERE active = true and processed is null
    ORDER BY deliverTime DESC
    

    代理然后查看deliverTime时间是多少:

    • 如果它已经通过或在下一个模糊边界(1 秒?),它会发送消息,然后将处理时间设置为数据库中的当前时间并循环回到 START:

    • 如果是在未来,它会一直休眠到该 DeliveryTime 或设置一个事件以在该时间唤醒它(取决于平台)。

    我最初是作为布尔值处理的,但如果你使用 null 来等于未处理,那么它可以兼作审计字段。


    例如,无论如何每 10 分钟检查一次。

    这是如何工作的:因为结果是按时间排序的,所以最快的结果会显示在顶部。我们所做的是在 10 分钟后将一个项目添加到结果集中。因此,最上面的项目永远不会超过当前时间的 10 分钟。

    SELECT TOP 1 * 
    FROM QueueTable
    WHERE active = true and processed is null
    UNION ALL
    SELECT NULL, DATEADD(min,GETDATE(),10), null, null, false, null, ...
    ORDER BY deliverTime DESC
    

    注意,活动列在此处用作标志,以表明不会执行任何操作。该记录只是唤醒代理的标记。此方法还可以根据其他规则进行调整(例如一天中的时间,因为在晚上您不需要经常检查等)

    【讨论】:

    • @Hogan - 你能写一个简单的例子吗?我在跟随时遇到了一些麻烦。我已经计算了发送时间并将其存储在数据库中,因此我计划通过执行 Where 子句来检查它是否属于该块来获取我的查询。我不确定你的第二点是什么意思。我不确定您所说的消息代理是什么意思,以及它将如何作用于顶部项目。
    • @Hogon - 是 ms sql server 中的代理,还是我从我的 C# 代码/nhibernate 中执行此操作?
    • @chobo2 -- 代理是执行通知的任何人。在您的情况下,我相信它是 C#(但该解决方案不依赖于一种架构——即代理可以是执行通知的任何东西)。
    • @Hogan - 嗯,还是有点难以跟上。因此,您获取满足您条件的最高查询(为什么您知道检查它是否在该交付时间范围内?)然后您将其发送出去。如果最上面的消息是在未来,那么你让它休眠直到它的时间范围,然后发送出去,然后重复。是这个过程吗?
    • 没有。我拿了最上面的东西。如果是在未来,我会退出这个过程并休眠,直到该消息处于活动状态,否则我将其发送出去。
    【解决方案2】:

    如果不符合您的要求,我可能会立即放弃选项 4。

    其他选项实际上取决于您的系统配置文件(有多少人在使用它?在任何给定的 5/15 分钟内有多少提醒?)这些是您需要回答的问题。此外,服务器上已经发生了多少活动?如果它还没有承受很大的压力,那么每分钟查询一次就不算多。

    最后,请记住,如果您仅每 5/15 分钟查询一次,那么您可能会错过对日程的更改/添加/删除,如果它发生在您查询之后并且提醒应该属于该 5/ 15 分钟窗口。同样,这归结为应用程序要求是否可以接受。

    【讨论】:

    • Ya 选项 4 我可能可以接受,但我宁愿在他们设置它的几分钟内而不是像 14 分钟前那样设置它。我的目标是对至少 1000 个用户进行压力测试,然后可能有 10,000 个用户,看看我的系统是如何工作的。我与这些数字中的任何一个都相去甚远,但这是我希望我的东西至少能够处理的。所有这些数字都悬而未决,因为它们都是用户定义的。我明白你的意思,如果他们改变提醒时间,那么它仍然会在旧时间触发。如果真的发生了,那也不会是世界末日。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 2018-12-22
    相关资源
    最近更新 更多