3

请考虑以下情况(为了问题而简化):

我在 SQL Server 2012 数据库中有以下表:

Parent_Table

Id  | Parent table fields
----+--------------------
1   | ...
2   | ...
3   | ...
...

Child_Table

Id  | ParentId | Child table fields
----+----------+-------------------
1   | 2        | ...
2   | 1        | ...
3   | 1        | ...
4   | 3        | ...
5   | 2        | ...
...

Big_Table

Id      | ChildId  | Value  | Status  | Other fields
--------+----------+--------|---------------------
1       | 12       | 672    | Closed  |
2       | 23       | 133    | Closed  |
3       | 7        | 2611   | Open    |
4       | 14       | 84     | Closed  |
...
1295769 | 23       | 458    | Closed  |
1295770 | 18       | 1046   | Open    |
1295771 | 7        | 8      | Open    |

Child 和 Parent 表相对较小(大约 100 个 Parent 条目和每个 parent 5 个 Child 条目)并且它们的条目每天只插入或删除几次。

另一方面,“大表”正在快速增长(为了讨论,每秒 100 个条目),并且行的状态在一段时间后变为 Closed(想想客户端会话,这里实际上就是这种情况)。

我需要定期(每隔几秒)为指定的 Parent.Id 提供 Big_Table 行数和 Big_Table.Value 列的总和-每次都不同。

我怀疑直接的实现(使用内部连接等)可能效率极低,更好的解决方案可能包括附加表、某种计数器表,或者我应该在我的服务代码中实现它(?!)并小心不知何故的坚持。

实施上述内容的“正确”(效率方面)方式是什么?处理额外级别的父母/孩子的解决方案将是最好的解决方案。

4

2 回答 2

3

如果我们假设 ChildId 始终保留相同的 ParentId,那么要考虑的一种选择是将 ParentId 添加到 Big_Table。如果您确定某些行只会从您控制的应用程序代码中添加到这些表中(例如,与具有数据库连接的人自己运行 INSERT 语句相反),您可以在内存中保留父表和子表的缓存,并且插入 Big_Table 时提供 ChildId 到 ParentId 的快速映射。然后您的总和/计数查询将完全在 Big_Table 上完成。这种非规范化当然会增加 Big_Table 的大小,但如果可以容忍这种情况和应用程序更改,这是一个可行的选择。

此外,如果 ParentId 是访问 Big_Table 中的行的主要方式(或具有最大性能问题的方式),那么您可以考虑在 ParentId 上对 Big_Table 进行分区。

一种完全不同的方法是将所需的统计信息直接存储在 Parent_Table 中,并使用 Big_Table 上的触发器来保持更新,或者,如果您在应用程序代码中控制所有数据库交互,则使用应用程序逻辑来更新统计信息作为Big_Table 插入。您可以在事务中执行此操作以确保一致性,或者如果您可以容忍某些错误,则可以将其作为异步统计信息更新来完成,以便 Big_Table 上的插入可以快速发生,而统计信息在后台更新。

至于处理额外级别的父母和孩子,您可能需要在灵活性和效率之间做出选择。例如,您可能需要限制您愿意支持的树的深度,以便硬编码深度逻辑以提高性能。

于 2012-11-10T00:23:53.490 回答
1

我会在下面的 2 上做一个时间测试,如果合理的话,你可以保持简单。我将留给您确定 with(nolock) 提示是否适合您的情况(数据库设置、数据的性质)。由于您知道父 ID,因此不需要涉及 Parent_Table。

显然 Big_Table.ChildId 和 Child_Table.ParentId 上应该有一个索引

select sum(Value)
from Big_Table with(nolock)
where ChildId in
(select Id
from Child_Table with(nolock)
where ParentId = @ParentId)

select sum(Value)
from Big_Table with(nolock)
inner join Child_Table with(nolock)
on  Big_Table.ChildId = Child_Table.Id
where Child_Table.ParentId = @ParentId
于 2012-11-10T00:42:01.680 回答