[转载]PgSQL · 特性分析· JIT 在数据仓库中的应用价值

原文:http://mysql.taobao.org/monthly/2016/11/10/

背景

近几年,分析型数据库中有项技术得到了广泛的应用。它就是 JIT(Just-in-time compilation)动态编译。还有一些相关名词 LLVM codegen 和这项技术相关。本文把这项技术做一个简单的分析,和大家分享。

一、JIT 是什么

长久以来数据仓库都是以高效的处理量数据的能力著称。随着硬件的发展,他们使用大量相关技术充分挖掘硬件的能力提高数据的吞吐量和处理效率。例如 SMP MPP mapreduce 列存储 压缩 等等。这么多年开源生态的活跃,使得我们对这类技术的实现细节也越来越了解。嗯,现在轮到 JIT 普及了。

简单的说 JIT 是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态直译。静态编译的程序在执行前全部被翻译为机器码,而直译执行的则是一句一句边运行边翻译。 JIT 则混合了这二者,一句一句编译源代码,但是会将翻译过的代码缓存起来以降低性能损耗。相对于静态编译代码,即时编译的代码可以处理延迟绑定并增强安全性。

二、数据仓库中的 JIT 应用

数据仓库领域,单个的任务为了追求高性能,需要尽可能的利用整个仓库的硬件资源进行计算。当前的硬件条件下,分析业务无疑是 CPU 密集型的任务。我们经常能看到跑一个任务,调度整个集群的 CPU 满负荷运转几分钟,甚至几小时的情况。另外,随着我们的数据的爆发式增长,数据压缩存放已经成为缺省选项。读取的读写都要相当量的 CPU 计算。如何提高 CPU 的计算效率成为一个通用的性能优化任务。

了解数据库内核实现的同学都知道,传统数据库后端编码是一套通用的代码,实现通用的数据处理。例如

  1. 一套代码实现不同数据类型(定长,变长)组合的表结构的读和写,而一个 SQL 往往只涉及几个有限的表。比如 select * from t 这个 SQL 只涉及一个表,这表的数据类型列的个数是固定的。
  2. 通用的 DB 执行器,可以兼容不同执行节点随意组合的执行方式,而一个SQL 往往是固定的几个执行节点的组合,比如 select count(*) from t 这个 SQL 就是一个全表扫描节点 Seqscan 和聚集节点 Group 的简单组合。
  3. 实现一个通用的 SQL 表达式计算框架,兼容所有表达式计算(各种数据类型 + - 计算 不同参数的函数调用)。而单个 SQL 中表达式是固定的。比如 select fun(t.a,t.b) + t.c from t 这个 SQL 即是把表 t 中的3个列做简单的函数加合计算。

各位已经看出,单个 SQL 中,很多之前的“变量”,已经成为“常量”,如果我们在知道用户的 SQL 的之后再 “coding”,会少很多条件判断,少很多无关代码,效率自然会高很多。 更加变本加厉的是,数据分型业务,往往处理的数据相当庞大。单个任务(SQL)往往使用相同的模式处理少则几十 GB,多则上 TB 的数据。如果我们拿到用户的 SQL 后使用 JIT 技术生成一段“精简”的代码再执行,效率会大大提高。

其实,这样的思路早在一些高端大气的商业产品中得到了使用,例如 IBM DB2 中就产品化了类似的特性。称作 threaded code generation 技术,动态生成效率较高的 section 来优化 CPU 执行效率。感觉很高级啊。的确,该技术之前不普及的原因是实践起来有一定难度,难点在于在执行阶段生成代码缺少难度较低的实现方式,直到 LLVM 的出现。

三、LLVM 是个什么鬼

LLVM,一个自由软件项目,是一种编译器的基础建设,以 C++ 写成。它是为了任意一种编程语言写成的程序,利用虚拟技术,创造出编译时期,链接时期,运行时期以及“闲置时期”的最优化。它最早是以C/C++为实现对象,目前它支持了很多编程语言。 LLVM 项目起源于 2000 年伊利诺伊大学厄巴纳-香槟分校维克拉姆·艾夫(Vikram Adve)与克里斯·拉特纳(Chris Lattner)的研究发展而成,他们想要为所有静态及动态语言创造出动态的编译技术。LLVM 是以 BSD 授权来发展的开源码软件。在2005年,苹果电脑雇用了克里斯·拉特纳及他的团队,为了苹果电脑开发应用程序系统,LLVM 为现今 Mac OS X 及iOS开发工具的一部分。

