V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
LeeReamond
V2EX  ›  程序员

想在业务端维护 inner join 应该用什么算法?

  •  
  •   LeeReamond · 2023-03-14 15:32:54 +08:00 · 2540 次点击
    这是一个创建于 625 天前的主题,其中的信息可能已经有所发展或是发生改变。

    数据库做连表压力有点大了,想要转到业务上维护,想问下版本答案用啥算法,没啥这方面的经验

    场景是有 a 表数据和 b 表数据,两表用相同的主键索引,数据库方式的话应该是 a 做 b 的外键,但是现在没有这方面约束,a 和 b 的数据可能互相不一致,有的条目多一些有的条目少一些,想得到一个一致的结果,如果按直觉写多次遍历取交集这类的感觉复杂度有点高了。。。

    40 条回复    2023-03-16 09:21:57 +08:00
    aw2350
        1
    aw2350  
       2023-03-14 15:41:15 +08:00
    没明白表述
    ljrdxs
        2
    ljrdxs  
       2023-03-14 16:39:36 +08:00
    第一反应是 LINQ 的 join 。
    不过,作为用 Oracle 的人,不懂“数据库做连表压力有点大了,想要转到业务上维护”是怎么回事。你自己取两个表,放内存操作,性能胜过数据库 join ?
    LeeReamond
        3
    LeeReamond  
    OP
       2023-03-14 16:47:49 +08:00
    @ljrdxs 说性能好肯定没把握,但是毕竟数据端扩展起来远不如业务端省事,业务节点想开多少开多少不是,然后在此基础上 join 逻辑好好写一写,相当于把数据层的 join 逻辑拆成 kv 索引了,整体压力应该能小不少吧。
    shyangs
        4
    shyangs  
       2023-03-14 17:09:15 +08:00
    如果是 Python 寫的的業務層, 我是不信你能在性能和速度方面贏過 C / C++ 寫的 Oracle 、Microsoft SQL Server 、MySQL.
    shyangs
        5
    shyangs  
       2023-03-14 17:18:16 +08:00   ❤️ 1
    阿里巴巴用的是 Java 只比 C 慢一倍,可以堆 2 倍伺服器。換 Python 比 C 慢 10 倍,人家堆 2 台主機,你要堆 20 台,我想在經濟下行段,老闆應該不會這麼揮金如土。

    hhjswf
        6
    hhjswf  
       2023-03-14 17:30:44 +08:00
    @aw2350 #1 就是自己写代码做表连接
    pengtdyd
        7
    pengtdyd  
       2023-03-14 17:32:43 +08:00
    用冗余换时间(用空间换时间)
    ljrdxs
        8
    ljrdxs  
       2023-03-14 17:51:09 +08:00
    @LeeReamond
    “但是毕竟数据端扩展起来远不如业务端省事,业务节点想开多少开多少不是”
    没懂。指数据太多了,塞爆表了?业务节点指什么?
    MoYi123
        9
    MoYi123  
       2023-03-14 18:18:42 +08:00
    一般 A join B 可以拆成。select A, select B where id in (....); 然后用个哈希表去组合.
    看你的描述是数据库设计的不好, 为什么不直接把数据库改好呢?
    MindMindMax
        10
    MindMindMax  
       2023-03-14 18:31:41 +08:00
    @shyangs 人家也没说用 Python 啊,你这是 PY 黑子吗
    lolizeppelin
        11
    lolizeppelin  
       2023-03-14 18:41:52 +08:00
    换数据库,mysql join 不行
    结束
    shyangs
        12
    shyangs  
       2023-03-14 20:28:12 +08:00
    @MindMindMax

    他前幾天在 Python 版塊發帖問了兩個問題。
    roundgis
        13
    roundgis  
       2023-03-14 20:31:19 +08:00 via Android
    有多大的資料 以至於 inner join 出了問題

    十億那種?
    LeeReamond
        14
    LeeReamond  
    OP
       2023-03-14 20:41:18 +08:00   ❤️ 1
    @shyangs 性能比较可以参考 Programming-Language-Benchmarks-Visualization 比你这个更清楚一些,另外为什么曾经在 py 区发过贴,连算法问题里都要有人来踩两句 py 的性能问题我也是不懂了,什么逻辑?你来发点有营养的也就算了还发的都是这种。。谁不知道 python 性能低,我们这个业务不是 python 做的
    LeeReamond
        15
    LeeReamond  
    OP
       2023-03-14 20:43:51 +08:00
    @roundgis 总数据量不到 10 亿,单表现在大概五百万左右,我对 join 性能没有不满但是我们需要能负载高 qps ,把数据库从 join 转化为 kv 会好很多。
    shyangs
        16
    shyangs  
       2023-03-14 21:03:13 +08:00
    @LeeReamond

    可行性評估,難道沒營養。你先說你用什麼語言,資料不足得不到有用的回答,訓練過 ChatGPT 都知道。
    iseki
        17
    iseki  
       2023-03-14 21:11:41 +08:00
    只能说你肯定不是单纯将数据库 join 变成自己的实现,否则比数据库的实现还慢几乎是板上钉钉的(如若不然那就说明数据库该换了,斜眼 MySQL
    iseki
        18
    iseki  
       2023-03-14 21:12:48 +08:00
    如果你只是想挑战下自己,那就去参考数据库的实现吧,它用什么你就用什么
    iseki
        19
    iseki  
       2023-03-14 21:15:13 +08:00
    @MoYi123 这样的做法,除非存在比如缓存(节省掉第二个查询)之类的优化,否则自己实作不太可能比数据库快,甚至说挖坑写出 bug 是大概率的
    gtx990
        20
    gtx990  
       2023-03-14 21:16:58 +08:00 via Android
    大部分的 oltp 业务就是一行 join 一行,或者一行 join 几行,走索引,你在业务做或者用 sql 做差不太多,大概率达不到你想要的效果。

    除非你的需求很特殊,是几十行 join 几十行。可以考虑用自动扩容的 KV NoSQL ,DynamoDB Cassandra 这种,业务层 join 。

    如果是全量 join 就上 olap 数据库没啥说的
    ljrdxs
        21
    ljrdxs  
       2023-03-14 21:17:34 +08:00
    @shyangs 主要不是 programming language 的问题(看你用繁体字加台湾术语,我不熟悉台湾术语,所以全用 term )楼主应聘 Oracle 或 Microsoft ,应该没能力去 database team 开发 join 相关 implementation 。所以,他说 database join performance 差,要自己 implement ,感觉很奇怪啊。同样的 language ,同样的 version ,他的 materialization 能达到 Oracle 或 Microsoft 的水平?我看到不少人说 MySQL join 差,但是楼主应该没能力当 MySQL 的 contributor 。MySQL 团队,比楼主强多了吧?
    所以,尽管楼主没回答我的细节提问。换我经历 performance issue ,第一件事,找 DBA 商量。
    ljrdxs
        22
    ljrdxs  
       2023-03-14 21:22:33 +08:00
    @iseki 假如 MySQL 烂,也是比 Oracle 、SQL Server 烂。
    和全世界绝大多数开发比,MySQL 团队肯定更强。
    在这个论坛,自己实现同一个算法,性能超过 MySQL 的,能有几个?
    所以,不理解楼主的情况。
    iseki
        23
    iseki  
       2023-03-14 21:23:46 +08:00
    @ljrdxs 我也只是斜眼一下~~
    roundgis
        24
    roundgis  
       2023-03-14 23:00:01 +08:00 via Android
    @LeeReamond 有一種辦法是把這兩張表的字段合併為一張表 這樣就不需要 join 了

    很多公司拿 db 當 nosql db 用就是差不多的路數

    你可以找找相關的案例分享

    現代數據庫的引擎優化得不錯 拿來當 kv store 用也沒有問題
    roundgis
        25
    roundgis  
       2023-03-14 23:02:13 +08:00 via Android
    @ljrdxs mysql 8 join 性能大有改善 不過很多公司未必會升級
    jones2000
        26
    jones2000  
       2023-03-14 23:06:05 +08:00
    加硬件, 内存,cpu 往上堆,就行了。今天下单, 明天升级机器, 速度立马就上来了。
    LeeReamond
        27
    LeeReamond  
    OP
       2023-03-14 23:57:16 +08:00
    @gtx990 有千行级别的 join 需求,单行 join 我还问什么。。
    nothingistrue
        28
    nothingistrue  
       2023-03-15 09:53:15 +08:00
    系统架构图先理一下。程序和数据库,即计算和存储合起来,才构成一个业务。你这和数据库分离的业务端是个什么鬼。如果你的业务端,指的就是可横向扩展多节点,并脱离数据库的程序,那就只是个单纯的计算节点,那就别说 inner join 了,它连任何跟数据存储有关的业务都做不了。

    我们通常所说的能让程序干的活就不让数据库干,那基本针对的是单个实体(表上的一行记录),而不是针对整个存储(表)。可以针对一两个甚至上万个记录,让程序分批查询出来之后再内部做 join ,这本质上是计算而非存储。但要针对动辄百万记录的整个存储,让程序做 join ,那是不行的。后者要交给专门的存储处理去做,如果关系数据库不行,KV 数据库、内存数据库、Nosql 数据库,或者更好更贵的关系数据库能顶上去,普通程序肯定顶不上去。
    realpg
        29
    realpg  
       2023-03-15 11:17:32 +08:00
    @ljrdxs #22

    可是数据库跑逻辑负载高,会降级整个系统的性能
    如果单纯的把最小化数据取出来,分布式的计算节点去计算,就会降低数据库的 cpu 负载,只吃 io

    这种优化是高并发互联网项目常做的,而商业软件就可以无脑都写存储过程里让数据库去飙 cpu
    ljrdxs
        30
    ljrdxs  
       2023-03-15 13:16:21 +08:00
    @realpg 你是这个意思吧?
    单个电脑,数据库性能>后端性能
    但后端用了分布式,相当于 N 台电脑,所以 N 台电脑计算能力>数据库性能优势
    这倒说得通。
    realpg
        31
    realpg  
       2023-03-15 13:49:48 +08:00   ❤️ 1
    @ljrdxs #30
    不是这个意思,感觉你可能没怎么做过中型互联网项目
    以 MYSQL 为例,其实维持主备也好,cluster 也好,维持他们的一致性其实开销是很大的,所以互联网项目这边,数据都都是优化成最简单可用查询,充分利用索引,转化为简单完全索引查询和简单 left join ,数据库的 cpu 能完全空闲是最好不过的了,只要 io 能跑就没啥性能瓶颈

    而计算节点天生就是一堆的弹性扩容的,如果一个复杂的内联查询算法能够通过其他方法让数据库服务器返回给程序的记录数据容量( KB-MB 级)不会太离谱的大,分散到计算节点处理就完事了,对系统没有任何影响

    RDB 这边,三机主备+1-8 只读节点就是最常见的中型以上( api server 10kQPS+)项目的最常见配置了

    如果你把太多复杂的查询都压到了数据库上,让数据库 cpu 满载,查询造成积压,整个系统都不好了

    压力压到数据库 cpu 上的复杂查询,大部分是乱 join 、group by having ,甚至直接内联 case when 之类,这些其实都不是好简单无代码直接优化到 kv 类的 nosql 上的,都需要算法协助才能充分利用 redis 之类的内存缓存

    中型高 QPS 系统上,当数据库较弱时(比如 MySQL 弱鸡的索引和锁体系),基本 DBA 都会要求全简单查询化,全索引匹配化,甚至条件全 int 化把 varchar 都优化掉



    与之相对的,就是写底负载商业软件的,前天帮人调试国产化数据库兼容,打开医院 HIS 系统,有个 TXT 资源文件,里面全是单行 SQL 代码都 1KB-2KB 的怪物查询。。。
    nothingistrue
        32
    nothingistrue  
       2023-03-15 14:02:22 +08:00
    @ljrdxs #30
    @realpg #31
    ljrdxs
        33
    ljrdxs  
       2023-03-15 14:03:18 +08:00
    @realpg 做过大型,但不是后端。
    转后端了,确实不做互联网。
    大部分没看懂。不过用 Oracle ,刚好和你反过来,join 、group by having 、case when 才是性能最优。一个 SQL 解决问题,最好; select 越多,性能越差。我们有 profiling ,所以我敢说这些是对的。
    不一定只和数据库类型有关,估计和你说的“都需要算法协助才能充分利用 redis 之类的内存缓存”有关。
    realpg
        34
    realpg  
       2023-03-15 14:08:20 +08:00   ❤️ 2
    @ljrdxs #33
    你有试过 oracle 按你那种写法,把基本操作压 10kQPS 上去测过么
    10kQPS 的业务 api 接口,算是互联网这边中型系统的门槛了
    nothingistrue
        35
    nothingistrue  
       2023-03-15 14:15:28 +08:00   ❤️ 1
    @ljrdxs #30
    @realpg #31
    这个是把少部分数据,首先镜像到程序的数据结构(内存)上,然后在程序中再做后期处理。这样做的前提是,每次业务操作,只需加载少量的数据。当你在业务上(重点是业务,不是后台技术)周密的拆分数据结构之后(微服务、DDD 都是干这事的),CRUD 业务上除了查询外都能符合那个前提,查询则有点无解,要靠读写分离、独立查询器等方式来支持后才能搞。
    raysonlu
        36
    raysonlu  
       2023-03-15 15:26:50 +08:00
    看标题给我的疑惑是:算法?打算直接改数据库底层的相关源码进行维护?
    Richard14
        37
    Richard14  
       2023-03-15 16:13:38 +08:00
    @nothingistrue 你说的缓算完全不是重点,重点在于原生 mysql 集群横向扩展困难,当压力上来了之后横向扩展导致的冷热备一致性 /热点 /IO 放大问题全都是老大难,而业务本身多变,有的业务读多,有的业务写多,有的热点集中,有的全局随机读写,各种歪瓜裂枣,极端情况也是屡见不鲜,你避不开这些问题。所以如果条件允许大家都要上虚拟储存层,关系型数据库本身就是为了维护复杂关系做的设计和优化,而按照我的经验来说业务往往对这些复杂关系的维护是非必须的,这样抛开关系型维护转化成单纯的索引后软硬件利用率都有质的提升,如果说一致性仍然是老大难,起码热点和 IO 放大问题会得到很好的缓解,并且抛开关系型数据库的抽象后可以更接近底层,对于充分利用硬盘本身性能的亲和也更好。楼主的方案是非常合理、且正常的。


    @realpg 看得出来楼主很无语,全楼只有老哥一个正常参与讨论的,你回帖说的都是很常识性的东西,楼上有位这些常识都听不懂然后还回了好几条的,也不知道之前都在说些什么。这楼里都是一些什么妖魔鬼怪,v2 氛围什么时候变成这样了,首页都是在那无限外行的讨论 AI 取代人类的群魔乱舞,点开算法贴里没有一个人讨论算法,全在互相踩
    realpg
        38
    realpg  
       2023-03-15 16:42:22 +08:00
    @Richard14 #37

    其实也不单纯的是 mysql 横向扩展困难 mysql 这么弱鸡的数据库去抗企业行业应用那种低 qps 负载,只要少用锁别干死锁了,都能扛得住,搞行业软件的跟搞对海量普通用户业务(我只是习惯叫互联网替代这种业务)的互相理解很难。

    我们定义的大系统 crud api server 是 35kQPS(包含缓存操作),他们定义的大系统是 80 人开发 700 多个模块编译后二进制文件都 900MB 然后 15qps ,对数据库性能的理解我们是优化到单查询 0.0035 秒他们是 1 秒能出结果就行。


    十五年前吧,我也搞过 oracle ,写企业商业软件简单到离谱,写医院的业务系统,20qps 都是高并发的超大大医院了
    oracle 这玩意只要搭起来集群,给足了海量内存,四路服务器或者当年小型机堆上去,也不用怎么设计索引,看着差不多觉得可能用得到就上一个,剩下的 oracle 自己就能给你优化好,这就是搞商业软件行业软件的逻辑,跟面对庞大公众用户的基本思维就不同


    比如,最近朋友公司在搞信创国产化,要绕过供应商把一个三甲特大型医院的一个大业务系统数据库从 oracle 替换成人大金仓,我听着直摇头,金仓就是魔改的 pg11 ,这怎么能行,一个特大型三甲那门诊量和住院医嘱量,oracle 的牛逼查询自适应优化能力,换弱鸡山寨 pg 怎么行,结果一换试了下,还真行。在中间件下了个性能检测记录 SQL 防止语法不兼容,结果 24 小时系统峰值读查询 qps45 ,医院上班工作时间平均读查询 qps15

    ---

    关于讨论,V2 早就这样了,所以这些年我都不爱吱声了,顶天在 tg 群里遇到感兴趣的能说两句。

    之前说的都是大家好理解的形象的常识,不说人话的不搭理就是了,更深入的不搞这个根本接触不到的你发了也没人看
    要不就是真搞这个的还有问问问从来不自己研究,就差让你手把手教了

    五六年前的 V2 讨论技术问题,还是可以只提供思路,现在,要么是一群啥也不懂的瞎参和,要不就是希望你手把手给他搭好才能证明你说得对的。。。
    ruanimal
        39
    ruanimal  
       2023-03-15 18:17:43 +08:00
    @shyangs Python PTSD ? 主贴根本没提到 Python 吧
    nothingistrue
        40
    nothingistrue  
       2023-03-16 09:21:57 +08:00
    @Richard14 #37 你这不就是通用规则的数据库顶不住,就自己定制一个专用数据库吗。处理还都只是存储节点 /数据层,没到计算节点 /业务程序上。楼主说得业务端,虽然没给出架构图,但看描述八九不离十是个计算节点,不是一回事。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1745 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 00:00 · PVG 08:00 · LAX 16:00 · JFK 19:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.