1

在事务数据库中拥有涉及多个表的计算列的最佳方法是什么?

背景

我们的事务型 MySQL 数据库包括如下简化模型的事实表:

CREATE TABLE LU_PROJECT(
    PROJECT_ID int,
    PROJECT_DESC varchar(60)
);

CREATE TABLE F_PROJECT_BUDGET(
    PROJECT_ID int,
    BUDGET numeric(15, 2)
);

CREATE TABLE F_TASK_BUDGET(
    TASK_ID int,
    BUDGET numeric(15,2)
);

CREATE TABLE  F_MONEY_USED(
    REPORTED_TIME datetime,
    TASK_ID int,
    MONEY_USED numeric(15, 2)
);

Task是 的孩子Project。任务 ID 不是唯一的,但项目/任务对是唯一的。

要求

我们需要保持项目所有任务的总预算<=项目预算的不变性。

此外,我们经常需要运行一个查询,该查询返回一个包含以下列的结果集:

PROJECT_ID, PROJET_DESC, PROJECT_BUDGET, TASK_COUNT,PROJECT_MONEY_USED

问题

我们关心性能。最简单的解决方案需要更新以命中三个事实表:

  1. 检查添加到F_MONEY_USED不会使我们超出任务的预算F_TASK_BUDGET
  2. 检查添加资金不会使我们超出项目的总预算
  3. 写到F_MONEY_USED

而我们需要获取统计信息的查询会命中三个事实表(除了查找表,上面的模型中没有):

  1. 加入LU_PROJECTPROJECT_BUDGETF_PROJECT_BUDGET组中PROJECT_ID
  2. 加入LU_PROJECTF_TASK_BUDGET获取TASK_COUNT分组依据PROJECT_ID
  3. 加入 LU_PROJECTF_MONEY_USED以获取PROJECT_MONEY_USED分组依据PROJECT_ID
  4. 加入LU_PROJECT上面的中间结果并得到PROJECT_DESC

问题是加入的次数很多,读写都会频繁发生。

潜在解决方案

我们正在考虑的一种解决方案是添加一个PROJECT_MONEY_USED字段,F_PROJECT_BUDGET该字段将在写入时更新F_TASK_BUDGET。这会减慢写入速度,但会加快读取速度。

  • 该解决方案还将引入复杂性和数据完整性问题,因为事实表将不再是“基本的”。这违反了数据仓库原则,但我无法确定它是否符合事务数据库的犹太教规。

  • 如果我们可以在 UI 中进行乐观渲染,那么写入速度的下降可能不是什么大问题,但这会带来更多的复杂性。

考虑的其他解决方案

  • 对于写入,我们正在考虑使用触发器来保留不变量。
  • 对于读取,计算列看起来很有希望,但它们不允许在 MySQL 中访问多个表。
  • 对于读取,物化视图可能不是一个选项,数据需要实时更新。

概括

是否有更好的解决方案以安全、简单和高性能的方式进行读写?

4

0 回答 0