数据仓库的性能问题及解决之道

随着数据量不断增长和业务复杂度逐渐攀升,数据处理效率面临巨大挑战。最典型的表现是面向分析型场景的数据仓库性能问题越来越突出,压力大、性能低,查询时间长甚至查不出来,跑批跑不完造成生产事故等问题时有发生。当数据仓库出现性能问题时便不能很好服务业务了。

传统数据仓库的性能解决方案

集群,也就是采用分布式技术,依赖扩展硬件来提升性能,是最常见的手段。将一个大的任务拆分到各个集群节点上同时计算自然可以获得比单机更好的性能,即使不进行分布式计算而简单分担并发任务也可以减轻单节点的计算压力。集群解决性能问题的思路简单粗暴,只要数据仓库支持集群并且任务能够拆分就可以通过堆硬件来解决性能问题,虽然可能做不到线性提升但基本都会有效果。

集群的缺点在于高成本。现在的大数据时代大家言必提集群,经常不管单机性能是不是得到充分发挥,反正只要能集群往里扩容就行了,集群似乎是很多人眼中的“万能药”。但我们要注意,集群需要更多硬件支撑成本自然高,集群运维也需要投入更多资源。另外有些复杂多步骤计算任务由于无法拆分压根就没法用集群,比如大多数的多步骤大数据量跑批任务还只能用单机(单体数据库存储过程)完成。集群虽好,但并不万能,即使财大气粗架设集群也并不能解决所有性能问题。

对于一些耗时较长的查询还可以采用预计算,采用空间换时间的办法将要用到的数据事先加工好,这样就可以将计算复杂度降到 O(1) 大幅提升效率。预计算同样可以解决很多性能问题,通过预汇总将要用到的数据事先加工好,用空间换时间,对多维分析场景尤其有效。

预计算的问题在于灵活性太差。我们仍然以多维分析场景为例,虽然理论上可以将所有维度组合都预计算好(这样就可以满足所有查询需求),但真这样做会发现不现实,这需要天量的存储空间才能满足。所以只能通过梳理业务进行部分预计算,这就大大限制了查询范围降低了灵活性。

其实即使能全部预计算,仍然解决不了诸如非常规聚合(如算中位数、方差)、组合聚合(如算月平均销售额)、条件测度(如算交易金额大于 100 元以上的订单销售额合计)、时间段汇总(自由选择时间段内的汇总)等情况。实际业务中的查询需求五花八门,灵活性极强,预汇总只能解决其中的一部分甚至仅仅一小部分问题,要更大范围、更高效率地满足多样的在线查询需求还需要更有效的计算手段。

更有效的手段是优化引擎,让数据仓库在同样的硬件资源下跑出更好的性能。这是许多厂商的工作重点,有大量工程性手段已为业界熟知,比如提供列存、向量化执行、编码压缩、内存利用等(集群也可以算是一种工程手段),通过这些技术在一定数据规模内可以提升几倍的计算性能,在某些场景下足够用。但工程些手段并不能改变计算的复杂度,在数据量大和复杂度特别大的场景时,性能提升仍然常常不能满足需求。

优化引擎更有效的手段是算法层面上的(复杂度层面的提升),一个优秀的数据仓库优化引擎可以猜出一个查询语句的真正目标,从而采用更高效的算法执行(而不以字面表达的逻辑去执行),算法层面的改善经常可以获得更高的性能提升。当前大部分数据仓库仍以 SQL 作为主要查询语言,基于 SQL 的优化已经做得足够优秀。但由于 SQL 描述能力的局限性,复杂查询会采取非常迂回的方法,一旦 SQL 复杂度上来优化引擎就很难发挥作用了(猜不出目标只能按照字面表达去执行,性能就不会提升),即优化引擎仅对简单查询有效

举个例子,TopN 运算时:

SELECT TOP 10 x FROM T ORDER BY x DESC

大部分数据仓库都会优化,不会真排序。但是改成组内 TopN 以后:

select * from
 (select y,*,row_number() over (partition by y order by x desc) rn from T)
where rn<=10

复杂度虽然没有提升很多,但优化引擎会犯晕,猜不出这句 SQL 的真正目的,只能按照 SQL 表达的意思进行大排序而性能低下。所以,有些场景我们会事先把数据加工成宽表,这样就可以简化查询从而发挥优化引擎的作用。虽然会付出很多代价,但为了有效利用优化引擎有时也只能不得已而为之。

当前几乎所有数据仓库技术都在竞争 SQL 能力,提供更完善的 SQL 支持、提供更强的优化能力、支持更大规模的集群等等,虽然这可以最大限度地“讨好”受众很广的 SQL 使用者,但在面向复杂计算场景时使用前面的方法往往不够有效,性能问题仍然存在。再在 SQL 的基础上努力(工程上的优化)获得的效用也并不高,并不能从根本上解决问题。而这类问题在实际业务中并不少见,下面是几个例子。

复杂有序计算。比如用户行为转换漏斗分析:用户页面浏览商品、搜索、加购物车、下单、付款等多个有序事件,现在要统计每个步骤的用户流失率,就需要遵循多个事件在指定时间窗口内完成、按指定次序发生才有效的原则来实现。这使用 SQL 就很难实现了,需要借助多个子查询(与步骤数量一致)和反复关联完成,有些数据仓库甚至不能执行这种复杂语句,即使能执行,性能也很低,更难以优化。

多步骤大数据量跑批。复杂的跑批任务使用 SQL 效果也不好,经常需要在存储过程中借助游标逐步读取数据处理,但游标性能很低又无法并行,最后不仅资源消耗大性能也低。同时,几十步运算在存储过程中需要几千行代码,过程中会伴随中间结果反复落地,性能很差,月末年终数据量大任务多的时候就会出现在规定时间内跑不完的情况。

大数据上多指标计算。很多行业都有指标计算的需要,比如银行的贷款业务中就包括多级分类维度、多种担保类型,再加上客户种类、放款方式、币种、分支机构、日期、客户年龄段、学历等指标会衍生出极其庞大的指标数量,汇总这些指标时要基于大量的明细数据完成,计算时会涉及大表关联、条件过滤、分组汇总、去重计数等多种混合运算,灵活、量大、计算复杂,同时伴随高并发导致使用 SQL 来做很吃力,预计算不灵活,实时算又太慢。

这些问题用 SQL 很难解决,于是扩展 SQL 能力成为继集群、预计算和优化引擎外的第四方案。现在很多数据仓库支持用户自定义函数(UDF)来扩展计算能力,用户可以根据实际需求编写 UDF 以满足自身的需要。但 UDF 的开发难度较高,这对使用者的能力有很高要求。更重要的是 UDF 仍然无法解决数据仓库的计算性能问题,因为仍然受限于数据库的存储,无法根据计算特点设计更高效的数据存储(组织)形式,很多高性能算法就无法实施,自然无法获得高性能。

因此,要解决这些问题就需要采用非 SQL 的方案手段,在数据库外由程序员控制执行逻辑,以便更好地采用低复杂度算法和充分利用工程手段。

于是我们看到诸如 Spark 等大数据计算引擎应运而生。Spark 提供的是一个分布式计算框架,本意还是希望通过大规模集群来满足算力的需要,由于基于全内存的设计对于超出内存的计算不够友好,而且 RDD 采用的 immutable 机制,在每个计算步骤后都会复制出新的 RDD,造成内存和 CPU 的大量占用和浪费,性能很低,工程手段利用的并不够好。此外,Spark 的计算类库也不够丰富,缺少足够的高性能算法,很难实现“低复杂度算法”的目标。加之 Scala 的使用难度很大,导致面对前面提到的那些复杂计算问题编码难度极高,既不好写性能也不高,这可能也是 Spark 又要拥抱 SQL 的原因之一。

传统数据仓库不行,外部编程(Spark)又难又慢,那还有什么选择?

从前面的内容我们不难得出这样的结论,要解决数据仓库的性能问题确实需要独立于 SQL 的计算体系(像 Spark),但这个计算体系要具备既简单又快的特点。描述复杂计算逻辑不能像 Spark 那么复杂,甚至要比 SQL 更简单;在计算性能上不能仅靠集群能力,还要提供丰富的高性能算法和工程能力从而能够充分利用硬件资源将单机性能发挥到极致。既有快速描述低复杂度算法的能力,又具备足够多的工程手段。同时,如果在部署运维方面还很方便就更理想了。

esProc SPL 的解决之道

esProc SPL 是一个专门处理(半)结构化数据的计算引擎,与当前数据仓库的能力一致。但与传统 SQL 型数据仓库不同,esProc 没有继续采用关系代数而是设计了全新的计算体系,在此基础上提供了 SPL(Structured Process Language)语法。SPL 相对 SQL 提供了更多的数据类型和运算、更丰富的计算类库,描述能力更强,在过程计算的加持下可以按照自然思维编写算法,不必绕,也更低代码,可以很好应对前面场景中的多步骤复杂计算,相对其他硬编码以及 SQL 的实现方式更简单。

在性能方面,esProc SPL 提供了很多“更低复杂度”的高性能算法来保证计算性能。我们知道,软件改变不了硬件的性能,想要在同等硬件条件下获得更高的计算性能只能设计更低复杂度的算法让计算机少执行一些基本运算,这样自然就变快了。但是算法不仅要想出来,还要能实现,写得越简单越好,所以说写得简单和跑得快其实是一回事。

SPL 提供的部分高性能算法,其中很多都是 SPL 的独创发明

当然,高性能算法还离不开良好的数据组织,即数据存储。像有序归并、单边分堆都要求数据有序才能实施。但是数据库的存储相对封闭,外界无法干预,无法根据计算特征设计存储。基于这样的原因,SPL 提供了自有的二进制文件存储,将数据存储在库外的文件系统中,以便充分利用列存、有序、压缩、并行分段等数据存储优势,实现根据计算特性来灵活组织数据,充分发挥高性能算法效力。

除了这些高性能算法,esProc 还提供了众多工程手段来提升计算性能,列存、压缩编码、大内存以及向量式计算等等。如前所述,这些工程手段虽然无法改变计算的复杂度,但使用后经常能获得数倍的性能提升,再叠加 SPL 内置的众多低复杂度算法,性能提升一两个数量级是常态。

前面说过,基于非 SQL 体系要获得高性能需要由程序员控制执行逻辑,采用低复杂度算法,并且充分利用工程手段。SPL 理论体系的不同带来了描述能力强的效果,编码简单不必绕;丰富的高性能算法库及相应存储机制可以直接使用,实现采用低复杂度算法的同时充分工程优化手段的目标,达到既简单又快的效果。

像 TopN 在 SPL 中被看成普通的聚合运算,无论对全集和分组都是一样的,都不需要大排序,这样就实现了“采用更低复杂度算法”的目标,从而获得了高性能。

我们再来看一下前面提到的电商漏斗例子实现,来感受 SQL 和 SPL 的不同。

SQL 实现:

with e1 as (
 select uid,1 as step1,min(etime) as t1
 from event
 where etime>= to_date('2021-01-10') and etime<to_date('2021-01-25')
 and eventtype='eventtype1' and …
 group by 1),
e2 as (
 select uid,1 as step2,min(e1.t1) as t1,min(e2.etime) as t2
 from event as e2
 inner join e1 on e2.uid = e1.uid
 where e2.etime>= to_date('2021-01-10') and e2.etime<to_date('2021-01-25')
 and e2.etime > t1 and e2.etime < t1 + 7
 and eventtype='eventtype2' and …
 group by 1),
