在常用的 分类表 详情表 1对多模型中,常常有统计某个分类下有多少详情数据的,比如 某分类下有多少文章,分类表往往数据量少,可能就只有几十条几百条,但是详情表会很多,几十万 上百万都有可能,那么在某些详情分类得到变更的情况下,或者说新增删除了某个详情记录,分类的统计记录又该如何统计呢?

我们这里先展示一下常用的分类详情设计

分类表

如何实现分类表统计数目和详情表数量同步_数据库

详情表

如何实现分类表统计数目和详情表数量同步_字段_02

这是最简单不过的1对多了,一条新闻属于某个分类下,然后我们想统计某个分类下有多少文章,如何统计呢?

如何实现分类表统计数目和详情表数量同步_缓存_03

当然了,其实我们在web应用中往往希望看到分类名称,以及该分类下的新闻数量,那么这个统计结果还是有些不太如意的,如何处理呢?

如何实现分类表统计数目和详情表数量同步_数据库_04

这才是我们希望看到的结果,有分类名称,有对应该分类下统计数量

甚至还可以这样写

如何实现分类表统计数目和详情表数量同步_数据库_05

不过这样写在有些SQL_MODE下好像不太支持 会提示这个name isn't in GROUP BY

因为你查询的那个字段不在分组的字段里面,所以会提示你这样的SQL错误。但是无论怎样都避免不了联表了,如何不联表而且能查询到我们想要的结果呢?

我们这里举个例子,通过分别查询,并进行键值组合得到结果

 代码如下:

 如何实现分类表统计数目和详情表数量同步_缓存_06

结果如下:

如何实现分类表统计数目和详情表数量同步_缓存_07

这样是通过PHP对数据进行处理得到的结果。

那么这样的情况是通过数据库的统计而得到的结果,如果有些时候不方便这样每次统计又该如何做呢?

那我们已经想到了,将统计数量先缓存起来,只有在新增和删除或者被修改的时候才更新缓存,就能拿到统计数量了。

我们可以采用很多种缓存,文件 Redis memcache等等,不过这里可以简单的用数据库添加字段冗余来缓存。我们将cat表改造一下

如何实现分类表统计数目和详情表数量同步_数据库_08

字段添加了以后 数据是空的

如何实现分类表统计数目和详情表数量同步_字段_09

得想办法把news详情表中的统计数量同步过来,那么如何同步呢?

我们可以用查询   select cat_id,count(id) as num from news group by cat_id;  的结果来循环更新进行同步,这是最直接最直观的方法

如何实现分类表统计数目和详情表数量同步_字段_10

结果如图:

如何实现分类表统计数目和详情表数量同步_字段_11

查看数据库:

如何实现分类表统计数目和详情表数量同步_字段_12

这是先统计结果,然后循环更新的方法,当然也可以想办法进行join同步

update 
cat left join (select cat_id,count(*) as count_num from news group by cat_id) as tmp
on tmp.cat_id=cat.id
set cat.num=tmp.count_num;

如何实现分类表统计数目和详情表数量同步_字段_13

这样数据就同步过来了。

当news详情表有新增和删除的时候,这个cat表里的num就要同步的加1或者减1,当news详情表里面的cat_id被修改的时候,cat表里面的num就要相对应的同步修改之前的cat_id的num和修改之后的cat_id的num。

描述起来有些复杂,不如用代码演示一遍

当前数据库

如何实现分类表统计数目和详情表数量同步_缓存_14

 代码如下:

如何实现分类表统计数目和详情表数量同步_字段_15

 结果如下:

如何实现分类表统计数目和详情表数量同步_字段_16

 数据库如图:

如何实现分类表统计数目和详情表数量同步_缓存_17

其实这里的SQL语句也可以用  select count(*) from news where cat_id=2 先统计出来 然后PHP计算统计数量+1之后,再  update cat set num=计算增加后的数量 where id=$cat_id  这样更新

但是为什么不用呢??? 请自行结合实际业务仔细思考或者给我留言。

那么相对应的,如果有人删除了某条详情,cat表里的num就要减1

具体如下:

当前数据库:

如何实现分类表统计数目和详情表数量同步_字段_18

代码如下:

如何实现分类表统计数目和详情表数量同步_缓存_19

结果如图:

如何实现分类表统计数目和详情表数量同步_数据库_20

数据库如图:

如何实现分类表统计数目和详情表数量同步_缓存_21

我们可以看到,删除详情表,需要先检查详情是否存在,存在的话获取详情的cat_id,删除详情后针对该cat_id进行减1操作

增加和删除都是对单条记录受到影响,如果是修改则不一样了,因为修改意味着当前分类的num-1,修改后的分类的num+1 ,此消彼长的概念便油然而生!

当前数据库如下:

如何实现分类表统计数目和详情表数量同步_数据库_22

代码如下:

如何实现分类表统计数目和详情表数量同步_字段_23

结果如下:

如何实现分类表统计数目和详情表数量同步_字段_24

数据库如图:

如何实现分类表统计数目和详情表数量同步_字段_25

这样就实现了旧分类减1,新分类加1的功能。

采用MySQL的字段冗余做缓存,虽然查询起来更方便了,可是维护起来也更加复杂了。

这往往是我们实际业务开发中需要抉择的,冗余多了,查询方便,可是维护的力度也变大了,冗余少,范式高,查询起来也复杂了,还是要适当冗余的好,毕竟目前大部分公司的业务中的查询和修改所占比例中,查询还是多一些的,用nosql做缓存的话也是很方便的,能够键值对直接修改,没有SQL这么复杂,维护力度也会稍微降低一点点,不过总体的设计上还是差别不大,具体选用哪种方式还要看我们所负责的业务和场景需要什么模型去融合去实现。