【问题标题】:Alternative to View for complex Data?替代查看复杂数据?
【发布时间】:2011-05-25 12:10:37
【问题描述】:

我有一个表,其中包含对查看我的应用程序的用户没有用的部分数据。查看者希望看到一个类似的表,其中计算出所有值,并希望能够快速查询该数据。通常,这将是使用视图的理想场所。不幸的是,计算的复杂性限制了我对视图的使用,所以我需要一个替代解决方案。我正在考虑做类似以下的事情......

表 A 包含后端数据。每当更新此表时,都会触发一个触发器来更新表 B,该表显示了这些计算的结果。此时可以快速查询表B。

我唯一担心的是计算过程有些冗长,而且表 A 有可能会爆发多次更新。是否有任何类似于“选择前”触发器的解决方案?所以基本上A表可以连续多次更新,但是只有查询B表时才会计算?

这是一个示例时间线:

  1. 表 A 已更新
  2. 表 A 再次更新 [不要运行 SP,因为还没有人需要表 B 数据]
  3. 从表 B 请求数据[在获取数据之前运行 SP 以更新表 B]
  4. 表 A 已更新
  5. 从表 B 请求数据[在获取数据之前运行 SP 以更新表 B]
  6. 从表 B 请求数据[不要运行存储过程,因为表 A 在请求表 B 数据之间没有更新]

所以我的问题是:

  1. 有没有像我上面描述的那样存在?
  2. 如果没有,有没有办法让触发器延迟到完成一批更新/插入?表 A 不会经常修改,所以当它更新时我可以忍受一个缓慢的触发器。唯一的问题是,当表 A 确实更新时,通常一次有数百行,我不希望每次都运行缓慢的触发器。

感谢您提供任何解决方案/见解!

编辑 - 详细说明为什么(我认为至少)触发器实现会很慢:

  1. 将发送更新/插入/删除语句的应用程序正在使用 LINQ-to-SQL,这对于批处理操作并不是特别好。所以如果我想删除一堆记录,它会发送一堆删除语句而不是批量删除语句。有没有办法对删除语句进行分组并在此之后运行触发器? (也许我在这里离题太远了)。
  2. 我所说的“计算”涉及一些递归函数和一些决策过程。我实际处理的数据是调度数据。所以表 A 包含可能有也可能没有预定开始的任务。如果没有定义预定开始,它必须从其前身预定开始 + 其前身持续时间派生。在某些情况下,前任可能也没有该信息,因此递归查询会不断挖掘直到找到结果。它的速度并不慢,但如果它必须在每次插入/更新/删除时运行,它就会到达那里。我上面提到的“表 B”基本上是同一个表,但它已经包含了计算好的计划开始数据(需要在表 A 更新时更改)。

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql triggers


    【解决方案1】:

    我认为物化视图能够解决这个问题,并且运行得相当快。但是,OP 没有说明“计算”是什么,只是说它们运行缓慢。因此,这是您最好的选择:

    向您的主表 A 添加一个触发器,在该触发器中将受影响行的 ID 插入一个新的“需要完成的工作”表中。这将具有非常低的开销,因为尚未完成计算。

    创建一个每 x 分钟运行一次的作业以进行工作计算并清除“需要完成的工作”表。该作业将填充并保持同步您的表 B,该表具有最终答案。

    仅通过存储过程调用授予对“查询”的访问权限,在此过程中,运行作业使用的处理(将确保表 B 中的数据是最新的)然后它将运行查询使用表 B。

    【讨论】:

    • @KM:请看我的编辑...我不知道物化视图,虽然看起来好像它们可能会给我留下陈旧的数据(我需要数据是最新的)。 “工作需要完成”的想法非常好。根据我的编辑,您还有其他见解吗?
    • 视图永远不会不同步,请参阅:[使用 SQL Server 2005 索引视图提高性能](technet.microsoft.com/en-us/library/cc917715.aspx)
    【解决方案2】:

    触发器对插入或更新的整批记录进行操作,而不是一次操作一行。

    如果计算时间过长而只有几百条新记录,那么计算本身可能需要进行性能调整。

    如果您在触发器中进行计算,那么它们是每个事务的一部分,并且它们将在另一个事务被允许之前完成,因此可以想象它可能会减慢插入速度。如果您正确编写触发器来处理数据集而不是逐行处理,它可能不会导致问题。数百行对于进行大多数计算来说是微不足道的。如果您批量插入数百万行,我会更担心触发器性能会干扰其他进程。

    您可以创建一个 proc 来进行计算,并安排它每十分钟左右运行一次,然后在需要报告时再次运行。这样,它可能会提前进行大部分预计算,并在报告时捕获最后几条新记录。

    给我们一个计算样本和潜在触发因素,我们可以更好地帮助您。

    如果单个事务成一个组触发器运行,则无法将一堆分组。如果您需要批处理一起处理,也许您应该停止使用 LINQ 和 senda 批处理语句。如果您一次处理多个记录,则基于集合的操作通常更可取。

    【讨论】:

      【解决方案3】:

      如果可能(当然这可能不是您的具体情况),您可以通过存储过程调用从表 B 返回数据,而不是从视图/表中选择。这样,您的程序只有在被特别调用时(即在表 A 更新后)才会执行繁重的工作。

      【讨论】:

        【解决方案4】:

        这是对已经讨论过的内容的更简单的变体......

        如果您的两个表上都有 DeltaTs/EditTs 列,您可以:

        通过存储过程返回查询数据,该存储过程将检查两个表上的 max(Deltats) 与 max(deltats) 并根据需要更新表 b。在更新表 A 后第一次选择时,您会受到一些打击,但之后会很好而且很快。

        【讨论】:

          猜你喜欢
          • 2021-02-02
          • 2014-01-17
          • 2011-08-24
          • 1970-01-01
          • 1970-01-01
          • 2018-04-05
          • 2023-03-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多