{eval=Array;=+count(Array);}

问答专栏Q & A COLUMN

sql一次查询需要关联十几张表,有什么优化方案么?

MarvinZhangMarvinZhang 回答0 收藏1
问题描述:sql优化已经到极限了,还是很慢
收藏问题

10条回答

ghnor

ghnor

回答于2022-06-28 13:46

不知道开发的同学有没有遇到过类似这样的需求:

  • 相同类型的数据在多个系统中,如果要得到全部的信息,就要连续调多个系统的接口;

  • 业务复杂,一个需求需要关联几张表甚至几十张表才能得到想要的结果;

  • 系统做了分库分表,但是需要统计所有的数据。

那么此类需求要如何满足呢?我们选择了“通过 ETL 提前进行数据整合”的方案。

什么是 ETL

说到ETL,很多开发伙伴可能会有些陌生,更多的时候 ETL 是用在大数据、数据分析的相关岗位;我也是在近几年的工作过程中才接触到ETL的,现在的项目比较依赖 ETL,可以说是项目中重要的一部分。


ETL 是三个单词的缩写:

  • Extraction:抽取、提取;就是把数据从数据库里面取出来;

  • Transformation:转换;包括但不限于:数据筛选校验、数据关联、数据内容及结构的修改、运算、统计等等;

  • Loading:加载;将处理后的数据保存到目标数据库。

从这三个单词基本可以了解 ETL 的作用:将各个业务系统的数据,通过抽取、清洗、转换之后,将加工后的数据落地到数据库中(数据仓库);在这个过程中,ETL 可以将分散、零乱、标准不统一的数据整合到一起。



使用场景

我接触过的项目,使用ETL工具的场景有这个几种:

1. 报表、BI系统:

在公司建设的初期,业务比较少,系统也比较少,一台数据库就搞定了;随着公司业务的增加,业务系统被拆成很多系统;随着数据量的继续增加,单个系统的数据增加到一定程度的时候,也做了分库分表;

这时候领导、业务人员在用数据做分析的时候,数据来源可能是多个系统的多张表,这时候企图通过一个复杂的 SQL 跑出来结果就很困难了;通常公司会建立一个数据仓库,通过ETL工具把数据抽取到数据仓库中,再做数据的拟合和展示。

2. 跨系统的数据加工或查询:

我们现在所在公司,业务系统有几百个,由于业务流程比较复杂,前端系统在做业务操作的时候,在正式提交交易之前,有很多业务校验;

比如要查询客户在 X 系统的交易历史,在 Y 系统的交易历史,在 Z 系统的交易历史;那么就需要分别调用 X、Y、Z 系统的接口,这个对前端系统很不友好,那么通常的解决方案是什么?

  • A 方案:做一个中间服务,中间服务去调用 X、Y、Z 系统的接口,客户端直接调用这个中间服务;这种方案只是把前端要做的事情,转移到了中间服务;

  • B 方案:整合 X、Y、Z 三个系统,建服务中台;这种方法很好,但是极为难,对于很多公司来说,别说把 X、Y、Z 三个系统整合成一个中台系统,就是其中一个系统本身进行重构,都是非常困难的;

  • C 方案:把 X、Y、Z 三个系统中需要的数据,通过 ETL 抽取加工到一个数据仓库中,对外提供服务;这个系统最大的好处是在不改造 X、Y、Z 三个系统的前提下,又可以实现跨系统的查询。

我们在 C 方案的基础上又往前做了一步,就是将落地后的数据又做了一次加工,将需要跨表关联的数据,提前关联好存入 MongoDB 中,对外提供查询服务;这样可以将多表关联查询,变成了单表查询。


吐数据 VS 抽数据

接上文中第二个例子中的 C 方案,有些同学可能会有个疑问:数据抽取,需要抽取哪些数据呢?为什么不让这些系统把数据吐出来呢?

