数据库应该使用单独列存储计数吗?

2022-07-10 00:47:53 +08:00
 zhengjian

问题描述

一个学校有 N 个班级,一个班级有 N 个学生。

以下两种方式如何选择:


1.使用单独列

学校表使用 classesCountstudentsCount 两个列来分别存储该校班级数量、该校学生数量,在班级表中使用 studentsCount 列存储该班学生数量。

班级实体增、删时,更新学校表的 classesCount 列;在学生实体增、删时,更新班级表及学校表的 studentsCount 列。

2.使用数据库查询

班级数量和学生数量由数据库查询获得。

select * from cmapus;
select count(*) as classesCount from classes group by campus_id;
select count(*) as studentsCount from students group by campus_id;

方式一在增、删时需要做额外操作,会存在事务不能保证正确的情况吗?

方式二在数据量大的时候性能会很差吗?

额外提问

类似这种数据库设计问题,有推荐的书籍参阅吗?

1897 次点击
所在节点    数据库
11 条回复
thinkershare
2022-07-10 01:00:47 +08:00
方式一: 有很多种办法可以保持事务一致性, 这个是数据库并发写入时保证一致性的基本操作了.
方式二: 并不会, 因为你这个结构就不可能有太多数据, 只要索引设计的正确, 不会有啥性能问题
书籍嘛: 我想到的有: 数据库概论(本科的教材), 高性能 MySQL, 数据库索引设计与优化, MongoDB 相关的设计原则, 对照一下关系数据库和 NoSQL 数据库的差异, 然后思考在 2 种模式下如何平衡性能 /一致性, 每一种选择都有自己的缺陷, 要根据你的业务场景寻求最佳 Schema. 有时候并不要求最佳, 甚至只需要有效就行. 等性能出了问题再去有针对的优化, 看的稍微远一点, 但不要太远.
noparking188
2022-07-10 01:05:12 +08:00
可以补充:
1. 数据量级预估
2. 更新频率
3. 数据库选型

一:
classesCount 和 studentsCount 可以单独建表存
二:
补充一下
lance6716
2022-07-10 01:19:24 +08:00
新加的这个计数引发的锁冲突,可能比你想象中的性能提升还要大
CEBBCAT
2022-07-10 01:42:58 +08:00
鉴于一个学校不会有 1k 个班,一个班平均不会有 1k 个人,我认为可以先用 count 的方法做。简单
mxT52CRuqR6o5
2022-07-10 05:42:37 +08:00
点赞系统吗?主要看场景,就比如点赞这个场景数量有点差错没关系的
lanlanye
2022-07-10 06:03:12 +08:00
方案应该根据业务情况选择,考虑能否接受统计不一致的问题,通常来说高可用和强一致你只能追求一个。
另外就是除非可预见上线时就需要面临很大压力,否则用 count 会简单些。(压力大不大可以用测试来量化)
Chad0000
2022-07-10 06:36:23 +08:00
我就做了,新增或删除学生后发消息到队列然后异步更新即可。尤其是 saas 更应该这么做。
lmshl
2022-07-10 17:07:21 +08:00
你的数据量级我建议直接 count ,除非后面加个万字

我也遇到了类似的场景,需要统计客户在我们平台存放了多少数据,我们是多租户 SaaS 软件。不同租户一般几千到几千万不等,冷热分区明显。根据我的场景我试用了如下方案

1. 行数存单独的表,根据事件消息异步更新行数,这个方案必然会产生不一致,解决方案是每日一点重算昨日新增数据。
2. 客户查询时,优先使用 pg estimate 估算,总行数一万以下走 count ,行数一万以上返回行数表 sum 数值

在我的场景下,客户对数据量个位数增减敏感,但是对数据总量差 1%~10%并不敏感,所以保证最终一致性就足够了,每日校正一遍
tairan2006
2022-07-10 20:32:24 +08:00
量级太小 直接 count 即可
zlowly
2022-07-10 23:55:24 +08:00
开始设计的方案肯定是追求一致性的。当性能问题严重才会考虑冗余数据来提高性能。如果你的数据库支持物化视图就可以考虑用它来做统计数据会较为省心,如果性能仍然有问题,这个数据量你就要从需求上考虑,是否真的对实时的统计数据有必要的需求,因为如果不是为了金融级别的结算等需求,应该不会有人介意这个统计数据其实是若干分钟甚至小时前的 ETL 加工数据,那方案就多了去了。
seth19960929
2022-07-11 11:30:58 +08:00
select `cmapus`.*, (select count(*) from `classes` where `cmapus`.`id` = `classes`.`campus_id`) as `classesCount` from `cmapus`

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/865187

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX