大型网站中,大量用到了多对多关系,传统的处理方式无法满足高并发的性能要求;通过冗余和缓存等方式,可以有效解决这方面的问题。
传统多对多的处理方式
就拿文章标签来说吧,一个文章可以有多个标签,而每个标签又可以对应多篇文章,这又是一个几何乘积,数据量也会是天文数字。传统的处理方式有三种:第一种是通过SEARCH的方法来实现;第二种是通过另建一个索引表,放置对应的ID以进行存贮;第三种是通过二次归档缓冲来实现。
对于第一种方案,因为要涉及大量的LIKE查询,性能不够理想。第二种情况下,数据库表中的惊人行数也是量级别的。要维护索引表的散列处理,并且要跨表跨区查询,还维护数据的唯一性。数据处理过程相当复杂,性能表现低下。
以标签和文章之间的多对多关系为例来讲解第三种方案:当一篇博文发布并插入标签时,一般是三步走:第一步插入文章数据库并获取文章的ID;第二步插入标签数据库同时查询标签是否存在,如果存在就取出标签的ID,否则的话插入新标签并取出ID;第三步,将文章ID和标签ID插入索引表来建立关联,那就是灾难性的,特别是在数据量大的情况下,尽管它可以有效提高查询速度,但是发布的速度可能就会让人无法忍受了。
多对多优化处理的四部曲
第一步:数据冗余
可以对文章做冗余,加一个TAG列,将标签这样写:[TAGID,TAGNAME]|[TAGID,TAGNAME]|[TAGID,TAGNAME]。同样,对于TAG表,作如下冗余:加个ARTICLE字段,比如[ARTICLEID,TITLE]|[ARTICLEID,TITLE]|[ARTICLEID,TITLE]。增加TAGNAME和ARTICLETITLE,是为了避免跨表查询和INNER JOIN查询。IN查询和跨表查询会造成全表遍历,所以必须要为IN查询找到一个有效的替代方法。
第二步:异步存贮
是一种另类的单件模式处理方法,就是把文章和标签之间的索引作为专门的进程来做异步实现。一般来说,在发布文章的时候,经常会因为要检查TAG表造成线程拥堵。为了避免这种情况,可以采取延迟加载方案。服务器应该维护一个进程,专门对标签和文章进行查询和索引。在发布文章时,我们还可以把标签同步这一块托管给另外的一个进程或者服务器进行处理,并进行索引。
第三步:二次索引
对于需要频繁判断的热门标签,我们可以在内存里组织一套有效的索引,对应常用标签,设计内在索引。
第四步:针对跨表查询的处理
很多情况下,我们可能避免不了多表查询,或者IN、OR查询。利用许多查询是频繁而且统一的特点,如SNS中常见的性别、嗜好等多条件索引因可能存储在多个数据表结构中而关系产生的全表遍历查询。除去业务层封闭分区视图集群之外,把原来散列的、垂直分割的表再合并起来,放到另外的只读订阅服务上,然后做适当的结构优化和索引,即可以对服务器进行横向扩充。
基于高并发数据库的缓存方案
在数据飞速膨胀和并发呈几何级增长的情况下,UPDATE经常会超时。基于高并发数据库的缓存方案(数据缓冲/异步更新数据)是一种有效的解决办法。
实现原理:将并发的更新首先缓存到一个应用程序池中,然后定时查询。传统的UPDATE请求处理流程是:请求-应用程序-更新数据库,将流程变更为:请求-应用程序-数据缓冲池-数据更新服务-数据库。数据缓冲和更新部分可以在数据层里独立实现,也就是UPDATE传递时,首先传递缓冲池,然后定时更新。要注意:数据缓冲池还要做全局的数据缓存,缓存数据更新到数据这段的时间间隔,可以理解为临时表。