概述

前段时间在跟其他公司DBA交流时谈到了mysql跟PG之间在多表关联查询上的一些区别,相比之下mysql只有一种表连接类型:嵌套循环连接(nested-loop),不支持排序-合并连接(sort-merge join)与散列连接(hash join),而PG是都支持的,而且mysql是往简单化方向去设计的,如果多个表关联查询(超过3张表)效率上是比不上PG的。

下面也对mysql多表关联这个特性简单探讨下~

MySQL多表关联查询效率高点还是多次单表查询效率高?

A,B两个表数据规模十几万,数据规模都不大,单机MySQL够用了,在单机的基础上要关联两表的数据,先说一个极端情况,A,B两个表都没有索引,并且关联是笛卡尔积,那关联结果会爆炸式增长,可能到亿级别,这个时候网络IO成了瓶颈,这个时候两次十万行结果集的拉去可能远小于1次亿级别的结果集的拉取,那么将关联合并拉到service层做更快。

但实际业务中一般不会有这么蠢的行为,一般关联会有连接条件,并且连接条件上会有索引,一般是有一个结果集比较小,拿到这个结果集去另一张表去关联出其它信息,如果放到service层去做,最快的方式是,先查A表,得到一个小的结果集,一次rpc,再根据结果集,拼凑出B表的查询条件,去B表查到一个结果集,再一次rpc,再把结果集拉回service层,再一次rpc,然后service层做合并,3次rpc,如果用数据库的join,关联结果拉回来,一次rpc,帮你省了两次rpc,当然数据库上做关联更快,对应到数据库就是一次blk nested loop join,这是业务常用情况。

但是确实大多数业务都会考虑把这种合并操作放到service层,一般是有以下几方面考虑:

  • 第一:单机数据库计算资源很贵,数据库同时要服务写和读,都需要消耗CPU,为了能让数据库的吞吐变得更高,而业务又不在乎那几百微妙到毫秒级的延时差距,业务会把更多计算放到service层做,毕竟计算资源很好水平扩展,数据库很难啊,所以大多数业务会把纯计算操作放到service层做,而将数据库当成一种带事务能力的kv系统来使用,这是一种重业务,轻DB的架构思路
  • 第二:很多复杂的业务可能会由于发展的历史原因,一般不会只用一种数据库,一般会在多个数据库上加一层中间件,多个数据库之间就没办法join了,自然业务会抽象出一个service层,降低对数据库的耦合。
  • 第三:对于一些大型公司由于数据规模庞大,不得不对数据库进行分库分表,对于分库分表的应用,使用join也受到了很多限制,除非业务能够很好的根据sharding key明确要join的两个表在同一个物理库中。而中间件一般对跨库join都支持不好。

举一个很常见的业务例子,在分库分表中,要同步更新两个表,这两个表位于不同的物理库中,为了保证数据一致性,一种做法是通过分布式事务中间件将两个更新操作放到一个事务中,但这样的操作一般要加全局锁,性能很捉急,而有些业务能够容忍短暂的数据不一致,怎么做?让它们分别更新呗,但是会存在数据写失败的问题,那就起个定时任务,扫描下A表有没有失败的行,然后看看B表是不是也没写成功,然后对这两条关联记录做订正,这个时候同样没法用join去实现,只能将数据拉到service层应用自己来合并了。。。

到这里答案就很清楚了~

对关联查询进行分解

很多高性能的应用都会对关联查询进行分解。

简单地,可以对每个表进行一次单表查询,然后将结果在应用程序中进行关联。例如,下面这个查询:

  1. select * from tag
  2. join tag_post on tag_post.tag_id=tag.id
  3. join post on tag_post.post_id=post.id
  4. where tag.tag=’mysql’;

可以分解成下面这些查询来代替:

  1. Select * from tag where tag=’mysql’;
  2. Select * ;
  3. Select * ,,,,);

为什么会这样做呢?原本一条查询,这里却变成了多条查询,返回结果又是一模一样。

事实上,用分解关联查询的方式重构查询具有如下优势:

  1. 让缓存的效率更高。
  2. 许多应用程序可以方便地缓存单表查询对应的结果对象。另外对于MySQL的查询缓存来说,如果关联中的某个表发生了变化,那么就无法使用查询缓存了,而拆分后,如果某个表很少改变,那么基于该表的查询就可以重复利用查询缓存结果了。
  3. 将查询分解后,执行单个查询可以减少锁的竞争。
  4. 在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能和可扩展。
  5. 查询本身效率也可能会有所提升
  6. 可以减少冗余记录的查询。
  7. 更进一步,这样做相当于在应用中实现了哈希关联,而不是使用MySQL的嵌套环关联,某些场景哈希关联的效率更高很多。