e3 as (
 select uid,1 as step3,min(e2.t1) as t1,min(e3.etime) as t3
 from event as e3
 inner join e2 on e3.uid = e2.uid
 where e3.etime>= to_date('2021-01-10') and e3.etime<to_date('2021-01-25')
 and e3.etime > t2 and e3.etime < t1 + 7
 and eventtype='eventtype3' and …
 group by 1)
select
 sum(step1) as step1,
 sum(step2) as step2,
 sum(step3) as step3
from
 e1
 left join e2 on e1.uid = e2.uid
 left join e3 on e2.uid = e3.uid

SPL 实现:

A
1=["etype1","etype2","etype3"]
2=file("event.ctx").open()
3=A2.cursor(id,etime,etype;etime>=date("2021-01-10") && etime<date("2021-01-25") && A1.contain(etype) && …)
4=A3.group(uid).(~.sort(etime))
5=A4.new(~.select@1(etype==A1(1)):first,~:all).select(first)
6=A5.(A1.(t=if(#==1,t1=first.etime,if(t,all.select@1(etype==A1.~ && etime>t && etime<t1+7).etime, null))))
7=A6.groups(;count(~(1)):STEP1,count(~(2)):STEP2,count(~(3)):STEP3)

SPL 在有序计算的支持下实现代码更加简短,可以根据自然思维分步(过程化支持)编写代码,而且这段代码可以处理任意步骤的漏斗分析(这里是 3 步,更多步只需要改变参数即可),相对 SQL 每增加一步漏斗就要增加一个子查询显然更有优势,这就是 SPL 的简单带来的效果。

性能上,这个例子其实是实际案例的简化版(原 SQL 有近 200 行),用户使用 Snowflake 的 Medium 服务器(相当于 4*8=32 核)3 分钟没有跑出来;而 esProc SPL 代码在一个 12 核 1.7G 的低端服务器上仅用不到10 秒就跑出来了,这是 SPL 高性能算法和相应工程手段造就的高性能。

有了这些机制以后,esProc SPL 就可以充分利用硬件资源,将单机性能发挥到极致,不仅原来很多单机性能问题可以得到有效解决,甚至很多原来使用集群的计算现在也可以用单机搞定(可能更快),达到单机顶级群的效果。当然,单机有极限,SPL 也提供了分布式集群功能,当单机性能无论如何也无法满足需要时可以通过集群横向扩展算力。这也是 SPL 的高性能计算理念:先把单机性能提升到极致,不够用再集群

当然,任何技术都有不足,SPL 也不例外。SQL 经过几十年的积累发展,很多数据库都拥有很强的优化引擎。对于适合用 SQL 完成的简单场景运算,可以将普通程序员写出来的慢语句优化出较好的性能,从这个意义上讲,对程序员的要求相对较低。某些场景(比如多维分析)已经被优化多年,某些 SQL 引擎也可以跑出相当好的极致性能。相比之下,SPL 没有做多少自动优化的功能,要跑出高性能,几乎全靠程序员写出低复杂度的代码。程序员需要经过一定的训练来熟悉 SPL 的理念和库函数,会多一个上手的门槛,不过获得数量级的性能提升和成倍的成本下降,这些付出通常也还是值得的。

SPL是开源免费的,欢迎前往乾学院社区了解更多!

开源SPL源码地址

免费下载试用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/935225.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云和恩墨 zCloud 与华为云 GaussDB 完成兼容性互认证

近日&#xff0c;云和恩墨&#xff08;北京&#xff09;信息技术有限公司&#xff08;以下简称&#xff1a;云和恩墨&#xff09;的多元数据库智能管理平台 zCloud 与华为云计算技术有限公司&#xff08;以下简称&#xff1a;华为云&#xff09;的 GaussDB 数据库完成了兼容性互…

分布式专题(4)之MongoDB快速实战与基本原理

一、MongoDB介绍 1.1 什么是MongoDB MongoDB是一个文档数据库(以JSON为数据模型)&#xff0c;由C语言编写&#xff0c;旨在为WEB应用提供可扩展的高性能存储解决方案。 MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xf…

03篇--二值化与自适应二值化

二值化 定义 何为二值化&#xff1f;顾名思义&#xff0c;就是将图像中的像素值改为只有两种值&#xff0c;黑与白。此为二值化。 二值化操作的图像只能是灰度图&#xff0c;意思就是二值化也是一个二维数组&#xff0c;它与灰度图都属于单信道&#xff0c;仅能表示一种色调…

Linux下redis环境的搭建

1.redis的下载 redis官网下载redis的linux压缩包&#xff0c;官网地址:Redis下载 网盘链接&#xff1a; 通过网盘分享的文件&#xff1a;redis-5.0.4.tar.gz 链接: https://pan.baidu.com/s/1cz3ifYrDcHWZXmT1fNzBrQ?pwdehgj 提取码: ehgj 2.redis安装与配置 将包上传到 /…

印闪网络:阿里云数据库MongoDB版助力金融科技出海企业降本增效

客户背景 上海印闪网络科技有限公司&#xff0c;于2017年1月成立&#xff0c;投资方包括红杉资本等多家国际知名风投公司。公司业务聚焦东南亚普惠金融&#xff0c;常年稳居行业头部。创始团队来自腾讯&#xff0c;中国团队主要由运营、风控及产研人员组成&#xff0c;核心成员…

【有啥问啥】大语言模型Prompt中的“System指令”:深入剖析与误区澄清

大语言模型Prompt中的“System指令”&#xff1a;深入剖析与误区澄清 引言 在与大语言模型&#xff08;LLM&#xff09;交互时&#xff0c;“prompt”&#xff08;提示符&#xff09;这一概念已不再陌生。Prompt是引导模型生成特定类型文本的关键输入&#xff0c;决定了模型的…

【解决】Vue配置了端口号 发布项目仍会改变

1 梗概 这里记录Vue配置了端口号&#xff0c;npm run serve 发布运行仍会选择其他端口&#xff0c;一般是配置的端口号1 2 解决方案 网上有些教程说是由于 portfonder 版本问题&#xff0c;需要降低版本&#xff0c;可能这个的确是个解决方案。 还有说在package.json 中配置 &q…

uniapp-在windows上IOS真机运行(含开发证书申请流程)

前期准备 1、Itunes [Windows 32位 iTunes]下载地址、所有版本的iTunes下载地址 [Windows 64位 iTunes]下载地址、所有版本的iTunes下载地址 2、爱思助手 https://www.i4.cn/ 3、typeC转Usb接口 (物理意义的设备接口&#xff09; 4、Mac电脑&#xff08;用来生成证书&am…

网络层分析

网络访问层仍受到传输介质的性质和相关适配器的设备驱动程序的影响很大。网络层与网络适配器的硬件性质几乎是完全分离的。为什么是几乎呢&#xff1f;该层不仅负责发送和接受网络数据&#xff0c;还负责在彼此不直接连接的系统之间转发和路由分组。查找最佳路由并选择适当的网…

罗技键鼠更换新台式机无蓝牙通过接收器安装

优联驱动下载&#xff1a; http://support.logitech.com.cn/zh_cn/software/unifying &#xff08;下载安装后按照步骤一步步操作&#xff0c;匹配后即可使用&#xff09; 向京东客服反馈后提供的驱动下载安装连接 有问题欢迎评论沟通~

《Keras3 minist 手写数字AI模型训练22秒精度达到:0.97》

《Keras3 minist 手写数字AI模型训练22秒精度达到&#xff1a;0.97》 一、修改源码加上如下两条代码二、源码修改如下三、Keras3 minist 训练22秒结束&#xff0c;训练过程截图四、Keras3 minist 源码截图 一、修改源码加上如下两条代码 import os os.environ["KERAS_BAC…

装饰模式的理解和实践

在软件设计中&#xff0c;设计模式提供了一种可复用的解决方案&#xff0c;用于解决常见的设计问题。装饰模式&#xff08;Decorator Pattern&#xff09;&#xff0c;也称为包装模式&#xff08;Wrapper Pattern&#xff09;&#xff0c;是结构型设计模式之一。它通过一种对客…

游戏引擎学习第43天

仓库 https://gitee.com/mrxiao_com/2d_game 介绍运动方程 今天我们将更进一步&#xff0c;探索运动方程&#xff0c;了解真实世界中的物理&#xff0c;并调整它们&#xff0c;以创建一种让玩家感觉愉悦的控制体验。这并不是在做一个完美的物理模拟&#xff0c;而是找到最有趣…

Maven(生命周期、POM、模块化、聚合、依赖管理)详解

Maven构建项目的生命周期 在Maven出现之前&#xff0c;项目构建的生命周期就已经存在&#xff0c;软件开发人员每天都在对项目进行清理&#xff0c;编译&#xff0c;测试&#xff0c;部署等工作&#xff0c;这个过程就是项目构建的生命周期。虽然大家都在不停的做构建工作&…

第六届地博会开幕,世界酒中国菜美食文化节同期启幕推动地标发展

第六届知交会暨地博会开幕&#xff0c;辽黔欧三地馆亮点纷呈&#xff0c;世界酒中国菜助力地理标志产品发展 第六届知交会暨地博会盛大开幕&#xff0c;多地展馆亮点频出&#xff0c;美食文化节同期启幕推动地标产业发展 12月9日&#xff0c;第六届粤港澳大湾区知识产权交易博…

通过“思维链”提升ChatGPT提示词质量,更好的辅助学术论文

目录 1.写在开头 2.思维链是啥 1.写在开头 对于初步接触AIGC工具的宝子们&#xff0c;可以直接用最符合你习惯的方式去使用Kimi、ChatGPT这类AI工具。想到什么问题就问什么。对于比较简单直接的问题&#xff0c;不需要去想怎么写好提示词&#xff0c;直接在聊天窗口里表述你…

nacos bootstrap.yml 和 spring.config.import 加载配置的流程区别

相关依赖 springboot:2.7.15 nacos:2.2.3 bootstrap.yml加载方式 加载流程如下图所示 从图中可以看出,&#xff1a; 1.bootstrap.yml 的加载是在 BootstrapApplicationListener.onApplicationEvent 接收到 ApplicationEnvironmentPreparedEventEvent 事件后另起一个 Sprin…

高效项目托管指南:从本地到 GitHub 的完整流程

在现代软件开发中&#xff0c;将项目托管在 GitHub 上是一个常见且高效的方式。GitHub 不仅可以用作版本控制工具&#xff0c;还能帮助你与团队协作或展示自己的项目。本文将带你一步步完成项目的打包和上传。 高效项目托管指南&#xff1a;从本地到 GitHub 的完整流程 1. 准备…

【漏洞复现】CVE-2024-34102 Magento Open Source XXE漏洞

目录 漏洞介绍 影响版本 环境搭建 查看版本 漏洞复现 手动复现 漏洞 poc Magento Open Source 是一个免费开源的电子商务平台&#xff0c;适合中小企业或开发团队通过自定义代码和插件创建在线商店。它由社区开发和支持&#xff0c;功能强大但需要更多的技术投入。Adobe…

Scala的隐式对象

Scala中&#xff0c;隐式对象&#xff08;implicit object&#xff09;是一种特殊的对象&#xff0c;它可以使得其成员&#xff08;如方法和值&#xff09;在特定的上下文中自动可用&#xff0c;而无需显式地传递它们。隐式对象通常与隐式参数和隐式转换一起使用&#xff0c;以…