一个学校有 N 个班级,一个班级有 N 个学生。
以下两种方式如何选择:
1.使用单独列
在学校
表使用 classesCount
和 studentsCount
两个列来分别存储该校班级
数量、该校学生
数量,在班级
表中使用 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;
方式一在增、删时需要做额外操作,会存在事务不能保证正确的情况吗?
方式二在数据量大的时候性能会很差吗?
类似这种数据库设计问题,有推荐的书籍参阅吗?
1
thinkershare 2022-07-10 01:00:47 +08:00 1
方式一: 有很多种办法可以保持事务一致性, 这个是数据库并发写入时保证一致性的基本操作了.
方式二: 并不会, 因为你这个结构就不可能有太多数据, 只要索引设计的正确, 不会有啥性能问题 书籍嘛: 我想到的有: 数据库概论(本科的教材), 高性能 MySQL, 数据库索引设计与优化, MongoDB 相关的设计原则, 对照一下关系数据库和 NoSQL 数据库的差异, 然后思考在 2 种模式下如何平衡性能 /一致性, 每一种选择都有自己的缺陷, 要根据你的业务场景寻求最佳 Schema. 有时候并不要求最佳, 甚至只需要有效就行. 等性能出了问题再去有针对的优化, 看的稍微远一点, 但不要太远. |
2
noparking188 2022-07-10 01:05:12 +08:00 2
可以补充:
1. 数据量级预估 2. 更新频率 3. 数据库选型 一: classesCount 和 studentsCount 可以单独建表存 二: 补充一下 |
3
lance6716 2022-07-10 01:19:24 +08:00 via Android 2
新加的这个计数引发的锁冲突,可能比你想象中的性能提升还要大
|
4
CEBBCAT 2022-07-10 01:42:58 +08:00 via iPhone
鉴于一个学校不会有 1k 个班,一个班平均不会有 1k 个人,我认为可以先用 count 的方法做。简单
|
5
mxT52CRuqR6o5 2022-07-10 05:42:37 +08:00 via Android
点赞系统吗?主要看场景,就比如点赞这个场景数量有点差错没关系的
|
6
lanlanye 2022-07-10 06:03:12 +08:00
方案应该根据业务情况选择,考虑能否接受统计不一致的问题,通常来说高可用和强一致你只能追求一个。
另外就是除非可预见上线时就需要面临很大压力,否则用 count 会简单些。(压力大不大可以用测试来量化) |
7
Chad0000 2022-07-10 06:36:23 +08:00 via iPhone 1
我就做了,新增或删除学生后发消息到队列然后异步更新即可。尤其是 saas 更应该这么做。
|
8
lmshl 2022-07-10 17:07:21 +08:00 1
你的数据量级我建议直接 count ,除非后面加个万字
我也遇到了类似的场景,需要统计客户在我们平台存放了多少数据,我们是多租户 SaaS 软件。不同租户一般几千到几千万不等,冷热分区明显。根据我的场景我试用了如下方案 1. 行数存单独的表,根据事件消息异步更新行数,这个方案必然会产生不一致,解决方案是每日一点重算昨日新增数据。 2. 客户查询时,优先使用 pg estimate 估算,总行数一万以下走 count ,行数一万以上返回行数表 sum 数值 在我的场景下,客户对数据量个位数增减敏感,但是对数据总量差 1%~10%并不敏感,所以保证最终一致性就足够了,每日校正一遍 |
9
tairan2006 2022-07-10 20:32:24 +08:00 via Android
量级太小 直接 count 即可
|
10
zlowly 2022-07-10 23:55:24 +08:00
开始设计的方案肯定是追求一致性的。当性能问题严重才会考虑冗余数据来提高性能。如果你的数据库支持物化视图就可以考虑用它来做统计数据会较为省心,如果性能仍然有问题,这个数据量你就要从需求上考虑,是否真的对实时的统计数据有必要的需求,因为如果不是为了金融级别的结算等需求,应该不会有人介意这个统计数据其实是若干分钟甚至小时前的 ETL 加工数据,那方案就多了去了。
|
11
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`
|