V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
nightspirit
V2EX  ›  职场话题

某滴面试题,请教答案

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

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

    答:水平分表,使用用户 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 做外卖的,不知道是哪边,我不熟
    angryfish
        16
    angryfish  
       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   ·   实用小工具   ·   1085 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:03 · PVG 03:03 · LAX 11:03 · JFK 14:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.