答案也简单,“有的时候,数据不一定能吐出来”。

  • MySQL 数据库往外吐数据有比较成熟的中间件,比如 Canal,它可以通过监听 Mysql 的 binlog 日志来获取数据,binlog 设置为 row 模式,能够获取到每一条新增、删除、修改的日志,同时还能获取到修改前后的数据;

  • 其他商用数据库,比如 Oracle、DB2 等,我也查阅过相关的资料,也是有触发器机制,可以当数据发生变化的时候通知出来,比如调用一段程序,将数据发送到消息队列中,再由其他程序监听消息队列做后续处理。

不管什么类型的数据库,这种“吐数据”的方案,对于基础设施的要求都比较高,并且对原有系统有一定的侵入性;所以我们采用了对原有系统侵入性更小的方案:主动抽数据。


ETL 方案的优缺点

1. 优点

  • 侵入性较低,数据源系统只需要开通数据库的访问权限即可,为保证数据抽取对业务的影响,通常是访问源系统的备库,并且多带带设置一个只读权限的数据库用户;

  • 支持不同类型数据源的数据抽取,比如源库有 Mysql、DB2、Oracle,通过 ETL 也可以轻松搞定;

  • 数据整合,将不同业务系统的相同数据整合在一起,比如有些系统 M/F 表示男女,有些系统 1/0 表示男女,ETL 在抽取加工后转换成统一的编码;

2. 缺点

  • 比较致命的一个缺点,就是数据抽取和加工有一定的延迟,需要根据业务场景进行评估,是否接受这个延迟;

  • 可能会受到源库表结构变化的影响;

  • 如果源库中的表没有时间戳,或者时间戳不准确,那么增量抽取就变得很困难;

  • 需要招聘 ETL 开发岗,从我目前的经验看,不是特别好招。

我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。

评论0 赞同0
  •  加载中...
刘东

刘东

回答于2022-06-28 13:46

关联表都是有复杂度的,一般不超过三个,不然后期维护很难看懂逻辑。

sql优化

可以试试拆分sql,在代码里多次查询再主键关联,最后合并数据。



索引

如果很慢的话可以调查一下是不是sql有笛卡尔积现象,没有加主键或缺少索引。一般查询慢都是缺少索引,或者索引没用上。


分页

业务逻辑上要加分页,不要一次查太大量的数据。


评论0 赞同0
  •  加载中...
用户84

用户84

回答于2022-06-28 13:46

我记得ucloud巴巴开发手册规定了一次join不能超过3张表,为什么会有这种规范,显然是在某种业务场景下要多做数据冗余,方便查询,性能更高,带来的缺点就是更新可能会更复杂,而三范式结构更清晰,数据量大性能必然会下降,所以要有取舍,设计表结构时,要三范式和反范式结合而用,否则那些头部互联网公司哪个业务不复杂,虽然可以用es和hbase,但如果都是join十多张表那都不用玩了,我所在的物流公司,业务也是非常复杂,刚来公司的时候就发现,前期表结构规划不合理,也没有采用es等中间件做数据聚合,一个简单的例子,扫条码码入库,全链路压测吞吐连10都不到,走读下代码,一个获取订单信息的查询10张表,整个流程中还有多个系统的同步调用,基本上随便都是七八张表以上,本身也是个新项目,跑了一年左右了,量没有特别大,但是业务复杂的牵一发动全身,这种系统就别想重构了,大公司你懂的,所以首先就是各种sql优化,能提高多少是多少,待了半年左右就走了,再待下去量上来,系统扛不住,天天就得加班挨叼了。所以说一个好的设计,至少可以让你系统能抗的住未来一两年的业务的增长。

评论0 赞同0
  •  加载中...
SolomonXie

SolomonXie

回答于2022-06-28 13:46

给你三个建议

建议一:

你应该找需求人员,了解清楚需求,看看能否减少关联表

建议二:

关联十几张表,很大概率,你这个是报表展示的需求,可以用etl工具抽取必要的字段,然后预处理一些简单汇总,这样能少扫描记录,提升查询速度

