我们总想寻找锤子来处理眼前的这个钉子,然而,说不定这里压根就不需要用到钉子呢。

事情是这样的

回流是传统行业麾下的一款互联网产品。正常情况下,数据量会逐渐增大,但是膨胀速度并不会说特别快。然而,只要有足够的时间,数据量总会到达一定程度。此时系统的某些部分就会渐渐变得缓慢,有些查询的速度会变得不忍直视。

回流是有自己的管理端的(基于React),当时是为了让自己人可以舒服一点,用空闲时间孵化的一个项目。无论是可扩展性还是交互体验应该会比ActiveAdmin强不少。只不过投入的精力有限,还有很大的优化空间。万万没想到,近期的性能问题就出在管理端。同事们映有时候加载一个列表页面需要5s左右的时间,几乎是处于一个不可用的状态。

后来发现,归根结底还是数据查询(搜索)不够快拖慢了整个请求,毕竟数据量摆在那里。

> Backflow.search_by_admin('订单号').order('backflows.received_at DESC')
  Backflow Load (2838ms)  SELECT "backflows".* FROM "backflows" LEFT OUTER JOIN "goods" ON "goods"."backflow_id" = "backflows"."id" LEFT OUTER JOIN "logis.....
=> #<ActiveRecord::Relation []>
irb(main):003:0> Backflow.count
   (55.9ms)  SELECT COUNT(*) FROM "backflows"
=> 332690

在30w条数据中,要在联表的情况下做模糊查找并排序,一次操作要花费2838ms,也难怪一个页面要加载好几秒的时间(业务团队居然忍了很长一段时间都不反馈过来)。作为一个技术宅,脑海中下意识就浮现出好几种解决方案

  1. 添加合适的索引(感觉索引能治百病)。
  2. 优化查询条件,看情况引入数据库全文搜索。
  3. 引入ElasticSearch这种主流的搜索解决方案。

下意识地想要一步到位地选择方案3,由于对接下来要做的事情很有信心,便告知团队,即将要用酷炫的搜索引擎技术来优化整个站点的搜索体验了。

你真的需要那么多数据吗?

在笔者疯狂调研全文搜索引擎的时候,有一天业务团队被卡到不行了,问我啥时候能优化好,因为实在是影响工作效率。要上ElasticSearch并不是那么容易的事情,却无法跟大伙解释这点,他们能看到的就只是系统卡不卡,才不管优化难度大不大呢。

考虑到业务团队在日常货品上架的过程中最常操作的就是最新的一些订单,绝大多数情况下其实也没必要从所有历史数据中进行搜索。于是做了个应急优化搜索范围限制在最近一个月,要是遇到搜索不到的情况,再联系笔者帮忙寻找对应的订单,而且这种情况应该极少。然而就在交代这些的时候,笔者突然灵机一动。

为何要执着于优化全局范围内的搜索性能呢,上架部门顶多就只需要几个月范围内的数据。一定有更简单的解决方案。

最后选择了如下解决方案:

  1. 管理端限制筛选范围,默认只显示最近两周的数据,默认搜索范围也是两周。
  2. 如果搜索无果,同事们可以选择更早之前的时间段做进一步的查找,但时间范围的长度不得超过一个月,以免数据太多造成卡顿。
  3. 多往前翻几个月没有数据就基本可以判定用户近期没有下过对应的订单,可以引导用户先做下单操作。

这并不是什么了不起的优化手段,也没有引入新的技术,不过对于后台管理软件来说已经足够用了。只不过是默认限制了一下时间范围而已,改动小,带来的效益却很大。默认搜索条件能满足80%以上的场景了,搜索性能提高了10倍不止。

我们总会下意识地寻求更新更酷炫的技术来解决眼下的问题,然而大多数的情况下远水难救近火。结合实际的场景,说不定会有虽看起来朴实无华,但是却更简单实用的解决方案。

路漫漫

笔者这次的优化,放在后台场景是十分合适的,优化效果也很好。然而,如果放在App端就不一定了,毕竟App的用户多,搜索需求大,限制了搜索范围,很难满足大部分人的要求。在App端的搜索接口,还真的要考虑用全文搜索的解决方案呢。笔者也会继续对ElasticSearch做调研。