嗯,乔大爷看上的技术都差不了。LLVM 的命名最早源自于底层虚拟机(Low Level Virtual Machine)的首字字母缩写。它提供了一种在程序运行时编译执行代码的可行的程序框架。不仅仅如此 LLVM 这几年快速普及,还有很多靓丽的特性

  1. LLVM 也可以在编译时期、链接时期,甚至是运行时期产生可重新定位的代码(Relocatable Code)上面已经提到;
  2. LLVM 支持与语言无关的指令集架构及类型系统。LLVM 可以提供完整编译器系统的中间层,从编译器获取中间表示(IR)代码并发出优化的 IR。然后可以将这个新的 IR 转换并链接到目标平台的依赖于机器的汇编语言代码。在我们的应用场景中,使用 LLVM API 会生成中间代码 IR。存放在内存或外部文件中。在目标平台执行时,针对对应的平台再生成对应的机器码再执行。这意味着我们在 IR 层编程,在不同的 CPU 上执行,会生当前硬件平台生成最优的机器码。即使是 intel 的 x86 平台,不同代的 CPU 优化程度也不同。例如 LLVM 会充分利用新 CPU 上的指令集,例如 SIMD。这一点在数据仓库做浮点数计算时会用到。
  3. LLVM 有一套完整的 API 可以用于编码,并生成 LLVM IR 中间代码。支持很多种编码语言,C/C++ 都覆盖到了。我们主要的工作都在这了。
  4. LLVM 的前端编译器 clang 兼容 gcc, 且性能相当。相关代码使用编译器 clang 编译,能和 gcc 编译的二进制相互链接。

四、谁在用 LLVM

目前比较流行的数据分析数据库中使用 JIT 技术的有

产品简介状态
HyPer高性能内存数据库闭源,使用 LLVM code generation 技术
ImpalaCloudera公司主导开发的新型查询系统开源,使用LLVM动态生成部分执行器
Postgres ProfessionalPostgreSQL 的一个发行版开源,JIT-compilation of queries 的计划
gpdb基于 PostgreSQL 的 MPP 产品开源,已经开始开发 JIT ,目前刚起步

另外,国内几家互联网公司也都有使用 LLVM 优化自己数据分析业务的案例

五、LLVM 可优化的点

一. 优化频繁调用的存取层

数据库执行器通过存取层装在数据,针对特定的表结构,可以定制读取和解析 tuple 的代码,其中有很多优化点。

举例: 通常,情况下通用的解析 tuple 的流程如下,每一列的数据类型不同,是定长数据类型还是变长也不确定。

void MaterializeTuple(char* tuple) 
{
	for (int i = 0; i < num_slots_; ++i) 
	{
		char* slot = tuple + offsets_[i];
		switch(types_[i]) 
		{
			case BOOLEAN:
			*slot = ParseBoolean();
			break;
			case INT:
			*slot = ParseInt();
			break;
			case FLOAT: …
			case STRING: …
			// etc.
		}
	}
}

当知道表结构后, 动态生成的代码就简单了。

void MaterializeTuple(char* tuple) 
{
  *(tuple + 0) = ParseInt(); // i = 0
  *(tuple + 4) = ParseBoolean(); // i = 1
  *(tuple + 5) = ParseInt(); // i = 2
}

按照顺序解析数据,不需要做数据类型的判断,直接在获取对应偏移的数据,跳过不需要获得的列。都是能够优化 CPU 的点。随着处理的行数增加,节省的计算量是惊人的。这才只是刚刚开始。

二. 表达式计算

以 PostgreSQL 为例,它的表达式计算基于一套通用的框架,表达式求值计算像一颗二叉树一样,求值过程就是从叶子节点算到根节点。整个步骤是递归方式执行。

例如

select funx(((1 + a.b) + a.a )) /2 from a 

