0

我有一个非常简单的 SQL 要求,但在遇到性能问题时想知道以下场景的“最佳实践”是什么。

我有一份球队名单,这些球队每周/每轮都支付比赛费用。如果一个团队不付款,那么他们将有未结余额。所有团队付款都进入一个越来越大的付款表。返回包含当前余额的团队列表的最佳做法是什么?

我目前拥有的:

Select teams.*, (Select SUM(amount) from payments p where p.TeamID=teams.TeamID) as teambalance 
from (select TeamID, TeamName from Teams) teams
4

4 回答 4

2

我对此进行了很多思考,并认为“不要两次存储相同的信息”的经典建议在这里是错误的,或者至少被误解了。

想想银行必须如何做。显然,当您想知道您当前的余额并且您已经是 20 年的客户时,他们不会将 20 年的帐户活动相加来找到您的当前余额。鉴于此,我看到了两种处理方法:

  1. 选择要“关闭”的期间,并始终从上次关闭的期间开始计算。这使总和相对较短。月报表可能是一个很好的锚。您是否有类似的自然时间段或业务生命周期要跟踪?
  2. 通过将您的帐户历史锚定在当前,向后工作。与其从 0 开始并添加,不如从当前余额开始并返回。在我看来,这同样有效,并且具有额外的好处,即当您想要修剪旧历史时,您不必做任何事情。存储当前余额,忘记所谓的非规范化。当前余额与起始余额一样是真实的经验事实,以这种方式锚定您的帐户没有任何害处。

喜欢的话可以继续添加,只要性能还可以。但它可能不是最优的。

您当前的查询很好,但不需要teams派生表。除非您使用 MySQL,否则 DBMS 不需要这种“帮助”——尽管 MySQL 实际上可能会受到伤害。

于 2012-08-05T07:57:21.780 回答
1
select teamId,teamName,sum(amount)
from teams t join payments p on t.teamId = p.teamId
group by t.teamId, t.teamName
于 2012-08-05T05:33:21.840 回答
0

我使用了两种方法来完成这项任务——一种是您当前使用的方法。另一种是使用交叉应用。

我更喜欢你现在的方法-

于 2012-08-05T05:30:45.427 回答
0

这可能比在 SELECT 子句(或连接)中使用子查询更快:

select teams.TeamID, teams.teamName, team_balances.teambalance
  from teams
  join ( select TeamID, sum(amount) teambalance
           from payments
         group by TeamID
  ) team_balances
  on team_balances.TeamID = teams.TeamID;

这将按顺序扫描支付表一次,而不是进行 N 次索引扫描(每个团队一次)。

非规范化

另一种选择是创建将“outstanding_balance”列添加到团队表。

在支付表上创建一个触发器。在触发器中,分别根据 TeamID 和发票/付款金额增加或减少团队中的未完成余额列。

根据您的 RDBMS,您还可以使用物化视图。这类似于触发方法,除了每个团队的余额将存储在不同的表中。

于 2012-08-05T08:04:24.007 回答