用中间表提高互联网程序的开发效率
基本的设计思想:
以业务的核心数据为中心,生成一张中间表,合并主要的业务数据。以简化互联网程序设计的复杂度。这个设计可以用于电子商务、在线视频等大部分互联网产品。下面以dangdang网为例说明:
举例说明
如果我们需要做一个dangdang那样的图书销售页面,假设我们有200万图书,数据存储到mysql,我们至少需要:
- 生成首页推荐:包括推荐图书的标题、价格、评分、评论信息
- 生成排行榜:包括图书标题、价格、评分、评论信息
- 生成图书详情页:包括图书标题、价格、评分、评论信息
- 做一个搜索引擎,可以根据标题,作者等等检索图书,检索页包含图书标题、价格、评分、评论信息
我们设计数据库的时候,一般会这么设计:
- 图书基本信息表 (c_id, c_title, c_authors, c_publish … )
- 价格表 (c_id, c_price, c_discount …)
- 评分表 (c_id, c_score …)
- 评论表 (c_id, c_comment_count …)
- 首页推荐图书(c_pos, c_ids)
- xxx
- xxx
实现前3个需求并不太复杂,读取每个表中的数据到内存,得到一个数据集,然后输出静态页面即可。但是需要读取很多个表,然后合并数据,这个操作仍然是很繁琐的(相信你不会去用一条sql联合很多个表吧),并且,随着运营需求的变化,需要读的表会越来越多,我们需要不断的调整程序,以读取更多的表。第4个搜索的需求就比较麻烦一些了,本来我们有sphinx可以用,但是由于表的复杂关系,sphinx没法用。
如果这些信息都存在一张表中,上面的问题可以迎刃而解。比如这样:(c_id, c_title, c_authors, c_publish, c_price, c_discount, c_score, c_comment_count ) 但是这种DB设计是不可接受的。原因有很多:
- 单条记录过长,DB效率低
- 模块耦合度大,所有的模块都通过DB耦合在一起了
- 更重要的,如果我们某个模块的存储结构不是mysql db怎么办呢。
我的设计方案:
表结构的设计和我们前面讲的一样,但是增加一张中间表,即那张包含了图书所有信息的大表(c_id, c_title, c_authors, c_publish, c_price, c_discount, c_score, c_comment_count … )。我们的程序每隔一段时间(比如2分钟),把其他表中的数据merge起来同步到这个大表。我们前面需求中的业务逻辑都通过这张大表进行。现在只要一条sql就可以读到所有图书的信息,然后我们用这个信息生成页面就可以了,不用再merge任何表。
这个设计方案可能的缺点有哪些呢?
- 单条记录过长,效率低。效率确实会低,但是没有关系,我们这个表是只读的,用来生成页面的,用来检索的,慢一点儿有什么关系呢?如果你还嫌她慢,那就增加一层memcached/redis/leveldb的缓存好了。
- 实时性问题,由于这个中间表是定时更新的,所以肯定有几分钟的延迟,但是有什么关系呢,除了详情页中的价格和评论数,其他的信息都不是敏感信息,只要我们在详情页中实时获取这些敏感信息就可以了。
所以这些缺点都不是太大的问题。
这个设计方案有什么优点呢?优点就多了
- 解决了搜索的问题,让我们尽情的用sphinx好了,即使数据存储在了非mysql的存储结构中,我们只要能把数据导入到这个中间表,sphinx依然可用,而且只要一条简单sql就搞定;
- 简化了程序开发,所有获取数据的过程都是1条sql搞定;
- 减少了程序耦合,如果没这张中间表,如果我们想把其中一个模块迁移到其他DB或非DB的引擎,那么很多程序都得修改,现在只要我们修改同步数据到中间表的程序就可以了。