V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
longmeier90
V2EX  ›  Python

请教大佬一个问题,有一个需求更新 30 张表的一个字段,怎么去实现?

  •  
  •   longmeier90 · 2022-10-11 15:53:14 +08:00 · 3926 次点击
    这是一个创建于 807 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我们公司业务场景是 把两个患者合并成一个患者,但是就需要把库里的 30 张表(未来会更多表...都是加的冗余字段)的信息更新一下。
    那么线上系统发起一个需求,怎么能在不影响性能,而且还有保证信息的完整性的情况下去实现。
    
    1. 如果保证完整性就需要加事务,但是就会锁表造成系统卡顿,app 转圈(之前的一些其他业务事务出现类似的)影响线上业务。
    2. 不加事务,怎么能保证数据的一致性。
    
    3.向这种场景应该是常见的吧,大佬都是怎么设计的?
    
    
    43 条回复    2022-10-12 22:37:19 +08:00
    hahasong
        1
    hahasong  
       2022-10-11 16:01:23 +08:00
    把这个字段只留一张表,或者常用字段都抽出来一张表。然后改代码逻辑重新读。再删掉 30 张表里冗余的字段
    guoziq09
        2
    guoziq09  
       2022-10-11 16:06:07 +08:00
    我的想法是异步曲更新数据。callback 通知或者客户端轮训查询结果。期间在加上定时任务的补偿操作。
    ipwx
        3
    ipwx  
       2022-10-11 16:07:27 +08:00
    为啥更新一个患者的 30 张表需要锁全部患者表的数据啊?

    难道你们数据库不支持行锁?
    westoy
        4
    westoy  
       2022-10-11 16:10:19 +08:00   ❤️ 2
    这种不需要高并发的业务代码搞互联网这套字段冗余是真的没事找事
    joApioVVx4M4X6Rf
        5
    joApioVVx4M4X6Rf  
       2022-10-11 16:10:44 +08:00
    https://www.cosmicpython.com/book/preface.html

    这本书里介绍了一种基于事件的架构,读可以容易,写的时候应该是走消息队列的。读写分离应该架构改动不小了
    lmshl
        6
    lmshl  
       2022-10-11 16:11:57 +08:00
    不应该是行级锁么?
    xsm1890
        7
    xsm1890  
       2022-10-11 16:15:26 +08:00
    感觉是设计阶段没符合 2NF 导致的问题??
    longmeier90
        8
    longmeier90  
    OP
       2022-10-11 16:15:39 +08:00
    @ipwx 那些表有些都是记录表,有很多行数据。
    longmeier90
        9
    longmeier90  
    OP
       2022-10-11 16:15:47 +08:00
    @lmshl 那些表有些都是记录表,有很多行数据。
    longmeier90
        10
    longmeier90  
    OP
       2022-10-11 16:21:51 +08:00
    @xsm1890 加一些冗余字段是为了查询是方便。很多统计都会联表查询数据量大的时候就会慢
    lmshl
        11
    lmshl  
       2022-10-11 16:24:01 +08:00
    不管有多少行,都应该是行级锁啊
    Mithril
        12
    Mithril  
       2022-10-11 16:24:27 +08:00
    做医疗系统的话,利用好半夜人少这段时间。
    用个表记录对应关系,弄个定时器半夜的时候再改。
    跟客户说好,因为修改患者对应关系很复杂,尽量不要瞎搞。一旦真的搞错了,那所有修改第二天生效。
    只要能该需求那都不是问题。
    p23XnFNH1Wq953rV
        13
    p23XnFNH1Wq953rV  
       2022-10-11 16:27:20 +08:00
    异步执行, 定时检查
    如果端需要看到效果, 而异步还没执行完, 就要增加异步效率, 或者通过其他方式让端先看到"未来数据"
    longmeier90
        14
    longmeier90  
    OP
       2022-10-11 16:31:32 +08:00
    @lmshl 嗯嗯,行锁也会影响查询
    longmeier90
        15
    longmeier90  
    OP
       2022-10-11 16:34:27 +08:00
    @Mithril 但是未来可能会增加表,也会加这个字段。还得改这个修改程序
    lmshl
        16
    lmshl  
       2022-10-11 16:43:18 +08:00
    读已提交怎么影响查询?
    yh7gdiaYW
        17
    yh7gdiaYW  
       2022-10-11 16:56:33 +08:00
    发 30 条消息异步修改?
    yh7gdiaYW
        18
    yh7gdiaYW  
       2022-10-11 16:57:00 +08:00
    @xsm1890 这玩意儿过时了
    wuxiaoqing234
        19
    wuxiaoqing234  
       2022-10-11 17:05:20 +08:00
    @longmeier90 做两个异步任务。 一个在夜间根据主表的字段,去刷新其他表的数据。
    第二个,做保存修改操作的时候, 提交一个单个的修改任务,去刷新其他数据库
    longmeier90
        20
    longmeier90  
    OP
       2022-10-11 17:08:23 +08:00
    @lmshl 刚试过了,查询没问题,写入会提示锁冲突。
    lmshl
        21
    lmshl  
       2022-10-11 17:10:39 +08:00
    写入的时候保持相同的顺序去锁,SELECT FOR UPDATE
    liaohongxing
        22
    liaohongxing  
       2022-10-11 17:14:57 +08:00
    innodb 和事务已用多年。都是行级锁 。哪里需要锁表
    cubecube
        23
    cubecube  
       2022-10-11 17:15:46 +08:00
    @westoy 现在的开发模式,不得不冗余分割,因为人员有流动,项目也不一定能连续的持续下去
    timethinker
        24
    timethinker  
       2022-10-11 17:16:24 +08:00
    问题不在于有哪些解决办法,而在你能承受什么样的成本。
    你是想在屎山上继续堆屎还是来个大扫除为将来留下更多的操作空间?

    现状就是你有几十张表需要去更新,在不考虑重构的前提下,你能选择的方案并不多:
    1 、你想要在一个事务里面进行更新,这也是最简单的办法,但是你会担心说影响性能。
    2 、一张表一张表的更新你又会担心无法保证数据的完整性。

    如果是我的话,在没有重构的选择情况下,在没有了解业务领域的情况下,我会选 1 ,这也意味着我不会考虑系统的性能,也不会考虑到系统的可用性问题。

    如果你是系统的设计人员,如果你有权决定是否应该重构,那么就应该考虑到这些问题(可用性以及可靠性)如何影响业务系统的架构设计,这些问题你应该最了解,如果你还不了解,那么要先去了解,因为只有你先了解以后,你才能够根据规模来决定应该如何重构,重构哪些方面可以解决关键的问题,以及重构的成本是否可以承受。
    IvanLi127
        25
    IvanLi127  
       2022-10-11 17:19:28 +08:00
    我觉得大佬会选择重写整个系统,30 张表都冗余一次这个字段,那这个字段它是不是应该住缓存里?
    如果没有这个冗余字段,性能会很差么?冗余字段要么写扩散,要么放弃实时性,只保证最终一致性。
    pengtdyd
        26
    pengtdyd  
       2022-10-11 17:20:03 +08:00
    一个需求更新 30 张表。。。。。。。。技术 leader 到底什么水平啊。
    liaohongxing
        27
    liaohongxing  
       2022-10-11 17:22:52 +08:00
    现在还不用事务,不知道你们多表更新的代码是怎么写的哈。要是一个转账场景 ,一个扣款 ,一个入款 。要是意外中途断掉了,入款岂不是平白无故丢了一笔钱。想想就很可怕。
    longmeier90
        28
    longmeier90  
    OP
       2022-10-11 17:23:21 +08:00
    @pengtdyd 单独讨论技术方案,不扯其他
    leeg810312
        29
    leeg810312  
       2022-10-11 18:46:21 +08:00
    不加事务,不可能保证一致。如果行锁仍然会影响业务,那么有 2 个选项,一个是用 2 个数据库做读写分离,另一个是读请求都是读缓存,写改成异步,事务写完再更新缓存。
    someonedeng
        30
    someonedeng  
       2022-10-11 18:59:22 +08:00
    能不能惰性处理,比如涉及到了这个患者的查询 /更新 就处理下这个患者就行了
    xy90321
        31
    xy90321  
       2022-10-11 19:18:46 +08:00 via iPhone   ❤️ 2
    建一张用户更新的临时表,PK 是 操作 ID ➕ 要更新的表名

    每次要合并时候生成个唯一的操作 ID ,然后往临时表里用这个 ID 为每张要更新的表插一条记录,按照你目前的表设计是每次合并需要插 30 条

    剩下的就是更新程序确保按照一定的顺序一条条处理临时表里的数据就可以了,人肉事务保证最终结果一致性(但不保证过程一致性和实时性,也就是更新过程中会有 20 张更新了,10 张还没更新,一部分界面表示不一致)

    说白了,就是有序 MQ 的思路,但是看你们这系统的样子也不像有 MQ ,就自己来吧
    route
        32
    route  
       2022-10-11 19:42:28 +08:00
    1. 先将数据同步到某个中间件,如 kafka ,只做访问不能修改,原始数据记为 db1
    2. 在某个时间点确定同步完成后,新建一模一样的表,新来的存储信息都往这个表存储,记为 db2
    3. 新建一个数据库,以后使用这个数据库做生产,记为 db3
    4. 线下完成好 db1 合并数据再导入 db3
    5. 线下完成好 db2 合并数据再导入 db3
    Maxwe11
        33
    Maxwe11  
       2022-10-11 19:47:22 +08:00
    首先,一定不能这样无休止为了“方便”在无数个表上加字段;

    看样子系统也不太可能短期内重构;

    但这样无休止加下去早晚会出问题,所以为了稳定,短期内无法做大调整的时候,我们以往的经验是先做分层;

    把你现在手里的表都拿出来,先做一次分析,哪些是业务核心表,哪些是报表数据等等,把表类型先分层,然后建层,就像建数据分析集市,哪些是事实哪些是维度哪些是业务层哪些是汇聚层等等,保持业务系统不变,但是把逻辑通过数据处理层解决,这样就可以把 1 对无限多的问题转换成局部问题。
    buster
        34
    buster  
       2022-10-11 20:04:11 +08:00
    异步处理嘛,执行速度不能保证,业务上应该不允许
    同步嘛,又会有慢和锁的问题

    1. 最理想状态,应该放弃全部更新的这个念头
    2. 实际干活,我觉得应该跟业务方沟通是否有妥协可能性,比如放弃一定的响应时间,把执行都搬到异步那边去做,等异步完成之后才可以看到最新的状态,否则就是 updating ,这样就只是多了额外的合并功能的业务代码,不影响原有逻辑,异步程序,30 次的大事务拆成小事务,维护一个 log 表来记录。
    NewYear
        35
    NewYear  
       2022-10-12 09:30:30 +08:00
    更新关键表,后台跑一个线程去更新冗余表吧。
    zmal
        36
    zmal  
       2022-10-12 10:30:29 +08:00
    异步的方案上面的回复都给出了,大差不差就那些东西。
    异步的问题无非是数据更新有延迟或不同步。理论上业务肯定有优先级,不必做到 30 多张表全部实时。如果还是有疑虑或者业务方要求必须实时,可以在异步的方案上加一张 patch 表,配合异步方案对这些表的查询结果用一个拦截器做实时补偿。
    JohnBull
        37
    JohnBull  
       2022-10-12 13:55:19 +08:00
    医务系统应该不是 7x24,花一个月时间每天下班后用事务无脑跑批可以的吧
    wxf666
        38
    wxf666  
       2022-10-12 14:37:35 +08:00
    @longmeier90

    > 加一些冗余字段是为了查询是方便。很多统计都会联表查询数据量大的时候就会慢

    好奇问一下,一般会连多少张表?被连的表一般有多大?(比如,一般连 千万级患者表 等类似级别的 5 张表?)
    longmeier90
        39
    longmeier90  
    OP
       2022-10-12 15:38:59 +08:00
    @wxf666 不等,其他同事写的 SQL 都不好控制,再加上前期都是用外键关联查,有的 7 、8 个 left join ,随着业务数据增加有的大表 100 万数量级。
    wxf666
        40
    wxf666  
       2022-10-12 15:54:06 +08:00
    @longmeier90 就算是 8 个 100 万行的表,每行 1KB 的数据,全部缓存也大概需要不到 8 GB 内存而已呀

    是内存不够,导致联表慢吗?

    如果不依赖数据库的 left join ,而是自己获取主要数据后,再手动查询 8 次表(若已花 8 GB 代价全部缓存至内存中了),最后组装数据,也很慢吗?
    hopingtop
        41
    hopingtop  
       2022-10-12 17:07:05 +08:00
    OP 这个应该不是一个一次性需求吧,说了冗余字段还会有。
    其实在设计冗余字段的时候,就相当于大部分场景放弃了一致性。
    那么其实可以 梳理一下业务,同步+异步一起处理, 或许梳理下来就只有 1-2 表 要求数据一致性呢,这不就好办,都兼顾到了嘛,如果 5-5 开,那也能减少大部分时间。真要是都要保证数据一致性,那冗余字段这个设计本来就是你们当前系统的大 BUG !
    longmeier90
        42
    longmeier90  
    OP
       2022-10-12 22:25:29 +08:00
    @Maxwe11 大佬有没有关于数据分层思想的资料推荐一下,想看看
    Maxwe11
        43
    Maxwe11  
       2022-10-12 22:37:19 +08:00
    @longmeier90 这种都比较理论,你就搜搜传统数据集市设计的内容看看,但通用方法论实际用的时候,还是个经验和玄学的综合体,最后都是取舍平衡,那些通用方法论能实际套用的很少,只能说是借鉴思想。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5722 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 06:27 · PVG 14:27 · LAX 22:27 · JFK 01:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.