面试官:为什么mysql不建议执行超过3表以上的多表关联查询?的更多相关文章

  1. 【原创】面试官:讲讲mysql表设计要注意啥

    引言 近期由于复习了一下mysql的内容,有些心得.随手讲其中一部分知识,都是一些烟哥自己平时工作的总结以及经验.大家看完,其实能避开很多坑.而且很多问题,都是面试中实打实会问到的! 比如 OK,具体 ...

  2. <转载>面试官: 讲讲MySql表设计需要注意什么?

    作者:孤独烟 出处: http://rjzheng.cnblogs.com/ 综述 近期由于复习了一下MySQL的内容看到一篇比较好的文章,转载分享一下.大家看完,其实能避开很多坑.而且很多问题,都是 ...

  3. MyBatis-Plus不写任何resultMap和SQL执行一对一、一对多、多对多关联查询

    对于一对一,一对多的关联查询,Mybatis-Plus官方示例(mybatis-plus-sample-resultmap)在处理时,需要编写查询方法及配置resultMap,并且写SQL. 为了简化 ...

  4. 面试官:Mysql 中主库跑太快,从库追不上怎么整?

    写这篇文章是因为之前有一次删库操作,需要进行批量删除数据,当时没有控制好删除速度,导致产生了主从延迟,出现了一点小事故. 今天我们就来看看为什么会产生主从延迟以及主从延迟如何处理等相关问题. 坐好了, ...

  5. 面试官:MySQL的可重复读级别能解决幻读问题吗?

    引言 之前在深入了解数据库理论的时候,了解到事务的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了. 但是对于 ...

  6. 面试官:MySQL 有哪些锁??

    大家好,我是小林. 这次,来说说 MySQL 的锁,主要是 Q&A 的形式,看起来会比较轻松. 不多 BB 了,发车! 在 MySQL 里,根据加锁的范围,可以分为全局锁.表级锁和行锁三类. ...

  7. 面试官:MySQL的幻读是怎么被解决的?

    大家好,我是小林. 我之前写过一篇数据库事务的文章「 事务.事务隔离级别和MVCC」,这篇我说过什么是幻读. 在这里插入图片描述 然后前几天有位读者跟我说,我这个幻读例子不是已经被「可重复读」隔离级别 ...

  8. 面试官:SpringBoot jar 可执行原理,知道吗?

    文章篇幅较长,但是包含了SpringBoot 可执行jar包从头到尾的原理,请读者耐心观看.同时文章是基于 SpringBoot-2.1.3进行分析.涉及的知识点主要包括Maven的生命周期以及自定义 ...

  9. 面试官:讲讲mysql表设计要注意啥

    内容时参考一个博主的,内容写的很好,就忍不住拿过来了,如遇到,请见谅 参考连接:https://www.cnblogs.com/rjzheng/p/11174714.html

随机推荐

  1. onunload与onbeforeunload事件解析 标签: 浏览器 2017-04-10 09:46 45人阅读 评论(0)

    注:只测试了chrome和IE浏览器的表现情况 onunload事件 //JS Document window.onunload = onunload_message; function onunlo ...

  2. HDU 2795 Billboard (线段树+贪心)

    手动博客搬家:本文发表于20170822 21:30:17, 原地址https://blog.csdn.net/suncongbo/article/details/77488127 URL: http ...

  3. css sprites拼合

    一.什么是css sprites css sprites直译过来就是CSS精灵.通常被解释为“CSS图像拼合”或“CSS贴图定位”.就是把网页中一些背景图片整合拼合成一张图片中,再利用DIV CSS的 ...

  4. 转载 - 最短路&差分约束题集

    出处:http://blog.csdn.net/shahdza/article/details/7779273 最短路 [HDU] 1548    A strange lift基础最短路(或bfs)★ ...

  5. 【ACM】hdu_zs2_1005_Problem E _201308030747

    Problem E Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)Total Subm ...

  6. 程序错误通常有2种,一种是运行时错误,这种错误ide会抛出异常,我们可以根据异常寻找问题.

    1.程序错误通常有2种,一种是运行时错误,这种错误ide会抛出异常,我们可以根据异常寻找问题. 2.可以根据异常寻找问题. 3.可以根据异常寻找问题

  7. HDU 1466

    经典DP,这样的递推确实有点难. 把所有直线分成两组,可以知道 m条直线的交点方案数 =(m-r)条平行线与r条直线交叉的交点数  + r条直线本身的交点方案 亦就是  =(m-r)*r+r条之间本身 ...

  8. Ruby 读取文件

    Ruby 读取文件 一次全读出来 textAll = File.read("fileName.txt") puts textAll 一次读取一行 file = File.open( ...

  9. Python面向切面编程-语法层面和functools模块

    1,Python语法层面对面向切面编程的支持(方法名装饰后改变为log) __author__ = 'Administrator' import time def log(func): def wra ...

  10. cefsharp 获取高度

    G.browser.GetBrowser().MainFrame.ExecuteJavaScriptAsync("$(document).height()"); // Get Do ...