V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
mawerss1
V2EX  ›  MySQL

一个表设计问题

  •  
  •   mawerss1 · 2020-04-20 09:44:13 +08:00 · 4947 次点击
    这是一个创建于 1680 天前的主题,其中的信息可能已经有所发展或是发生改变。

    业务场景是保存物流动态信息 物流动态目前看一般情况下只会进行 append,不会修改和删除中间的行

    问题: 两种建表方式那种更好一点

    1. 具体的物流动态用单独的表保存。 比如:
    表 A 保存订单 id 和状态
    id tid  status
    
    表 B 保存具体物流动态信息
    aid content time 
    
    2.物流信息保存在上面的表 a 中和订单状态放在一起,用字符分割,在程序中解析字符串,插入时使用 concat 链接字符串
    
    表 A 中的数据单表大概有 500w 条,如果按第一种方式,假设每个订单平均 5 个动态,就要 2500w 行,按第二种设计方法是否会有问题?
    
    第 1 条附言  ·  2020-04-20 13:59:02 +08:00
    场景没写清楚,这里不保存订单信息,只是单纯保存物流动态,第一种方案里 A 表保存的是当前物流中转节点,不是订单状态,这里的表本身没有订单数据
    第 2 条附言  ·  2020-04-20 14:03:00 +08:00
    重新梳理之后再看第一种方案,好像只需要一个表,保存物流动态
    id | tid | 运单号 | 物流公司名 | content | time | status
    第 3 条附言  ·  2020-04-20 17:42:07 +08:00
    读多写少的场景,物流动态可能每天最多有 2 次写入,查询频繁,物流签收之后也不会再更新,最后选第二种
    第 4 条附言  ·  2020-04-20 17:43:39 +08:00
    想错了还是第一种吧
    30 条回复    2020-04-20 18:22:14 +08:00
    privatetan
        1
    privatetan  
       2020-04-20 09:50:50 +08:00 via iPhone
    哈哈哈哈哈 我昨晚上睡觉前想了一个类似问题 没想到今天就有人来问了
    Vegetable
        2
    Vegetable  
       2020-04-20 09:57:30 +08:00
    我来设计会选择第一个。
    数据量不算问题,毕竟查询简单。
    yongjing
        3
    yongjing  
       2020-04-20 09:59:27 +08:00 via Android
    第一个
    mawerss1
        4
    mawerss1  
    OP
       2020-04-20 10:01:13 +08:00 via iPhone
    @Vegetable 其实第一种设计我认为是有些浪费的,查询只会按照订单来查,不会查询单个动态详情,这样物流动态的索引其实是用不到的?
    Egfly
        5
    Egfly  
       2020-04-20 10:01:20 +08:00
    选第一个。 第二个方案可以改进一下,把物流动态信息用 json 格式存起来。这样一个订单就一条数据
    linxb
        6
    linxb  
       2020-04-20 10:09:01 +08:00
    选第一个,简单便捷清晰
    littleylv
        7
    littleylv  
       2020-04-20 10:11:02 +08:00
    我个人毫不犹豫选 1
    xuanbg
        8
    xuanbg  
       2020-04-20 10:14:36 +08:00   ❤️ 1
    第一个简单,开销也低,因为只管 insert 就行。第二种就要先读出来,然后拼接,然后 update 。不说数据库操作 select +update(delete+insert)比 insert 开销大得多,业务逻辑也复杂了很多。省那么点存储空间,脑子瓦特了……
    Vegetable
        9
    Vegetable  
       2020-04-20 10:15:44 +08:00
    @mawerss1 第一个对于开发者来说,需要做的事情更少。浪费点资源可能大家不太在乎
    lancelock
        10
    lancelock  
       2020-04-20 10:23:03 +08:00
    用 pg,json 存
    index90
        11
    index90  
       2020-04-20 10:28:23 +08:00
    要看是读多写少还是写多读少啊。
    读多写少用第二种,写多读少用第一种。用列存储的话用第一种,如果是 B 树存储结构的用第二种,B+的可以考虑第一种。

    如果第一种,aid 不能使用自增 id,需要自己生成和 tid 有关的 id,否则 B 表横向扩展会有问题。
    mawerss1
        12
    mawerss1  
    OP
       2020-04-20 10:41:38 +08:00
    @index90 横向扩展能详细讲讲吗,现在只做了分库没做分表,分库是按用户 id 分的
    x66
        13
    x66  
       2020-04-20 10:50:15 +08:00
    感觉很适合使用时间序列数据库
    ISSSSSSS
        14
    ISSSSSSS  
       2020-04-20 10:52:15 +08:00
    看情况,如果是专业的物流公司,必然选择第一种。如果是普通电商小公司,我会选择第二种。
    首先第一种设计的很严谨,但是带来的数据行数过大。一个订单平均有 10 个左右的物流行数,不划算。而且设计的这么严谨其实没有用处。
    第二种设计方式虽然看着简陋但很实用。能有效减少行数,适合小项目。至于有人说 update 复杂,其实数据处理完全可以放在应用中。
    个人建议:
    1 按状态分表。//因为物流信息一般是在订单未完成之前才关注,订单完成后几乎就是死数据,所以不妨在订单完成后,将此类数据迁移到另一个表。
    2 增加缓存。//缓存按照 30 分钟进行刷新,避免用户着急刷新物流而导致的查询数据库过多。
    3 换一个数据库 比如 mongo 或 ES 。
    arthas2234
        15
    arthas2234  
       2020-04-20 11:02:50 +08:00
    订单表的数据量多少和物流信息查询快慢没有必然关系
    一般来说订单列表中不会返回物流信息的,只有在订单详情里面返回,这种查询效率很快的

    按照第二种方法,特定的查询会很麻烦,如果用 json 来储存的话,如果物流信息的 json 结构改变的话,也很麻烦
    mawerss1
        16
    mawerss1  
    OP
       2020-04-20 11:05:04 +08:00
    @arthas2234 商家应用列表里要返回物流信息
    tabris17
        17
    tabris17  
       2020-04-20 11:07:47 +08:00
    选用 postgresql,然后物流动态用数组类型字段保存
    DoUSeeMe
        18
    DoUSeeMe  
       2020-04-20 11:10:48 +08:00
    @index90 就针对 mysql 来说,这位仁兄的想法我深表赞同
    encro
        19
    encro  
       2020-04-20 11:13:20 +08:00
    当然选择第一种,
    虽然数据量大了数倍,但是因为订单 id 比较分散,那么性能是很高的;
    第二种你也防止程序源 select * 返回一堆信息;
    而且你自己需要的时候需要 select 再 append 。
    第一种就好办了,直接 append,每次都不需要查以前的。只在需要的时候再 append 。


    从软件工程角度来说,
    第一种物流和订单也更解耦了,物流依赖订单,订单不依赖物流。
    比如你可以先实现订单功能,有时间再实现物流追踪。

    甚至我以前做的一个海淘系统,订单和物流采用了不同的子系统,只能通过类似微服务的接口调用,这样保证重构系统的时候,接口不变就可以了。
    xieshaohu
        20
    xieshaohu  
       2020-04-20 11:52:53 +08:00
    选第一种,页面上加载订单信息和物流信息调用两个接口。原因 :功能解耦了,后台数据库负载低,应用接口也变得简单。
    index90
        21
    index90  
       2020-04-20 12:37:15 +08:00
    @mawerss1 横向扩展是指你需要考虑当一台机器已经无法满足你的容量需求时,在架构上能够扩展的能力。看你的数据量,很快单机就处理不了。例如你可能会将不同订单存储在不同节点上,这时候你需要有一个算法,根据 id 找出对应的存储节点,而同一个订单的 content 都存储在一个节点上,显然查询更友好。
    mawerss1
        22
    mawerss1  
    OP
       2020-04-20 13:59:39 +08:00
    @index90 目前是根据用户 id 来分库的
    RJH
        23
    RJH  
       2020-04-20 16:34:46 +08:00
    我建议选第一个,两张表存储,因为你根本不会知道后续会增加什么维度的查询。

    本来简单的表,后面可能会随着功能的迭代,增加越来越多的字段。
    fcoolish
        24
    fcoolish  
       2020-04-20 17:24:07 +08:00
    反正我选第一个,又不是不会分库分表,然后用缓存索引。
    还有数据量大直接从 es 查呗。
    jatesun
        25
    jatesun  
       2020-04-20 17:37:31 +08:00
    第一个还用选吗
    isleon
        26
    isleon  
       2020-04-20 17:43:39 +08:00
    第二种的话,后面突然让你加个字段你就欲仙欲死了。
    ZoR
        27
    ZoR  
       2020-04-20 17:47:27 +08:00
    第二个后期变更需求,维护会是个灾难
    leoskey
        28
    leoskey  
       2020-04-20 17:54:33 +08:00
    如果项目没死,第二种后期维护的确是个不小的问题。
    chimw
        29
    chimw  
       2020-04-20 18:20:40 +08:00
    物流信息可以存在时序数据库中,比如 influxdb
    newtype0092
        30
    newtype0092  
       2020-04-20 18:22:14 +08:00
    @index90 大佬 MySQL 大概多少数据量时需要考虑横扩呢?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3193 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 13:40 · PVG 21:40 · LAX 05:40 · JFK 08:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.