V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
go522000
V2EX  ›  问与答

请教一下关于 MYSQL,有一个订单的状态字段,用什么类型来设计比较好。

  •  
  •   go522000 · 4 天前 · 1945 次点击
    我现在数据库是使用 5.7 版本,但不熟悉 MYSQL ,所以习惯沿用以前旧的习惯。

    以下为我的作法,感觉很不合理,希望学习一下。

    比如:

    state int ( 2 ) ,表示:0 待支付,1 已支付,2 已发货...6 交易完成

    然后这个字段用 MYSQL 的注释把 123 这些表示什么注释好。

    或者增加一个新的字段,把不同的状态的名字存储起来,比如:

    state_value varchar ( 10 ) 。 用来记录状态的描述

    大概这样设计。



    然后就会遇到一些问题,假设未来增加一个备货中的状态,这个状态在 1 与 2 之间,就会很为难,那么在最后面增加一个 7 备货中,很奇怪的样子。

    -----

    搜索了一下,5.7 已经支持 JSON 格式了。

    那么未来新的项目是否可以设计为:state json 这种类型,把状态 ID 与描述一起存进去,比如:{state:1,value:'PAY_SUCCESS',description:'已支付'}

    类似这种方式?这样会不会在未来遇到排序很卡或者不好搜索之类啥的,影响非常大?

    或者,是否可以升级到 8.0 版本,支持 ENUM 类型?

    ENUM 索引会不会更快点?

    数据库小白,求指点。
    36 条回复    2024-12-09 10:59:00 +08:00
    dcsuibian
        1
    dcsuibian  
       4 天前   ❤️ 2
    直接存字符串,对运维最友好
    kk2syc
        2
    kk2syc  
       4 天前
    加个 7 最方便,不要代码洁癖
    Cu635
        3
    Cu635  
       4 天前
    感觉是要么就是只微调,不大动直接加个状态 7 ,不用管奇怪不奇怪了;要么大升级,“是否可以升级到 8.0 版本,支持 ENUM 类型”这种最合适,从根子上就不会奇怪的做法。
    nzynzynzy
        4
    nzynzynzy  
       4 天前 via iPhone   ❤️ 6
    有个客户的系统设计是 100 ,200 ,300…900 。这样你可以先用 100 ,200 ,等中间有了居间的再用 130 ,再精细还有 132 、133…感觉很合理。
    pweng286
        5
    pweng286  
       4 天前
    @nzynzynzy 还真是.
    coderYang
        6
    coderYang  
       4 天前
    @nzynzynzy 学到了,还真是,类似于 http 状态码一样的设计
    Bylinz
        7
    Bylinz  
       4 天前   ❤️ 2
    其实 1 2 3 4 只是你觉得的顺序,对程序来说,这随便什么都行。
    如果程序早期的定义看起来不舒适,可以通过文档弥补。
    不建议重新发明创造,因为你新加的东西也不一定能满足以后的需求,稳定才重要。
    go522000
        8
    go522000  
    OP
       4 天前
    @nzynzynzy 谢谢,是个好主意。
    Suaxi
        9
    Suaxi  
       4 天前 via Android
    同四楼大佬的做法,部分场景下排序字段的值我们这边也是这样设计的,中间间隔 10
    b821025551b
        10
    b821025551b  
       4 天前
    1 、int (2 )还是很大,MySQL 中 int 后面的只影响显示,用 tinyint 更好;
    2 、1->2->3 和 1->8->5 只是你理解的顺序不一样,对于程序没什么区别;比如一个审核流程,正常可以 1->2->->3->4->5 ;但是走到 3 是不是可以驳回到 1 ,或者是不是可以跳过 4 到 5 ,或者 3 之后 4 和 5 可以同时审核
    3 、不要用枚举!不要用枚举!! ENUM IS EVIL!!!
    icemanpro
        11
    icemanpro  
       4 天前
    @b821025551b 用枚举有什么问题?
    z1829909
        12
    z1829909  
       4 天前 via Android
    直接用英文字符串,看见 state 就知道啥状态,不用在脑子里维护一个 map ,也不用代码里整注释。
    Rache1
        13
    Rache1  
       4 天前
    @icemanpro #11 因为 MySQL 的枚举比我这个表情还滑稽
    akira
        14
    akira  
       4 天前
    增加一个 7 备货中,很奇怪的样子。 // 不要有代码洁癖。。保持文档更新即可。。
    b821025551b
        15
    b821025551b  
       4 天前
    @icemanpro 严格模式下无法插入新的条目,想新增需要 alter table ;弱类型语言(这里特指 PHP )以及或者菜鸡一个不注意搞混了 insert xxx values(1) 还是 values('1')就炸了;与其它数据库对接不兼容,说到这里这里还有个不建议的是 UNSIGNED 属性(当然只用 mysql 的话倒是个 feature ,比如用 int 型可以直接存 ipv4 )以及一大堆问题随便搜搜就能看见
    adoal
        16
    adoal  
       4 天前   ❤️ 3
    数值类型只有作为基数(表示数量多少)和序数(表示先后顺序)使用时才有大小的语义。作为枚举类型的值,没有大小语义。

    你可能以为,一个业务流程状态是序数,因为你很清楚流程是一路流转下来的。但实际上的流程,中间可能有分支、回转、跳跃。比如因为有特殊要求中途补付一些钱,比如物流弄丢了重新发货。这里每个节点使用的数字,只是为了把这个节点和其它的区别开,并没有任何大小的意义,所谓的 1 与 2 之间,只是莫某个节点与另一个节点之间,1 不是 1 ,2 也不是 2 。

    换个角度想,如果用文字类型来描述,难不成能你也要让业务流程中的每个状态的名字恰好是按字典顺序从小到大?为什么用数值类型你就要有这种追求呢?
    adoal
        17
    adoal  
       4 天前
    至于 eunm 会不会更快,当然是不会。类型系统的完备性,不是为了性能,而是为了有更严谨的数据一致性约束。也就是减少程序的 bug 。但有些人认为这是多余的负担。
    javapythongo
        18
    javapythongo  
       4 天前
    直接用字符串
    sujin190
        19
    sujin190  
       4 天前 via Android
    @go522000 他这个就是最佳最标准案啊,除了他说的,还有更重要的是,任何业务逻辑场景都分为住流程和细节,细节会随着业务流程变迁,但是主流成一般在一开始就可以确定,所以百位一般会进一步用来区分主流程节点,十位区分二级节点,就算一开始无法完全确定有几部主节点,但是大概分几部还是可以确定的,那么应该把 0 到 9 整体规划到几个大步骤去,而不是直接连续,这样就算主步骤一开始没有设计全也可以再加,其设计过程也是业务流程分析过程,既表达清楚又逻辑清晰,业务流程迁移方便也兼容性好,而且查询和逻辑规划也更容易
    sagaxu
        20
    sagaxu  
       4 天前   ❤️ 1
    代码中用 enum 类型,DB 中存 varchar 。

    文本描述比数值更直观,你不用老是翻代码或者找注释去想 5 是什么。状态区分度不高,并不适合用于索引,所以对查找性能损失也不大。每条记录增加几个字节的存储,也不会带来很大的存储开销。
    coolboys
        21
    coolboys  
       4 天前
    ENUM 或者其他
    franchise
        22
    franchise  
       4 天前
    学习学习
    weiwenhao
        23
    weiwenhao  
       3 天前   ❤️ 1
    字符串+1 , 存英文状态,以后导出到 duckdb ,Excel 之类的做个分析都很方便。
    yaott2020
        24
    yaott2020  
       3 天前 via Android
    我们公司也是使用字符串做状态的
    zbowen66
        25
    zbowen66  
       3 天前
    @nzynzynzy #4 我也曾这么想过,但是没有这么干...
    esee
        26
    esee  
       3 天前
    我用 10 间隔,tinyint 无符号,不过你只要没有代码洁癖,不直接操作数据库,其实数字多少没啥关系啊.
    mark2025
        27
    mark2025  
       3 天前
    mysqler 总是各种鸡肋优化…… 包括不限于 tinyint ,tinytext ,int 保存时间(戳),where 条件顺序
    mgzu
        28
    mgzu  
       3 天前
    投英文状态一票
    至少我遇到过新需求要增加新的状态。。。
    smlcgx
        29
    smlcgx  
       3 天前 via iPhone
    来学习一个,感觉 tinyint 和 varchar 都可以吧,另外从业务上来说,加一个备货中也可以,以备将来真有大件商品要专门进口或者定制的,所以放在后面挺合理的
    Rickkkkkkk
        30
    Rickkkkkkk  
       3 天前
    用 10 - 20 这种

    哪天中间多一个状态也灵活
    lscho
        31
    lscho  
       3 天前 via iPhone
    用 int 来代表状态就是上古时代留下的不符合现在时代的经验了,除了节省点存储空间其他的全是坏处。

    用字符串我觉得最合适
    zpf124
        32
    zpf124  
       3 天前
    我还是习惯用数值类型的,不过 varchar 也可以接接受,但数值类型我不会强制数值的大小与含义有关系,单纯是思考时候想到的顺序,同时用 char 或者 vchar 我也不接受写 "0001"、"0002"这种玩意,你这么写还不如用数值类型。


    另外,不要给数值类型设置长度,因为 mysql 对数值类型设置长度没什么意义,底层存储该是多长还是多长只跟着数值类型 bit 、int 、long 的定义走不会看你设置的长度,只有显示的时候会给你截取一下。

    我只有 tinyint(1) 的时候会设置长度,这是因为我们用的 orm 生成 bean 的时候默认可以将这个特殊类型识别为 boolean 的,8 之后我用的工具这里会 warning 让我用改 bool 类型,目前还没改,因为我还需要和别人统一,包括 json 类型,虽然数据库支持了但我们开发手册没改,所以我实际还是用的 text 。
    cumt21g
        33
    cumt21g  
       3 天前
    用文本类型更好,免得注释,一看就知道什么意思
    GooMS
        34
    GooMS  
       3 天前
    tiny ,不在乎数字大小,代码里转枚举
    shuang
        35
    shuang  
       2 天前
    数值类型,省空间,性能也更好
    vZexc0m
        36
    vZexc0m  
       2 天前
    数据库存字符串,代码里面使用枚举
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3239 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 82ms · UTC 10:39 · PVG 18:39 · LAX 02:39 · JFK 05:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.