-
2008-08-07
秒杀十分钟
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://dreamhead.blogbus.com/logs/27386412.html
我们系统有一个发布的功能,这个发布非常慢,因为它牵扯到很多内容,所以,我们把这个发布变成了异步操作。不过,最近一段时间,这个发布变本加厉的慢了,据PM在UAT上测试的结果,发布一次要5个小时。于是,我今天决定看看为什么这个发布会慢到这个地步。
当我分阶段为这个发布过程加上日志之后,定位到了一个非常慢的方法。我简单测试了一下这个方法,耗时在十分钟以上。这个方法要做的是,如果一个对象所关联的一些对象都已经被废弃的话,那么就把这个对象废弃。这里的废弃实际上就是一个标记的工作。说起来很简单,但是真正理解这个方法所做的事却花了我很多时间,这段代码的实现是这样的:
* 它在关联对象的表进行查找,找到那些那些关联对象都已经废弃的情况,然后,找到这些关联对象所指的目标对象,也就是这些目标对象应该废弃,由此得到一个目标对象数组。
* 遍历目标对象表,如果这个目标对象在目标对象数组中,那么把它标记为废弃。确实不好理解吧!如果你理解了这段代码的意思,你可能会问为什么会这么做,我也想知道。
当我用产品数据库进行测试时,第一步产生的目标对象数组包含超过12000个对象,而第二步遍历目标对象表则有近8000个对象。那么判断目标对象是否在目标对象数组的操作就是一个上亿规模的操作,这是这个操作缓慢的原因。可以预见,随着这个系统使用的增多,这两个表里面的内容会越来越多,这个操作的规模会越来越大,那么这个方法就会越来越慢。
之前曾有同事解决过一个问题,就是这里。问题是这样的,这里的操作有很长时间没有访问数据库,所有有时候,数据库连接会超时。我在这里做了一个统计,真正需要标记为废弃的对象大约只有800个,而前面提到了,这是一个上亿的数据规模,也就是说,大部分时间,系统是在空跑,而且你知道,Ruby并不是以高性能著称的程序设计语言,所以,会长时间没有任何操作。当时的解决方案是,定期进行一个对连接进行verify,告诉连接我们还活着。这是一个治标不治本的解决方案。
简单分析一下,我们便不难发现一些问题:
* 目标对象表一共只有8000个对象,为什么目标对象数组会超过12000。
* 既然目标对象数据包含了所有要废弃的对象,为什么还要遍历目标对象表。
简单这样一想,似乎解决方案就在眼前了,删除第二步操作,把第一步得到的数组做uniq,去除相同的内容,然后,遍历得到的数组,将所有的目标对象废弃。按照这个思路,把对象拿到内存中,进行处理的话,那么我们要做的是,把所有的对象找出来,然后遍历,修改状态,之后保存数据。内存操作虽好,但最终还需要写回数据库,这样算下来,这里要进行的数据库访问就是1(查找)+ N(保存)。
且慢,我们的目标是什么?其实,这只是一个标记对象的过程,也就是一个更新表中一个字段的操作,解决问题的关键就在于如何写更新条件。更重要的是,如果这样做的话,一条SQL语句就可以搞定问题。
好吧!我承认,我是一个SQL白痴。但我可以找到人帮忙,于是,我请了一个DBA帮忙,果不其然,当DBA明白了这里的需求,很快就帮我们写出了所需的SQL语句。
当我们敲下回车的时候,瞬间操作就完成了。大于十分钟的操作,再见了!
引用地址:
《秒杀十分钟》之后
Blog:梦想风暴2008-08-09 23:42:21










评论