blog
blog copied to clipboard
数据库操作太多了
我发现才做了一点功能,数据库操作就多的不行了,比如访问一下功能正常的主页,要进行至少如下的数据库操作
- token解析后找到登陆的人,1次
- 显示最近发的帖子,如果一页30的话,1次
- 每个帖子根据作者id,查询作者信息,1*30次
- 如果有最近回复的id,那就是查询最近回复, 1*30次
- 30个帖子中是否有收藏的,1*30次
- 是否点赞,1*30次
也就是说大概要进行上百次的操作,这简直是可怕的,我查了下discus访问一下主页大概是要10-30次之间,这也很多了
很显然,肯定是我什么地方想错了,不该有这么多数据库查询
比如我一直在纠结一个帖子的评论使用mongoose的子文档还是就是放在正常的文档中呢
放在子文档会很爽,每次新增评论只需要向comments这个属性中push这个评论,只会有一次save操作
如果是单独的collection,则需要新增一个reply,并且更新last_reply_id
,如果不更新last_reply_id
,则会导致显示最近回复需要一次复杂的操作
数据库操作复杂起来,对于nodejs简直是致命的,因为每次回调加上错误判断,3次以上的异步操作,函数就斜的不能看了
所以是时候使用一下异步的库,以前确实不知道有专门解决回调过深的库,现在觉得真是丢死人,写js不用异步库简直智商拙计
我想了很久,认为model设计上出了问题
比如一个帖子,按照nodeclub的做法,在帖子的model中既有last_reply_id
也有last_reply_at
,其中last_reply_at
似乎是必须的,因为大多数排序是按照最后回复时间来排序的
但这样也有问题
- 如果还是要获取最后回复的用户的name,则还需加一层嵌套
- 每次发布一个评论,都要在主题中加入
last_reply_id
和last_reply_at
,有一个发生错误就会产生冲突 - 删除评论,如果碰巧是最新的评论,还需要删除该主题的
last_reply_id
和last_reply_at
并且重新找最新的回复,因此大部分都是直接写评论已删除。。
总之,光是这几点,就足以让人崩溃,我们理想中的方法就是添加一个评论,不牵扯其他,仅仅为了最新的回复排序要折腾这么多?
目前的想法就是在内存中保留一个hash,键为帖子的id,值为所有评论,按时间排序。同时保存一个数组,按时间排序hash的键
这样的话有如下好处
- 按最新回复排序,只需从数组中取出值
- 显示一个帖子的回复已经不需要查询
- 新增一个帖子只需要加入数据库后,把返回值shift入该主题的评论数组,并重新排序时间数组
- 删除一个评论只需要从数据库中删除,并将其从该主题的评论数组slice出来,并重新排序时间数组
- 除了数据库操作外,其他都不是IO操作
- 每次启动论坛程序,只需遍历全部主题,根据id查询评论,按时间输出
坏处
- 把数据保存在变量中很容易出问题,比如一个帖子有1000个回复,有1w多个帖子了,但变量就至少是600M大,越到后面就越无法扩展
解决方法是获取全部主题的前100个,然后存在数组中
但这样实现想想就很蠢
我最终的决定是加上一个辅助的collections,专门用来统计,每次开启服务的时候取到回复数(注意浏览数不属于统计),收藏数,最近回复
这样,每添加一个回复,直接替换该帖子的最近回复即可,也就是说这个新增的collection是专门用于算出可以统计出来的信息,防止冲突
同时在api设计的时候,还在想如何把评论插件化,如果能顺利插件化,那以后做赞,收藏,踩这样的功能就会轻松许多