他的执行过程是
          expr(root)	// funroot
         funx(data)    // funx
       data (/) 2      // fundivision
   data (+) a.a        // funadd
1 (+) a.b              // funadd

可以看到,表达式越复杂,递归调用越深。执行的函数个数越多。

然而,在获取到查询计划之后再“写”代码,就简单了,只需要这样

llvm_expr_fun1
{
tmp = 1 (+) a.b;
tmp1 = tmp + a.a;
tmp3 = tmp1 / 2;
tmp4 = funx(tmp3); 
}

这么做的好处是:

  1. 递归改顺序执行
  2. 整个过程一个函数调用完成,性能提高明显。 整个优化方式适合 OLTP 和 OLAP 场景,我们可以像保存查询计划那样保存 LLVM 生成的表达式函数

三:优化执行器流程

这部分是表达式计算的高级版本,改进的单位从每一行数据的处理提高到整个 SQL 的处理流程。 传统的流水线执行方式效率不高,如果调整成循环批量处理方式,能充分利用 CPU cache,大幅提高效率。

举例

select *
from R1,R3,
(	select R2.z,
	count(*)
	from R2
	where R2.y=3
	group by R2.z
) R2
where R1.x=7
and R1.a=R3.b
and R2.z=R3.c

上面的 SQL 采用传统的方式是 pipeline 方式,如下图

pipeline.png

如果采用如下“批量”处理的方式

initialize memory of ona=b, onc=z, and Gz
for each tuple t in R1
	if t:x = 7
		materialize t in hash table of ona=b

for each tuple t in R2
	if t:y = 3
		aggregate t in hash table of Gz

for each tuple t in Gz
	materialize t in hash table of onz=c

for each tuple t3 in R3
	for each match t2 in onz=c [t3:c]
		for each match t1 in ona=b [t3:b]
			output t1 ◦t2 ◦t3

他的核心思想是批量处理,单独处理每个表,把处理结果固化下来 这么做的优势是充分利用现代 CPU 的大缓存,让尽可能多的数据的计算能够在 CPU cache 中完成,避免去相对慢得多的内存中存取数据。 再结合 CPU 向量计算相关指令集,性能会进一步提高。LLVM 会帮我们做到这一点。

性能

  1. 我们在场景 1 和 2 上完成了优化的 demo,在比较复杂的 SQL 表达式计算场景(读取单表中 10 个数值的简单数学计算,1000W 行数据),性能有 3 倍的提高(执行时间从25秒降到7秒)。
  2. 相关论文表明,以为典型的分析型业务场景模型 TPCH 为测试模型,采用上述优化的方法,TPCH 中所有 SQL 都能获得少则几倍,多则几十倍的性能提升。

总结

LLVM 降低了 JIT 的工程化难度,使得它最近几年在数据仓库领域得到了广泛的普及。它能通过提高 CPU 效率的方法提高任务的性能,显著降低硬件成本。

