简体   繁体   English

汇总SQL

[英]Rolling Sum SQL

I have a pretty simple SQL requirement but wanting to know what is 'best practice' for the below scenario as I am running into a performance issue. 我有一个非常简单的SQL要求,但由于遇到性能问题,想知道以下情况的“最佳实践”是什么。

I have a list of teams, each week/round these teams pay a game fee. 我有球队名单,这些球队每周/每轮都要支付比赛费用。 If a team doesn't pay then then they will have an outstanding balance. 如果一支球队不付款,那么他们将有未偿还的余额。 All team payments go into a payments table which is getting bigger and bigger. 所有团队付款都进入越来越大的付款表。 What is the best practice to return a list of teams with their current balance? 返回具有当前余额的球队名单的最佳实践是什么?

What I have at the moment: 我目前所拥有的:

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

I have thought about this a lot and think that the classical advice of "don't store the same information twice" is mistaken here, or at least misinterpreted. 我已经考虑了很多,并认为“不要两次存储相同的信息”的经典建议在这里被误解了,或者至少被误解了。

Think about how banks must do it. 想想银行必须怎么做。 Obviously, when you want to know your current balance and you've been a customer for 20 years, they don't add up 20 years of account activity to find your current balance. 显然,当您想知道当前余额并且已经成为客户20年时,他们不会将20年的帐户活动总计起来即可找到您的当前余额。 In light of that, I see two ways to handle it: 有鉴于此,我看到了两种处理方法:

  1. Choose periods to "close" and always calculate from the last closed period. 选择要“关闭”的期间,并始终根据上一个关闭的期间进行计算。 This keeps the summing relatively short. 这使求和相对较短。 The monthly statement is probably a good such anchor. 月度报表可能是一个很好的主播。 Do you have a similar natural time period or business life cycle to track with? 您是否有类似的自然时间段或业务生命周期可以跟踪?
  2. Work backwards, by anchoring your account history in the present . 逆向操作,通过在锚固您的帐户历史记录。 Instead of starting at 0 and adding, start at current balance and go back. 而不是从0开始加法,而是从当前余额开始再返回。 This is just as valid, in my opinion, and has the added benefit that you don't have to do a thing when you want to trim old history. 在我看来,这同样有效,并具有额外的好处,即当您想修剪旧的历史记录时,您不必做任何事情。 Store the current balance, and forget the supposed denormalization. 存储当前余额,并忘记所谓的非规范化。 The current balance is as true an empirical fact as the starting balance, and there is no harm in anchoring your accounts this way. 当前余额与初始余额一样,都是真实的经验事实,以这种方式锚定帐户没有任何危害。

You can continue to add if you like, so long as performance is okay. 只要性能还可以,您可以继续添加。 But it may not be optimal. 但这可能不是最佳选择。

Your current query is fine, but there is no need for the teams derived table. 您当前的查询很好,但是不需要teams派生表。 Unless you're using MySQL, the DBMS doesn't need this kind of "help"--though MySQL could actually be harmed by it. 除非您使用MySQL,否则DBMS不需要这种“帮助”,尽管MySQL实际上可能会受到伤害。

select teamId,teamName,sum(amount)
from teams t join payments p on t.teamId = p.teamId
group by t.teamId, t.teamName

I have used two methods to accomplish this task - one being the method that you are currently using. 我使用两种方法来完成此任务-一种是您当前正在使用的方法。 The other is using cross apply. 另一种是使用交叉应用。

I prefer your current method - 我更喜欢您当前的方法-

This may be faster than using a subquery in the SELECT clause (or a join): 这可能比在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;

This will sequentially scan the payments table once, rather than doing N index scans (one per team). 这将顺序扫描付款表一次,而不是进行N次索引扫描(每个团队一次)。

denormalizing 非正规化

Another option is to create add a "outstanding_balance" column to the teams table. 另一种选择是在“团队”表中创建一个“ outstanding_balance”列。

Create a trigger on the payments table. 在付款表上创建触发器。 In the trigger, increment or decrement the outstanding_balance column in teams based on the TeamID and the invoice/payment amount, respectively. 在触发器中,分别基于TeamID和发票/付款金额增加或减少团队中的未清余额列。

Depending on your RDBMS you could also use a materialized view. 根据您的RDBMS,您也可以使用实例化视图。 This is similar to the trigger method, except the balance for each team would be stored in a different table. 这类似于触发方法,除了每个团队的余额将存储在不同的表中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM