期末余额等于SUM(amount),无需按时间累加;WHERE必须严格限定账户和期间,否则结果错误;常见错误是时间条件不完整,如仅用create_time='2024-01-01'且缺trade_date范围。

直接用 SUM() 累计就能得到期末余额
只要流水表结构合理(含 amount 字段,正负表示收入/支出),期末余额就是所有记录的 amount 总和。不需要按时间排序再逐行累加——SQL 是集合操作,SUM(amount) 本身已等价于“从期初 0 开始累加全部变动”。
WHERE 条件必须严格匹配账户和期间
漏加账户过滤或时间范围,结果就不是“该账户的期末余额”,而是全库或跨期数据。常见错误是只写 WHERE create_time ,却忘了 <code>account_id = 123。
- 必须包含账户标识字段,如
WHERE account_id = <code>123 - 期间条件推荐用闭区间:
AND trade_date BETWEEN '2024-01-01' AND '2024-12-31'(注意:若字段含时分秒,改用trade_date >= '2024-01-01' AND trade_date 更安全) - 如果存在“期初余额”单独记录(比如 type = 'INIT'),需确认是否应纳入计算——通常应包含,否则结果会少掉起点值
遇到 NULL 或未提交事务会导致结果不准
amount 为 NULL 的记录会被 SUM() 自动忽略,看似无害,实则隐性丢失数据。更危险的是未提交的事务——其他会话还没 COMMIT 的流水,在当前查询中不可见,导致余额暂时偏低。
- 检查
amount是否允许为NULL:执行SELECT COUNT(*) FROM tx WHERE amount IS NULL AND account_id = 123 - 生产环境务必在
READ COMMITTED或更高隔离级别下查余额,避免脏读 - 若业务要求强一致性(如支付场景),应配合行锁或版本号控制,不能仅依赖
SUM()
大表上 COUNT(*) 和 SUM() 性能差异不大,但索引很关键
SUM(amount) 和 COUNT(*) 都要扫描数据,但前者还多一步数值累加。真正影响速度的是有没有覆盖索引。没有索引时,哪怕只查一个账户,也可能触发全表扫描。
- 必备复合索引:
CREATE INDEX idx_acc_date ON tx (account_id, trade_date)(把trade_date放第二列,方便范围查询) - 如果经常按日期聚合,可考虑分区表(按
trade_dateRANGE 分区) - 避免在
WHERE中对字段做函数操作,例如WHERE DATE(trade_date) = '2024-01-01'会让索引失效
SUM() 得到不同答案。

