内容概要:本文档详细介绍了PlatforMax单机版5.0.1-rc6版本的完整安装流程,涵盖硬件、操作系统、硬盘、网络等前置环境要求,并提供了Ubuntu 20.04.3 Desktop与Server两种系统的安装步骤。重点强调系统需全新安装、禁用自动更新、正确设置磁盘分区以充分利用全部空间,以及创建指定用户名“amax”。随后指导用户通过运行离线安装包完成PlatforMax的部署,包括校验、解压、输入安装码、驱动与Docker配置等环节。安装完成后需通过浏览器访问初始化页面完成最终配置。文档还列举了常见问题及应对措施,特别是NVIDIA驱动不兼容时的处理方式,允许用户手动提供驱动或跳过安装以确保主程序顺利部署。; 适合人群:具备Linux系统操作基础,从事AI平台运维、系统集成或技术支持的相关技术人员,尤其适用于负责本地化部署高性能计算平台的工程师。; 使用场景及目标:①为满足AI训练与推理需求的企业级用户提供PlatforMax平台的本地单机部署方案;②指导技术人员完成从系统准备到平台上线的全流程安装,确保环境合规、数据安全和系统稳定运行;③解决新GPU驱动兼容性等问题,保障平台可扩展性和实用性。; 阅读建议:在实际操作前通读全文,重点关注硬件配置、磁盘管理、用户命名规则及驱动处理策略,建议在测试环境中先行演练,避免因误操作导致数据丢失或安装失败。
内容概要:本文提出了一种面向光储充社区的电动汽车有序充电双层优化模型,旨在通过Matlab代码实现对光伏发电、储能系统与电动汽车充电行为之间的协同优化。该模型采用双层架构,上层以降低社区综合用电成本为目标,综合优化光伏出力与储能调度;下层则结合用户充电需求与动态电价机制,实现电动汽车充电的有序管理,有效达成削峰填谷、提高可再生能源消纳率与电网运行效率的目的。文中详细阐述了模型的数学建模过程,包括目标函数与多重约束条件的设计,并配套提供了完整的Matlab仿真代码,便于读者复现结果、开展拓展研究与实际工程应用。; 适合人群:具备一定电力系统基础知识、优化理论背景及Matlab编程能力的研究生、科研人员,以及从事新能源发电、智能电网、电动汽车与综合能源系统等领域的工程技术人员。; 使用场景及目标:①研究光储充一体化系统的协同能量管理与优化调度策略;②探索电动汽车参与需求侧响应的有序充电调控方法;③学习并掌握双层优化模型在综合能源系统中的建模思路、求解流程与算法实现;④获取可用于学术论文复现、课程设计或实际项目开发的高质量Matlab代码参考。; 阅读建议:建议读者结合模型理论描述与Matlab代码进行对照学习,重点理解上下层优化问题的耦合关系、约束条件的物理意义及其代码实现方式,可通过调整负荷参数、光伏出力曲线或电价策略等方式进行仿真实验,深入探究模型的适应性与优化性能。
内容概要:本文系统研究了基于卡尔曼滤波的二维轨迹跟踪方法,重点在于利用Matlab实现卡尔曼滤波算法对目标在二维平面内的运动轨迹进行高精度估计与预测。文中深入阐述了卡尔曼滤波的核心原理,包括状态方程与观测方程的构建、协方差矩阵的更新机制以及滤波过程中的预测-校正循环,突出其在抑制测量噪声、提升轨迹平滑性方面的优势。通过设计合理的系统动力学模型和观测模型,实现了对含噪轨迹数据的有效滤波与未来状态预测,并进一步探讨了不同噪声强度下滤波器的鲁棒性与性能表现,验证了该方法在复杂干扰环境下仍能保持良好跟踪精度的能力。; 适合人群:具备信号处理、控制理论或状态估计基础知识,熟悉Matlab编程环境,从事自动化、电子信息、航空航天、机器人导航或相关领域的科研人员、工程师及研究生。; 使用场景及目标:① 掌握卡尔曼滤波在二维目标跟踪中的建模与实现流程;② 学习如何在Matlab中编写并调试卡尔曼滤波算法;③ 理解过程噪声与观测噪声对滤波效果的影响机制,并通过仿真实验优化参数配置以提升跟踪性能; 阅读建议:建议读者首先回顾卡尔曼滤波的基本理论,结合文中的Matlab代码逐模块分析算法实现细节,尝试调整系统参数(如噪声协方差)并观察滤波结果变化,从而深化对滤波器动态响应与收敛特性的理解。
内容概要:本文系统研究了风光火储多源协同参与电网一次调频与二次自动发电控制(AGC)的联合调控策略,依托Matlab/Simulink平台构建包含风能、光伏、火电及储能系统的多能源协同仿真模型。研究重点在于设计高效协调的控制机制,使各类电源在电网频率发生波动时能够快速响应并协同调节,提升系统频率稳定性与动态响应性能。通过引入构网型控制、虚拟同步机(VSG)、下垂控制等先进控制技术,实现了对一次调频的瞬时功率支撑与二次AGC的精确频率恢复控制,并在电磁暂态层面完成仿真验证,有效复现了高水平学术论文中的核心成果,兼具理论深度与工程实践价值。; 适合人群:电力系统、新能源并网、智能电网控制等领域的研究生、科研人员及从事电力系统仿真与运行控制的工程技术人员,需具备Matlab/Simulink建模能力及电力系统动态分析基础。; 使用场景及目标:① 分析多源电力系统在负荷扰动下的频率响应特性;② 掌握风光火储协同调频的控制逻辑与系统建模方法;③ 复现博士论文或SCI期刊级别的研究成果,支撑科研课题、学位论文撰写与工程项目开发。; 其他说明:该资源提供完整的Matlab代码与Simulink仿真模型,可通过指定公众号或网盘链接获取,建议结合理论学习与仿真实验,深入掌握多源协同控制策略的设计与优化方法。
内容概要:本文提出了一种基于离散平稳小波变换(SWT)域中结合离散余弦变换(DCT)与局部空间频率(LSF)的红外与可见光图像融合方法,并提供了完整的Matlab代码实现。该方法首先对红外和可见光图像进行SWT多尺度分解,克服传统小波变换缺乏平移不变性的问题;随后在高频子带中采用基于DCT系数幅值和LSF的融合规则,有效保留图像边缘、纹理等细节信息;在低频子带中则通过能量加权策略融合整体亮度与结构信息,提升图像对比度;最后利用SWT逆变换重构融合图像。算法在主观视觉效果和客观评价指标(如PSNR、SSIM、MI等)上均表现出优越性能。; 适合人群:具备数字图像处理基础理论知识和Matlab编程能力的研究生、科研人员,以及从事计算机视觉、遥感监测、安防监控、智能驾驶、医学影像分析等相关领域的工程技术人员。; 使用场景及目标:①实现红外图像(热辐射信息突出)与可见光图像(空间分辨率高、色彩丰富)的优势互补,提升复杂环境下的目标检测与识别能力;②应用于军事侦察、夜间导航、火灾监测、自动驾驶夜视系统、工业缺陷检测等多模态图像融合需求场景;③为图像融合领域的学术研究提供可复现的技术方案与基准实验平台。; 阅读建议:建议读者结合提供的Matlab代码深入理解算法实现流程,重点掌握SWT分解层数、DCT分块大小、LSF窗口尺度等关键参数对融合效果的影响,可通过公开数据集(如TNO、RoadScene等)开展对比实验,并借助PSNR、SSIM、互信息(MI)等量化指标评估算法性能。
内容概要:本文围绕新能源发电接入弱电网所引发的宽频带振荡问题展开深入研究,系统探讨了其振荡机理及抑制策略。通过构建Matlab代码与Simulink仿真模型,复现博士论文中的核心技术环节,涵盖系统建模、序阻抗分析、扫频辨识、稳定性判据等关键步骤,重点剖析新能源并网系统在弱电网条件下的动态交互特性与失稳机制。研究内容包括LCL型逆变器的分序阻抗建模、锁相环(PLL)引起的频率耦合效应、正负序阻抗特性及其对系统稳定性的影响,并揭示了宽频带耦合振荡的形成机理。在此基础上,提出针对性的振荡抑制方法,如阻抗重塑、控制参数优化与自适应调控策略。配套提供的完整代码与仿真模型为理论验证、算法迭代与二次开发提供了坚实的技术支撑。; 适合人群:具备电力系统、电力电子或自动化等相关专业背景,熟练掌握Matlab/Simulink仿真工具,从事新能源并网、电力系统稳定性分析、并网逆变器控制等方向研究的研究生、高校科研人员及电力行业工程技术人员。; 使用场景及目标:① 深入理解新能源发电系统在弱电网条件下产生宽频带振荡的物理本质与动态演化过程;② 掌握基于序阻抗的建模方法与扫频分析技术,用于评估并网系统的交互稳定性;③ 利用所提供的Matlab代码和Simulink仿真模型进行精确复现、算法验证、参数敏感性分析,并进一步开展创新性研究与工程应用。; 阅读建议:建议读者结合原始博士论文进行对照学习,按照理论推导、模型搭建、仿真运行、结果分析的流程逐步实践,重点关注系统参数设置、模块化建模逻辑、扫频算法实现细节以及稳定性判据的应用,以全面提升对新能源并网系统稳定性问题的分析与解决能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值