背景图

我的历史订单列表的实现

源起

最近面试了一家小公司,可惜小公司的面试体验并不好,首先是他可能在一个带有回音的房间中和我进行电话面试,带有很大的回音导致我听不清他在讲什么。还有就是苛责细节,给我的感觉是没有全局的视野,因为问的问题太过零碎和基础。

我觉得最不爽的一点是问了太多关于数据库执行计划的问题,可是蚂蚁集团内部都是使用OB,执行计划和MySQL有太大的差异,我已经好久没见过MySQL的执行计划了;而且一般系统开发过程中我们不会使用复杂的SQL,特别是微服务化之后,复杂SQL出现的可能性也是大幅降低;我们也不会紧盯着执行计划,因为大部分的SQL即时你不去查执行计划也不会有太大的问题,因为SQL简单,索引怎么走都是固定,很少出现复合索引的情况。可这哥们一直问,就是希望我把执行计划里面的字段描述清楚,我在想有必要这样教条吗?有些东西知道思想就行了,没必要死记硬背。

期间他问我了一个他们的问题就是他们的用户的访问记录需要给用户展示的问题;我当时就想到了历史订单这样的功能。这个功能在淘宝、京东这样的平台肯定不是通过数据库来进行实现,而且京东和淘宝的历史订单还经常出现订单出不来的问题,至少我的淘宝账户和京东账户都出现过类似的问题,历史订单根本显示都是错的。他问我怎么利用数据库进行实现,我当时就想这么简单的问题,建张表,然后建索引,offset不就ok了么,这个问题有啥好问的。最后给了我一个评价经验不符合,好吧我也是服。

思考

可这哥们死命的追问,我就反问他你是不是要分表分库,他似乎还不满意,搞得我很郁闷。所以我们来看看这哥们究竟想问啥,也好对历史订单这样的场景做一些更深入的思考。

我们可以看出他们的数据库是没有分表分库的,也就是说只能进行单表的优化。可是用户访问记录这个是个大数据量的东西,放在单张表中一定会出现数据量过大的问题。一般我们都是走缓存的方式进行实现,但是缓存不是存储,我们还是会在数据库中进行存储,而进行存储我们也不可能存单表,必然会进行分表分库的存储。对于用户访问存储db比较简单;那么如何去读呢?这里一般是通过es、solr这样的搜索平台进行存储,或者redis存一些最近的数据,但是无法存储全量的数据。之前我翻过滴滴的历史订单,那个速度是真的慢,可能就是在查历史记录表。

关于分表分库,这里可以通过用户分表,这样就可以对时间进行排序而不用担心数据分散而带来的排序问题。

好了我们回到之前的那个问题,那么对于该哥们的场景又该做何种优化呢?其实优化的方式也比较简单就是减少表中记录的数据。那么如何减少表中的数据呢,答案就是合并. 比如将用户的访问记录记录在一条记录上,同时记录最近访问的时间,访问记录的条数等等,然后将用户的访问记录统统塞入一个大的JSON中,这个JSON是默认排好序的,另外结构是固定的,也就是说一条记录占用的字节数不会有太大差异,读取时不用读出所有的记录;但是这个也有缺点,字段太大维护比较麻烦。但是也可以以月、日的方式进行记录。也可以用条数打包进行记录,这样分页也比较方便实现。另外写入的数据也不能同步去写,需要加一层缓存队列,这层缓存必须是可序列化的,比如Redis。

其实我这种方案比较适合ES这样的结构存储或者MongoDB的方式进行存储,其实就是文件存储的NoSQL方式。如果按照HBase的存储方式的话就更方便了。rowKey就是用户,family就是时间了,值就是某用户这段时间的访问量详情。

扩展

一般情况下,你还会发现,你浏览商品时会出现已买过,已看过等这样的标记,那么这个又该如何进行实现呢?其实这里分两个维度

  1. 商品上记录最近访问或购买的客户,记录有多少人最近浏览过。一层小缓存,因为只能记录最近访问的,可以设置一个极限值,同时加一个标表示是否超过极限值。这样有时就不用查用户维度的缓存了。
  2. 用户维度记录访问或购买的商品ID列表,我觉得这个实现起来还算比较简单吧。

对了如果商品下架,那么的用户维度的列表就可以进行一些清除策略,但是这种清除策略一定是懒清除策略。而商品维度就不需要进行修改。

存储最好有序地存储,这样便于二分查找,每次插入的时候也是二分查找式插入,一个有序的列表的维护其实花不了多少时间。

下面就是商品页面静态化的问题,有些信息可能是包含在静态化里面的,有些不是。

0%