订单列表上,用户可以看到他下的单一页的,好多,那么表数据很多有好多亿条,那么怎么设计?
答:水平分表,使用用户 id 做 hash
那么已知订单 id,怎么获取订单详情?
答:union 订单表
上万的表直接联合么?
思考。。。答:可以维护 uid->订单 id 的 k-v 结构在 redis 中
扩展下,已知 XX (忘了啥字段了,当时紧张了)获取订单详情呢?
答:那就存个 hash 对应关系
司机的 APP 也能显示订单,怎么获取呢?
思考。。。答:不会了,之前公司都是千万级数据,没做过水平拆分
面试官怒了,你可以滚了,回去等消息吧
好的,我滚了。。。。(确实没做过啊,能想的我都想了)
当时太紧张了,前面的算法没答上来,有点自暴自弃,现在想想有了点答案了,只是我不知道对不对,请教大神这题答案
![]() | 1 oppoic 2020-12-16 22:24:49 +08:00 via iPhone 那是面试官原话吗? |
![]() | 2 nightspirit OP @oppoic 滚那个不是,我内心虚拟的,但能感觉面试官的鄙夷,前面算法还有锁的问题 我都答错了 |
![]() | 3 wellsc 2020-12-16 22:32:11 +08:00 via iPhone 橙心优选还是出行啊 |
![]() | 4 uiosun 2020-12-16 22:43:24 +08:00 坐等答案,这个数据体量,这种问题,该解决啊…… |
![]() | 5 jandou 2020-12-16 22:50:02 +08:00 via iPhone 以前问过同样问题,他们家常规题目。 |
![]() | 6 beidounanxizi 2020-12-16 22:53:54 +08:00 nosql hbase 可以做查询 另外 滴滴面试官 嗯 不说了 水平分表的话 排序 join 都不好操作 感觉楼主也是个憨批 有啥好怕的 |
![]() | 7 opengps 2020-12-16 22:55:47 +08:00 ![]() 很多时候考察的不是是不是会做,而是会不会去思考这种问题。 我以前 gps 项目面试也这么问过,然而能有思路的人太少,当然不像滴滴这么有实力可以挑面试的人 订单表作为需要联合查询,可能我分享的单表逻辑不适用,不过可以发出来分享下,外加其他比如一主多从等方案的结合应该可以适当提高下得分 https://www.opengps.cn/Blog/View.aspx?id=284&from=v2ex |
![]() | 8 fantastM 2020-12-16 22:57:51 +08:00 订单 id -> 用户 id,用户 id -> 订单 id |
![]() | 9 fantastM 2020-12-16 22:59:16 +08:00 #8 这两个关系都存一下 |
![]() | 10 Vegetable 2020-12-16 23:03:29 +08:00 ![]() 这提问方式压迫感挺强的,后续问题都是基于你的答案提的,挺考验临场水平的。 我感觉你后边的问题没答出来不是因为没有答案,而是他前边给的需求太少,按照这种条件给出来的答案本来就是设计不足的。 单纯的寻求这个答案好像不是很重要吧,超纲了等答案 |
![]() | 11 CEBBCAT 2020-12-16 23:46:10 +08:00 via Android ![]() 楼主的第一段我实在读不通畅 |
![]() | 12 nightspirit OP ![]() @CEBBCAT 语文功底不是很好,他的意思是用户可以看到他所有下的订单,我们好多用户,订单表很大,我们怎么处理订单表 |
![]() | 13 nightspirit OP @beidounanxizi 因为面试机会少,有点患得患失 |
14 rocky114 2020-12-17 08:47:42 +08:00 司机的 APP 也能显示订单,怎么获取呢? 司机应该常看的订单就是六个月吧?六个月内的数据维护一份 map,六个月之前的数据查询慢就慢一点吧 |
![]() | 15 nightspirit OP @wellsc 做外卖的,不知道是哪边,我不熟 |
![]() | 16 GBdG6clg2Jy17ua5 2020-12-17 09:12:03 +08:00 via iPhone 对这类问题表示关注,等大神来回答 |
![]() | 17 cxshun 2020-12-17 09:17:28 +08:00 ![]() @nightspirit #15 一般情况下,你要分表就需要按多维度去分,比如订单表,有可能按用户查,也有可能按订单查,那 OK,我们就按 [用户 ID] 和按 [订单 ID] 两个维度去分表,冗余多一个表。查询的时候根据不同条件查不同的表,也就是分不同的 DAO 或 Mapper,我们之前就是这样做的。 当然,其实还可以上 ES 的,当量大到一定程度,比如上亿,mysql 有可能撑不住,那上到 ES 是自然而然的事情了 |
18 simapple 2020-12-17 09:19:34 +08:00 原则上规避 io 瓶颈,先用设计策略,快速查询到必要的查询条件,再通过一个可控制数据返回量的条件查询,查出单个 request 需要的数据。如果必要,再设计预查询策略,在资源可用的情况下,提前准备好下一个 request 的数据。 |
![]() | 19 nightspirit OP @cxshun 多谢 思路多了起来 |
20 zardly666 2020-12-17 09:37:32 +08:00 能想到的就是每个用户都冗余维护一个订单列表的缓存项。在下单逻辑的时候,实时把缓存更新,查的时候就是秒查了。。坐等大神解答 |
22 DebugTy 2020-12-17 10:04:08 +08:00 如果真的是详情数据落在了很多表里面需要聚合, 这个可以考虑用宽表 tidb 把所有信息聚合到宽表中, 如果订单需要筛选可以先查询 es 只筛选出订单号, 再去查 tidb 补充详细信息; |
![]() | 23 nightspirit OP @wellsc 海外 |
24 rming 2020-12-17 10:17:17 +08:00 ![]() 基因法,让大部分查询条件都带上用户 ID 的基因,冗余关联表也是个办法,还是回答不够系统和完整,可能面试官期望回答是一套系统的总结分析和实践经验 |
![]() | 25 murmur 2020-12-17 10:23:03 +08:00 |
![]() | 26 lasuar 2020-12-17 10:35:06 +08:00 ![]() 还是没太看懂描述,说说我的理解: 1. 用户要在一页内显示完所有的订单(不分页?) 答:个人觉得可以在(user_order_ref)表内存储 uid 和 order_id_list 的关联关系,order_id_list 字段是 json 数组,mysql/mongodb 都可以容易的做 json 对象的操作,那么这张表的数据量就<=user 表,不会太大,也就不需要分表,那么这里就可以拿到用户所有的订单 id 。 (有的人也许会考虑部分 rows 的 order_id_list 字段过长带来的一些对表空间的影响,其实我认为可以忽略,因为一个用户的订单量上天了也不过几千几万,这点量不会有什么影响) 然后就像楼主说的,订单详情表使用订单 id 做 hash 水平分表,这里就能查到一个用户所有的订单详情了。 2. 司机的 APP 也能显示订单 答:司机 APP 显示自己的订单,其实与用户订单没啥不同,按照前面的做法,是可以实现按排序分页的(计算出要读哪些订单表,然后 union+orderby )。 个人愚见。 |
![]() | 27 yzbythesea 2020-12-17 10:41:34 +08:00 一般大公司面试两个技巧, 1. 存数据用 nosql 2. table 拆得越越好,别把逻辑分给 database 。 你这个可以是 3 个 table, order table, oder ID -> order user table, user ID -> order ID driver table, driver ID -> user ID |
![]() | 28 f12998765 2020-12-17 13:54:27 +08:00 第一反应是来个 kylin 吧 |
![]() | 29 DoctorCat 2020-12-17 15:44:19 +08:00 公有云上丢 DynamoDB 给他看 ,私有化部署用 Cassandra 告诉面试官:您知道么,mysql 不能 allin 所有的业务场景的。 |
30 zhengdai1990 2020-12-17 15:53:19 +08:00 走 ES 啊,哈哈哈哈哈 |
![]() | 31 lewis89 2020-12-17 17:32:58 +08:00 所有的分库分表实际上 处理问题的方式 都是差不多的,要么冗余数据 要么冗余关系 |
32 zhangyp123 2020-12-17 18:03:05 +08:00 基因分库 + 数据冗余 解决 “多 key” 类业务 参考: https://cloud.tencent.com/developer/article/1689831 |
33 melkor 2020-12-17 18:49:28 +08:00 via iPhone 单据维度数据按 ID hash 拆分存,用户维度的存用户 ID 到单据 ID 的映射,司机维度的也一样。用户也不会一次看所有的单,可以按用户维度预缓存一页的单。如果用户要看后面的单再去查存储。 |
![]() | 34 nightspirit OP @yzbythesea 我理解一下这三个表,看是你说的这样不 order table, oder ID -> order 订单 i 按照 id 取模分表 user table, user ID -> order ID 用户表 然后 nosql 存储用户 uid->订单 id driver table, driver ID -> user ID 司机表,nosql 存储 司机 id->订单 id |
![]() | 35 yzbythesea 2020-12-18 11:37:24 +08:00 @nightspirit 是的。甚至 order table 也可以是 nosql,然后 order 的内容纯成 json,读到你 service 里在取各项的值。 想了下觉得 driver ID -> order ID 要好一些。因为同用户肯定乘坐了不同的司机。 |
![]() | 36 nightspirit OP @lasuar 分页,他意思是订单表太大,怎么查订单列表 你说的这个我不是很理解 uid 和 order_list 的关联关系数据量怎么会小于用户表?用户对订单是一对多的关系,那如果是 order_list 存数组,你说的数组增加影响可以忽略,我没这么做过,不了解,还有就是用户表了,我认为滴滴用户也不少,有可能一人有多个账号,我觉得数据量也不小。 |
![]() | 37 lasuar 2020-12-18 13:22:46 +08:00 @nightspirit 我写的应该足够清晰,你可以在读一遍; user 表是否再分表也是没关系的。 |