建议三:

建议使用适合做数据分析的平台,如Hadoop,hbase,tispark

评论0 赞同0
  •  加载中...
OldPanda

OldPanda

回答于2022-06-28 13:46

什么业务需要关键这么多表检索?用物化视图做多次查询,或先优化一下脑子

评论0 赞同0
  •  加载中...
zhaochunqi

zhaochunqi

回答于2022-06-28 13:46

这种查询大概率不是要求查实时数据,就是统计报表用的,那你为什么非得要从原数据结构上做这种复杂查询?为什么不能去做etl之后再优化数据结构?一条路走到黑等着的就肯定是死胡同。如果是要求查询实时数据,那就用业务代码去简化查询逻辑,用业务代码做数据计算和拼接,把变动频率低的数据做缓存,把读库做分库分表,办法多的是,你除了写sql就不会别的了?

评论0 赞同0
  •  加载中...
livem

livem

回答于2022-06-28 13:46

一次查询需要关联十几张表,是不是报表查询的维度太多了?

关联子查询的执行逻辑和通常的SELECT语句的执行逻辑完成不一样。这就是SQL关联子查询难以理解的原因。

在关联查询时要注意:where子句中一定要包含表之间的连接条件,如 line.lid=track.lid,否则查询结果会完全超乎我们的想象,造成不必要的麻烦。
我看了一下回答,感觉很少有人能说到点子上。

先说说需求吧,一次十几张表,这是什么需求?是不是理解错误,还是说这需求必须要做?建议和业务沟通沟通。

如果说,需求真的不能改,那就用视图吧。

使用视图时,会运行视图里的sql查询语句创建出一张临时表。

可以将频繁使用的select语句保存成视图,这样就不用每次都重新书写了。

使用视图需要注意什么?

(1)避免在视图的基础上再次创建视图,因为这样多重视图会降低sql的性能和效率;

(2)不能往视图里插入数据,不然会报错。

最后,其实做报表真的不复杂,你要是用好报表工具FineReport,写sql那真的是很轻松,回复“报表”就能有了。

评论0 赞同0
  •  加载中...
Yi_Zhi_Yu

Yi_Zhi_Yu

回答于2022-06-28 13:46

互联网时代倡导非关系型数据库,首先保证单表查询速度到极致,然后程序设计数据关联最终算出结果,这才是解决之道。强烈依赖关系型数据库是一种偷懒的方式,当今海量数据时代,关系型数据库用武之地也就剩下对速度要求不高的后台统计和用户量低的场景。

评论0 赞同0
  •  加载中...
hsluoyz

hsluoyz

回答于2022-06-28 13:46

良好的设计数据库,这种情况往往是糟糕的数据库设计的问题。找个对数据库有深入了解大牛,帮忙规划一下,要不了几天,但很解决问题。

评论0 赞同0
  •  加载中...
Simon_Zhou

Simon_Zhou

回答于2022-06-28 13:46

本人写sql也有好多年了,但一次查询关联10几张表的情况还没碰到过。但是这种情况还是有优化的方法的。

首先查询关联10几张表,不管是内联还是外联,不管怎么优化你的sql语句,比如建索引,指定返回列,where加限制条件,我相信你的结果还是会很慢的。 因为这已经不是技术层面可以去优化的,建议还是从业务层面去优化。

不管多复杂的业务我们都可以去分解它,将它分解成一段段的子结果集,可以将它们作为临时表或者结果表存储起来,在最终的查询时可以从分解的子集去查询,这样就避免了多表关联,而且这样代码可读性,可维护性更好。也符合我们设计代码的基本原则。

评论0 赞同0
  •  加载中...

最新活动

您已邀请0人回答 查看邀请

我的邀请列表

  • 擅长该话题
  • 回答过该话题
  • 我关注的人
向帮助了您的网友说句感谢的话吧!
付费偷看金额在0.1-10元之间
<