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
aliehuhu
V2EX  ›  MySQL

用户购买商品表应该怎么设计?

  •  
  •   aliehuhu · 2017-10-01 10:09:52 +08:00 · 7409 次点击
    这是一个创建于 2618 天前的主题,其中的信息可能已经有所发展或是发生改变。
    需求:判断用户是否购买过该商品。
    表 1 是一个用户买一个商品就加一条记录。

    表 2 是一个用户购买的商品都放在一条记录里,用,号隔开,查询的时候读取出这个字段分割成数组再判断。

    表 1 的话,如果有一万个用户,一百件商品,最多就会产生 100 万记录了,感觉好多。
    该用哪种方法呢?或者有更好的实现方式?
    32 条回复    2017-10-02 17:30:22 +08:00
    silencefent
        1
    silencefent  
       2017-10-01 10:14:57 +08:00   ❤️ 1
    第一种表可以根据时间将记录作废
    或者归纳到分表,2015 2016 2017 订单
    第二种表简直是灾难
    zjsxwc
        2
    zjsxwc  
       2017-10-01 10:26:54 +08:00 via Android
    查询下用户订单表不就可以判断用户是否购买过商品了吗?

    select * from order where user_id=123 and item_id=456 limit 1

    同时给个 user_id 与 item_id 组合 index 就好了
    Vogan
        3
    Vogan  
       2017-10-01 10:27:34 +08:00 via iPhone
    第二种是反模式,不推荐。数据如果脏了,那么爆炸。
    bxb100
        4
    bxb100  
       2017-10-01 10:38:30 +08:00
    还有第二种这样的操作啊
    aliehuhu
        5
    aliehuhu  
    OP
       2017-10-01 10:41:38 +08:00
    @bxb100 初学,见笑了
    gouchaoer
        6
    gouchaoer  
       2017-10-01 11:01:25 +08:00 via Android
    用 json 字段,如果是 5.7 的话
    rootx
        7
    rootx  
       2017-10-01 11:06:42 +08:00 via iPhone
    100 万…很少…
    codingadog
        8
    codingadog  
       2017-10-01 11:47:19 +08:00 via iPhone
    请看数据库设计一二三范式
    codingadog
        9
    codingadog  
       2017-10-01 11:47:54 +08:00 via iPhone
    顺便 100w 数据完全不多啊
    loveCoding
        10
    loveCoding  
       2017-10-01 12:15:59 +08:00
    100 万....很少的 , 目前公司一个库单表 800 万没啥问题 . 主要是索引设计好
    evlos
        11
    evlos  
       2017-10-01 12:22:37 +08:00 via iPhone
    第二种设计太可怕了
    loveyu
        12
    loveyu  
       2017-10-01 14:16:36 +08:00 via Android
    正被要求第二种设计的路过,都是累
    rainex
        13
    rainex  
       2017-10-01 15:55:49 +08:00   ❤️ 1
    看了下,楼上还没人说到点子上,我说两句。

    第一种方法是初学者就会用的方式,后续数据库维护也简单。

    第二种其实思路是对的,因为接下来你还要根据需要作为查询条件去取那些商品数据的,你需要快速一步到位的得到 id 逗号分隔这种数据,但因为逗号分隔的数据内容可能很大,有可能空也可能买的太多导致 varchar(3000)都不够用,就不能用定长字段,所以数据量大了查询会慢,而且后续维护起来麻烦。

    所以,如果不想找太多麻烦就用第一种,如果想优化设计,可以用第二种的思路,只拿第一种做原始数据,但查询的 id 逗号分隔数据用 nosql 或文件目录结构来存放“缓存”,需要更新维护时先修改原始数据,然后更新“缓存”,也称不上楼上有人说的灾难,想运行快就要付出代价。

    有个设计原则,就是别什么烂活都交给关系型数据库,这种数据库是种代价高昂的数据存储方案,相对而言速度也不是很快。

    另外每一部分用什么方案,跟服务器的假设和配置方案也有关系,比如 cpu 和内存还有磁盘的方案等等,不过现在因为硬件越来越强,人工成本反而高,所以。。。现在搞技术的其实越来越幸福越来越容易了
    rainex
        14
    rainex  
       2017-10-01 16:05:38 +08:00
    补充下,要根据业务情况做好模拟测试,别拿着书上的东西生搬硬套,比如说一些数据还被别的业务所使用(查询、修改),这就可能会影响到查询、更新两者的负载比例关系(因为 mysql 查询虽快但更新很慢而且并发多了容易锁死),影响到哪种缓存方案合算,我说这些就是说没有绝对的办法,各因素要通盘考虑,但大原则都是要稳妥的设计原始数据存放方案,尽量确保业务需求的修改变动只需要修改缓存方案即可解决。
    wemore
        15
    wemore  
       2017-10-01 16:45:06 +08:00 via Android
    json 字符串存商品 id list,但是商品没了就不能删除只能标记下架。
    zjqzxc
        16
    zjqzxc  
       2017-10-01 17:25:15 +08:00
    表 1 是 sql 的思路
    表 2 是 nosql 的思路( json 存储,不建议逗号)

    表 1 可以查某个用户购买过什么,也可以查某个商品被哪些用户买过
    表 2 的思路可以作为在 redis 中的存储格式

    另外,楼上说商品没了就不能删除只能下架。。我想说,sku 一旦进入数据库,还能有删除这一说?
    学校的数据库课程中,有很多说法真的不适合互联网环境下的应用,包括但不限于各种断言触发器以及很多完整性约束。。。
    konakona
        17
    konakona  
       2017-10-01 18:15:47 +08:00
    多用第一种方式。
    第二种方式是灾难 - -
    gamexg
        18
    gamexg  
       2017-10-01 19:45:42 +08:00 via Android
    尽量第一种,另外第二种可以放 kv 缓存数据库,不需要放到 mysql。
    leeg810312
        19
    leeg810312  
       2017-10-01 19:45:52 +08:00 via Android
    第二种叫灾难?哪有这么严重!订单可以用 NoSQL 或 PGSQL/MySQL 的 json 来存,比直接逗号存储要好,查询一样很方便。
    leekafai
        20
    leekafai  
       2017-10-01 20:07:08 +08:00 via Android
    op 现在做的就到点子上了。
    和上面说的一样,数据结构不需要二选一,你需要方便统计的,第一种,你需要快取的,第二种。
    edison111cry
        21
    edison111cry  
       2017-10-01 23:35:39 +08:00
    @konakona

    请教大神们,为啥都説第二种是灾难呢?上面又説不要用逗号,改成 JSON 格式存储,这样吗:
    {"id":"4","id":"6"}
    那岂不是比用逗号占的空间更多,也没有看出这样比用逗号分割好在哪里?
    liprais
        22
    liprais  
       2017-10-01 23:47:47 +08:00 via iPhone
    第二种就是典型的自己吃香喝辣喂别人吃屎
    chinvo
        23
    chinvo  
       2017-10-01 23:51:53 +08:00
    @edison111cry 很多数据库的存储引擎可以处理 json,但是你用逗号法,随着记录的复杂化和数量增加,你的逻辑部分处理速度会越来越慢,而且管理起来也很麻烦。
    konakona
        24
    konakona  
       2017-10-02 02:45:05 +08:00
    @edison111cry 因为不好查询数据啊……我给你举 2 个例子,顺序来说:
    1. 你现在已知的需求也许就是一个商品属于多个分类。—— 你用自己认为合适的方法实现了。
    2. 卧槽,老板突然发春了!!!!!!!!!!!!!!!!!!!!要改成多商品对多需求,同时要做类似( http://desktops.pconline.com.cn/)太平洋那种多聚合搜索!怎么办!原来的方式效率太低,只能重写,还要考虑之前的数据如何转换成新数据,并且避免沉郁代码等等。

    你就知道了-v-
    konakona
        25
    konakona  
       2017-10-02 02:49:18 +08:00
    @edison111cry 我补充一下。
    我看到你提到了“空间”。
    我得提醒你,注意下目前的格局。
    刚开始写程序的几年是在第一种水平上思考。
    再写几年就会到达第二种水平。

    等你接触到分布式部署或者是分表的时候,你就知道,空间不是问题。

    我回头看了一下,你提到可能会产生 100w 条数据。既然如此,一定要换一个方式看待这个问题。你可以分表呀~~~~~~~~~~~~

    千万不要为了节省所谓的“空间”,去使用逗号存储的方式。你省了这点空间,却增加了性能负担( CPU、io、mem ),得不偿失。

    我们用电脑也知道,比方说你有 500G 的内容,你可以压缩它(你第二种方法就好似压缩),然后压缩到只占用 200G 空间。看起来美好,你用的时候怎么办?而且一直从压缩里拿东西(整表查询和模糊搜索)对硬盘对损耗很大,本来可以用 3 年对硬盘,功耗导致只能用 1 年就坏了。而多买一块硬盘就好比不压缩,分表。
    konakona
        26
    konakona  
       2017-10-02 02:53:56 +08:00
    再说一下。
    你如果用第二种方法,如果将来客服那边说“我们加错了 10 个商品到 A、B、C 这 3 个分类下,你能帮忙改正到 D 分类下吗”。你写 sql 都要几分钟。如果是用第一种方法存储的,你只需要不到 1 分钟。
    本来很简单的事情,反而被处理的复杂了。

    我刚开始写代码的时候也遇到过你现在的这个问题,我也曾经做过用第二种方法的。只能说甩手项目,就是做完了,不再管的那种。因为接盘侠肯定会恨死我。为啥?因为本来很块就能处理的问题,变得复杂、难追寻、难处理。

    因为我们写代码,要注意低耦合。
    ericls
        27
    ericls  
       2017-10-02 02:58:43 +08:00 via iPhone
    第一种 查询起来肯定是毫秒级
    des
        28
    des  
       2017-10-02 06:27:58 +08:00 via Android
    @edison111cry 不是存 json,而是有种字段类型叫 json,另外说一下,用 jsonb 会比 json 好。
    ChasYuan
        29
    ChasYuan  
       2017-10-02 07:43:53 +08:00 via Android
    数据局范式
    chenxytw
        31
    chenxytw  
       2017-10-02 12:23:42 +08:00
    居然会有人认为第二种好,太可怕了。
    如果是想要快速根据用户 id 来取数据,应该加索引。
    或者在上一层加缓存。
    但第二种无论怎么样都不该出现在关系型数据库的设计里面。
    stcasshern
        32
    stcasshern  
       2017-10-02 17:30:22 +08:00 via iPad
    非关系型的觉得第二种未尝不可,但是建议再分列
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   992 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 22:53 · PVG 06:53 · LAX 14:53 · JFK 17:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.