数据库设计问题

时间:2009-11-07 10:25:17

标签: database database-design firebird

我有一个Firebird数据库,假设表A和B看起来像这样:

表A

TableB's Id | SomeNumber | OtherNumber | ComputedByField              | OtherIntField
    1              5          200           SomeNumber*OtherNumber          10
    1              2          70                  ...                       20

表B

Id   | Sum                     |  Sum
 1     Sum of OtherIntFIeld       Sum of ComputedByField

where TableA'sId = TableB's Id

但是现在TableB正在填充(它是2k行),由于这个计算,访问它也变得很慢。

所以我的问题是:我应该删除TableA的computedby字段并将其直接添加到TableB中,并且添加新的TableA行以手动修改对应的行吗? (这应该更快,但我真的不喜欢它)

编辑:性能问题来自这样一个事实:有两个computedby字段在TableA上执行完全相同的查询但返回不同的字段。我想这是需要优化的部分。

Edit2:行计算如下

TABLEB_FIELD_X COMPUTED BY ((
    select SUM(TableA.FieldX) from TableA
    where TableA.FAT_ID = TableB.ID
))

TABLEB_FIELD_Y COMPUTED BY ((
    select SUM(TableA.FieldY) from TableA
    where TableA.FAT_ID = TableB.ID
))

我认为主要问题来自这两个独立字段从TableA查询相同行的事实,它们只是得到一个不同的字段。

3 个答案:

答案 0 :(得分:1)

为什么不创建view,而不是TableB? (警告:我从未使用过Firebird,我不知道它对视图的支持程度如何)。

这样的观点将是:

 create view Totals (SumX, SumY)
          as
      select SUM(FieldX), SUM(FieldY)
        from TableA
    group by ID

每次更改TableA时,此类视图(Totals)都会自动更新。 一个不错的DBMS会在优化这个方面做得很好:只有在Totals发生变化时才会重新计算{em> {/ 1>} TableA,与TableB不同,这将是Totals每次都要重新计算(我假设您的性能问题 - 确定需要知道Firebird内部)。

select * from Totals where ID = ... 将像任何其他表一样(但是只读);您将使用以下内容过滤信息:

TableA

P.S。: Walter Mitty在下面的评论中提请我注意我对原始解决方案的假设,即{{1}}:

  • 必须属于(至少)第一范式(1NF) - 否则关系操作无法保证正确的结果( nota bene:必须知道您的应用要求和概念/逻辑设计详细 - 在论坛中获取/通过间接通信是不切实际的 - 在未完全规范化的设计中发现最终问题,例如我们插入/删除/更新异常;关于DB理论的书将让你头疼,不幸的是这些书很少);
  • 它被正确编入索引(至少在ID上)。

令人遗憾的是,基于SQL的DBMS 要求来自用户的此类物理设计细节具有良好的性能,这与DBMS应该擅长的相反(它具有所需的所有信息)自动完成工作,即物理数据结构和数据访问路径统计的所有权。)

答案 1 :(得分:0)

我会在表A上使用一个触发器,它在表A中的任何插入/更新/删除之后用字段的总和更新表B.

这会对表A上发生的任何事务产生一些额外的影响,但在查询表B时会更有效。

答案 2 :(得分:0)

不确定为什么每次更新时都要重新计算整个表格?这就是你的代码和解释似乎暗示的内容。

最好的办法是将计算值存储为常规值整数或结果。然后你还可以添加索引之类的东西。如果您将其保留为动态字段,则如果您有索引,则还必须动态重建索引。

标准程序是将其移至代码,并计算&更新其他两个中的任何一个时,动态更新ComputedValue字段。如果您在代码中有多个地方更新该字段,我会考虑优化您的代码。

此外,如果你真的需要加快速度,你可以使用存储过程(我不使用Firebird - 所以我不知道它是否支持它)并在需要时从你的代码中调用它们。 / p>