目前在一家海外电商平台网站工作,我们有一个给会员送优惠券的功能,用户在下订单后可以使用优惠券享受一些相应的折扣,比如减价打折什么的。
在我们后台运营系统中,我们需要按照用户ID给指定用户发放优惠券,也需要对全体会员发放优惠券。给指定用户发放优惠券便是在相应表里插入对应记录,里面有字段 user_id,以及 discount_id 分别为用户和优惠券,最初给所有用户发放优惠券的设计方案是插入 user_id 为 0 的记录,表示这张优惠券发放给所有用户。这种方案是最直接也比较好理解的方案,但后来发现者并不是很好的设计,后来发现代码里面到处散落着对 user_id = 0 的判断,使得代码复杂了不少。还有一个问题就是,优惠券记录表里面还记录这优惠券使用时间,优惠券使用次数等数据,当我们用 user_id = 0 这个的设计后,这些数据就没法记录了。
后来着手优化给所有人发放优惠券,有同事提出,当给所有人发放优惠券时直接粗暴地遍历所有用户,每人都发放一张优惠券。但这种设计显然不合理,假设我们有 10 万用户,每次给所有人发放优惠券则一次插入 10 万条记录,太恐怖了,就是 10 万时还 OK,当用户数达到百万级别了呢。
我又想到,给所有人发放优惠券不一定需要立刻就在数据库里面插入该用户的记录,我们只需要在用户登录的时候把那条记录给他插入进去就好了。这样处理就将发放优惠券的时间打散在每个用户登录时。达到了给所有用户发放优惠券的目的同时不需要一下子就插入 10 万条记录。就是这样一个方案,我们后来又进行改进,因为考虑到,假设用户15点登录了网站,我们15点1分发放优惠券,这样用户也看不到他的优惠券,因为他没有再登录。最终我们的方案是,当去获取用户拥有的优惠券时,我们先同步一下发放给所有人的优惠券(检查到有发放给所有人的券,则发放给该用户并做记录,做记录是为了去重防止每次都去给用户发放相同的优惠券)到用户的优惠券里面。目前运行 OK。
就在我写这篇博客的时候,我又想到,user_id = 0 的设计其实也是可行的,只不过我们需要把用户拥有的优惠券和用户使用优惠券的使用记录分开另外用一张表来存储,实际上,这种方式才是合理的。