某滴面试题,请教答案 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
nightspirit
V2EX    职场话题

某滴面试题,请教答案

  •  
  •   nightspirit 2020-12-16 22:17:29 +08:00 5917 次点击
    这是一个创建于 1759 天前的主题,其中的信息可能已经有所发展或是发生改变。

    订单列表上,用户可以看到他下的单一页的,好多,那么表数据很多有好多亿条,那么怎么设计?

    答:水平分表,使用用户 id 做 hash

    那么已知订单 id,怎么获取订单详情?

    答:union 订单表

    上万的表直接联合么?

    思考。。。答:可以维护 uid->订单 id 的 k-v 结构在 redis 中

    扩展下,已知 XX (忘了啥字段了,当时紧张了)获取订单详情呢?

    答:那就存个 hash 对应关系

    司机的 APP 也能显示订单,怎么获取呢?

    思考。。。答:不会了,之前公司都是千万级数据,没做过水平拆分

    面试官怒了,你可以滚了,回去等消息吧

    好的,我滚了。。。。(确实没做过啊,能想的我都想了)

    当时太紧张了,前面的算法没答上来,有点自暴自弃,现在想想有了点答案了,只是我不知道对不对,请教大神这题答案

    第 1 条附言    2020-12-17 08:45:36 +08:00
    我自己想的是,冗余一个表,看各位回复我这答案肯定是错的
    第 2 条附言    2020-12-18 11:52:42 +08:00
    6 楼。hbase,这种没用过,没经验,不是很了解是否可行
    7 楼,分享的单表优化,表示感谢
    26 楼 存 json 数组法,没怎么搞过,不知道 json 数组的增加有何影响
    剩下的总结分两种:
    1.用户 id 取模分表&&司机 id 取模分表 [订单表冗余] +订单 id 基因
    2.用户 id-订单 id 和 司机 id-订单 [关系冗余] +订单 id 取模分表
    我更倾向关系冗余法,我觉得订单表数据字段会多,只冗余关系更好一些,和同事讨论了一下也觉得冗余关系更好些
    应该没漏掉啥吧?不知道还有没有好的方法
    37 条回复    2020-12-18 13:22:46 +08:00
    oppoic
        1
    oppoic  
       2020-12-16 22:24:49 +08:00 via iPhone
    那是面试官原话吗?
    nightspirit
        2
    nightspirit  
    OP
       2020-12-16 22:26:37 +08:00
    @oppoic 滚那个不是,我内心虚拟的,但能感觉面试官的鄙夷,前面算法还有锁的问题 我都答错了
    wellsc
        3
    wellsc  
       2020-12-16 22:32:11 +08:00 via iPhone
    橙心优选还是出行啊
    uiosun
        4
    uiosun  
       2020-12-16 22:43:24 +08:00
    坐等答案,这个数据体量,这种问题,该解决啊……
    jandou
        5
    jandou  
       2020-12-16 22:50:02 +08:00 via iPhone
    以前问过同样问题,他们家常规题目。
    beidounanxizi
        6
    beidounanxizi  
       2020-12-16 22:53:54 +08:00
    nosql hbase 可以做查询 另外 滴滴面试官 嗯 不说了
    水平分表的话 排序 join 都不好操作
    感觉楼主也是个憨批 有啥好怕的
    opengps
        7
    opengps  
       2020-12-16 22:55:47 +08:00   2
    很多时候考察的不是是不是会做,而是会不会去思考这种问题。
    我以前 gps 项目面试也这么问过,然而能有思路的人太少,当然不像滴滴这么有实力可以挑面试的人

    订单表作为需要联合查询,可能我分享的单表逻辑不适用,不过可以发出来分享下,外加其他比如一主多从等方案的结合应该可以适当提高下得分 https://www.opengps.cn/Blog/View.aspx?id=284&from=v2ex
    fantastM
        8
    fantastM  
       2020-12-16 22:57:51 +08:00
    订单 id -> 用户 id,用户 id -> 订单 id
    fantastM
        9
    fantastM  
       2020-12-16 22:59:16 +08:00
    #8 这两个关系都存一下
    Vegetable
        10
    Vegetable  
       2020-12-16 23:03:29 +08:00   1
    这提问方式压迫感挺强的,后续问题都是基于你的答案提的,挺考验临场水平的。

    我感觉你后边的问题没答出来不是因为没有答案,而是他前边给的需求太少,按照这种条件给出来的答案本来就是设计不足的。

    单纯的寻求这个答案好像不是很重要吧,超纲了等答案
    CEBBCAT
        11
    CEBBCAT  
       2020-12-16 23:46:10 +08:00 via Android   2
    楼主的第一段我实在读不通畅
    nightspirit
        12
    nightspirit  
    OP
       2020-12-17 08:41:25 +08:00   1
    @CEBBCAT 语文功底不是很好,他的意思是用户可以看到他所有下的订单,我们好多用户,订单表很大,我们怎么处理订单表
    nightspirit
        13
    nightspirit  
    OP
       2020-12-17 08:43:42 +08:00
    @beidounanxizi 因为面试机会少,有点患得患失
    rocky114
        14
    rocky114  
       2020-12-17 08:47:42 +08:00
    司机的 APP 也能显示订单,怎么获取呢?

    司机应该常看的订单就是六个月吧?六个月内的数据维护一份 map,六个月之前的数据查询慢就慢一点吧
    nightspirit
        15
    nightspirit  
    OP
       2020-12-17 08:50:15 +08:00
    @wellsc 做外卖的,不知道是哪边,我不熟
    GBdG6clg2Jy17ua5
        16
    GBdG6clg2Jy17ua5  
       2020-12-17 09:12:03 +08:00 via iPhone
    对这类问题表示关注,等大神来回答
    cxshun
        17
    cxshun  
       2020-12-17 09:17:28 +08:00   1
    @nightspirit #15 一般情况下,你要分表就需要按多维度去分,比如订单表,有可能按用户查,也有可能按订单查,那 OK,我们就按 [用户 ID] 和按 [订单 ID] 两个维度去分表,冗余多一个表。查询的时候根据不同条件查不同的表,也就是分不同的 DAO 或 Mapper,我们之前就是这样做的。
    当然,其实还可以上 ES 的,当量大到一定程度,比如上亿,mysql 有可能撑不住,那上到 ES 是自然而然的事情了
    simapple
        18
    simapple  
       2020-12-17 09:19:34 +08:00
    原则上规避 io 瓶颈,先用设计策略,快速查询到必要的查询条件,再通过一个可控制数据返回量的条件查询,查出单个 request 需要的数据。如果必要,再设计预查询策略,在资源可用的情况下,提前准备好下一个 request 的数据。
    nightspirit
        19
    nightspirit  
    OP
       2020-12-17 09:23:56 +08:00
    @cxshun 多谢 思路多了起来
    zardly666
        20
    zardly666  
       2020-12-17 09:37:32 +08:00
    能想到的就是每个用户都冗余维护一个订单列表的缓存项。在下单逻辑的时候,实时把缓存更新,查的时候就是秒查了。。坐等大神解答
    wellsc
        21
    wellsc  
       2020-12-17 09:38:09 +08:00 via iPhone
    @nightspirit 滴滴外卖不是几年前就无了,难道是滴滴海外?
    DebugTy
        22
    DebugTy  
       2020-12-17 10:04:08 +08:00
    如果真的是详情数据落在了很多表里面需要聚合, 这个可以考虑用宽表 tidb 把所有信息聚合到宽表中, 如果订单需要筛选可以先查询 es 只筛选出订单号, 再去查 tidb 补充详细信息;
    nightspirit
        23
    nightspirit  
    OP
       2020-12-17 10:05:36 +08:00
    @wellsc 海外
    rming
        24
    rming  
       2020-12-17 10:17:17 +08:00   3
    基因法,让大部分查询条件都带上用户 ID 的基因,冗余关联表也是个办法,还是回答不够系统和完整,可能面试官期望回答是一套系统的总结分析和实践经验
    murmur
        25
    murmur  
       2020-12-17 10:23:03 +08:00
    @zardly666 这个是微博和朋友圈用的逻辑啊,每个人冗余一条时间线,不要求实时性只要求缓存定时更新就可以

    订单这种实时性的怎么做
    lasuar
        26
    lasuar  
       2020-12-17 10:35:06 +08:00   1
    还是没太看懂描述,说说我的理解:
    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 )。

    个人愚见。
    yzbythesea
        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
    f12998765
        28
    f12998765  
       2020-12-17 13:54:27 +08:00
    第一反应是来个 kylin 吧
    DoctorCat
        29
    DoctorCat  
       2020-12-17 15:44:19 +08:00
    公有云上丢 DynamoDB 给他看 ,私有化部署用 Cassandra
    告诉面试官:您知道么,mysql 不能 allin 所有的业务场景的。
    zhengdai1990
        30
    zhengdai1990  
       2020-12-17 15:53:19 +08:00
    走 ES 啊,哈哈哈哈哈
    lewis89
        31
    lewis89  
       2020-12-17 17:32:58 +08:00
    所有的分库分表实际上 处理问题的方式 都是差不多的,要么冗余数据 要么冗余关系
    zhangyp123
        32
    zhangyp123  
       2020-12-17 18:03:05 +08:00
    基因分库 + 数据冗余 解决 “多 key” 类业务 参考: https://cloud.tencent.com/developer/article/1689831
    melkor
        33
    melkor  
       2020-12-17 18:49:28 +08:00 via iPhone
    单据维度数据按 ID hash 拆分存,用户维度的存用户 ID 到单据 ID 的映射,司机维度的也一样。用户也不会一次看所有的单,可以按用户维度预缓存一页的单。如果用户要看后面的单再去查存储。
    nightspirit
        34
    nightspirit  
    OP
       2020-12-18 11:29:01 +08:00
    @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
    yzbythesea
        35
    yzbythesea  
       2020-12-18 11:37:24 +08:00
    @nightspirit 是的。甚至 order table 也可以是 nosql,然后 order 的内容纯成 json,读到你 service 里在取各项的值。

    想了下觉得 driver ID -> order ID 要好一些。因为同用户肯定乘坐了不同的司机。
    nightspirit
        36
    nightspirit  
    OP
       2020-12-18 11:40:20 +08:00
    @lasuar 分页,他意思是订单表太大,怎么查订单列表
    你说的这个我不是很理解 uid 和 order_list 的关联关系数据量怎么会小于用户表?用户对订单是一对多的关系,那如果是 order_list 存数组,你说的数组增加影响可以忽略,我没这么做过,不了解,还有就是用户表了,我认为滴滴用户也不少,有可能一人有多个账号,我觉得数据量也不小。
    lasuar
        37
    lasuar  
       2020-12-18 13:22:46 +08:00
    @nightspirit 我写的应该足够清晰,你可以在读一遍; user 表是否再分表也是没关系的。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2424 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 15:34 PVG 23:34 LAX 08:34 JFK 11:34
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86