大数据SQL调优专题——调优切入
引入
我们都知道大数据的SQL优化,并非一蹴而就的简单任务,而是一个涉及多个环节的复杂过程。从需求提出到最终交付,任何一个环节的微小偏差都可能影响最终成果。
虽然我们的专栏名字叫大数据SQL调优,但是实际调优并不是简单对SQL优化,而是一个涉及多个环节的复杂过程。实际上从需求接入到最终交付,任何一个环节的都可能影响最终成果。而调优的本质并非对任务进行大规模重构,而是通过各种监控工具,排查梳理出瓶颈点在哪,并深入了解其成因以及对应需求背景,才能以最小的代价进行修改或调整。
正所谓“工欲善其事,必先利其器”。可以看到,在优化过程中,无论是发现问题的根源,还是寻找最优的解决方案,合适的工具、流程和思路都至关重要。
以下将我们从数据研发日常工作的角度,来简要介绍调优的几个关键切入点。
梳理真实需求
梳理真实需求的前提是理解业务,这是数仓调优的根基,只有深入理解企业的业务流程、业务模式和业务目标,才能明确业务部门的真实需求是什么。
数据最终的目的是赋能业务、驱动业务,以此为前提,我们就需要用数据准确的展示业务现状,为业务和分析提供数据支持。而要做到以上各点,必须了解业务痛点,理解业务流程,分析出业务场景中可能存在的问题,以及判断各业务方的诉求是否合理、其底层的真实需求是否和表述需求一致等。
所谓理解业务,从高层视角而言,指的是了解行业的基本模式、运作的流程、供需之间如何流转,本质就是找到不同主体之间的业务流转关系。从底层视角看的话,则是需要清楚地知道不同表中具体字段的含义,以及相关的表有哪些,他们之间的数据关联关系是什么等。数据是客观存在的,而需求才是基于业务的,很多不必要的资源开销、冗长的沟通、费尽周折的查询优化,其实在源头阶段是可以避免的。只有了解业务,我们才有能力去甄别需求是否合理,其背后隐藏的真实需求是怎样的。
所以对于一个合格的数据研发来说,在开发工作开始之前,就需要明确以下几点:
1.明确需求
不要接到需求就只顾埋头实现,在正常开发流程的需求澄清会上,不要闷头光想着怎么实现需求,要学会多问问需求提供方或业务方究竟要做什么事情,想达到什么目的,并与业务提供需求文档和设计文档核对复验,最后要记得询问期望的结果、反馈和交付时间节点。这样的过程才谈得上是一个闭环,而不是埋头苦干一通,最后发现需要返工,或者被业务人员全盘否定。
2.应对需求的正确思路
比如老板发现一个城市的司机接单指标下跌了,不要急着去查口径,找数据问题,或者直接拿相关数据去做多维交叉分析,拿历史数据波动,看同环比等。因为当数据指标出现异常时,急于从数据本身寻找答案,最后的结果可能也只是“自证清白”,并没能找到问题根因,我们应该深入探究背后的业务逻辑。比如前面提的指标下跌的原因,可能是因为多方面的,比如高峰期刚过,或者对应城市天气问题等,基于业务理解,去找出这些真正影响指标的答案,才是正确的思路。
3.技术栈应用储备
大数据处理的技术栈种类繁多,它们都有各自的适用场景和局限性,也就是所谓的术业有专攻,目前也没有出现一个能解决所有问题的银弹。而需求方不了解也不关心底层的具体实现和局限性,所有数据研发作为其中承上启下的重要节点,就需要有相关大数据处理技术广度和深度的知识储备,才能帮助或引导模糊的需求具象化、合理化。
收集相关信息
执行计划
执行计划(Execution Plan,也叫查询计划或者解释计划)是查询优化的重要依据。我们可以通过EXPLAIN命令查看优化器针对指定SQL生成的逻辑执行计划。如果要分析某条SQL的性能问题,通常需要先查看SQL的执行计划,排查每一步SQL执行是否存在问题。
通过查看执行计划,我们可以得到表的读取顺序、表之间的引用、表连接的顺序、表连接的方式以及实际读取文件的位置等信息。尽管不同的框架实现会导致执行计划有所差异,但目的都是相同的。通过使用EXPLAIN关键字,可以模拟优化器执行SQL查询语句,从而理解引擎是如何处理SQL语句的。这样我们就能够分析提交的查询语句可能存在的性能瓶颈。
例如通过EXPLAIN命令解析HQL执行计划去定位以下可能的瓶颈:
- JOIN顺序优化:优先过滤小表以减少Shuffle数据量。
- 数据倾斜处理:识别Hash Join中的倾斜Key。
- 资源分配:根据Stage耗时调整Map/Reduce并发度。
统计信息
统计信息对于查询优化也是至关重要。前面我们有提到CBO,其本质就是依赖统计信息来选择最优的执行计划。
统计数据分为表级别的统计数据(如行数、大小等)和列级别的统计数据(如最大、最小值等)两类。表或字段的统计信息有助于我们更深入地了解表中数据的分布情况,从而规避潜在的问题。例如,单表数据量过大,就可以考虑将表转换为分区或分桶表;如果字段唯一值数量较少,在去重时就需要注意潜在的数据倾斜问题。
在Hive中,除了保存元数据库表之外,也会保存这两类统计信息,包括表或分区的大小、行数等信息。Hive会尽可能地在每次变更数据时更新统计信息,以确保其准确性。统计信息的主要用途在于辅助CBO制定更高效的查询计划,从而选择成本最低的执行路径。此外,当启用配置hive.compute.query.using.stats(默认关闭)时,对于COUNT(1)、MIN、MAX等聚合查询,引擎会直接利用统计信息快速返回结果,而无须进行实际的文件扫描操作。
在Spark中,尽管我们也使用Hive Metastore来管理库表的元数据,并且Spark能够兼容Hive表的读写操作,但Spark对于Hive统计信息的利用与Hive本身存在差异。Spark定义了一套自己的统计指标和规则体系,这也意味着由Spark引擎写入的统计信息不会被其他引擎所利用和共享。此外,Spark在处理统计信息的写入时比Hive更为谨慎。在默认配置下,Spark并不会在数据写入时自动更新统计信息,这导致Hive Metastore中的统计数据可能无法准确地反映表的当前状态。Spark主要通过org.apache.spark.sql.execution.command.CommandUtils类中的update-TableStats方法来更新表级别的统计信息,感兴趣小伙伴可以深入看看其实现原理。其核心就是,如果处理的是非分区表,它会递归遍历表存储路径下的所有文件,并对每个文件的大小进行求和。如果处理的是分区表,它会默认使用listPartitions方法获取所有分区的路径,然后并行计算每个分区的大小。最终,该方法只会更新表级别的spark.sql.statistics.totalSize属性。对于字段级别的统计信息,只能通过执行ANALYZE TABLE...COMPUTE STATISTICS FOR COLUMNS...命令来进行计算和写入。这个语句会记录某个字段在整张表中的最小值、最大值等统计信息,但并不会在分区维度上进行统计。字段级别的统计信息包括平均长度(avgLen)、唯一值的数量(distinctCount)、最小值(min)、最大值(max)、最大长度(maxLen)、空值数量(nullCount)以及直方图(histogram)。前几个统计值的含义相对直观,而直方图(histogram)则较为特殊,需要在开启spark.sql.statistics.histogram.enabled后,再运行ANALYZE命令才能生成。直方图会将字段值的分布切分成n个百分比位(n=spark.sql.statistics.histogram.numBins,默认值为254),每一段内部会统计最小值、最大值和唯一值的数量。直方图可以对高频查询字段建立统计快照,加速范围查询响应。
执行日志
执行日志记录了数据库的各种操作和事件,包括查询执行时间、错误信息等。通过分析执行日志,可以发现频繁执行的查询、耗时较长的查询以及出现错误的查询。针对这些问题查询,可以进行针对性的优化,提高数据仓库的整体性能。
而且日志有助于保护开发人员和用户免受应用程序和系统中大规模故障和问题的影响。由于我们无法24h实时监控查询任务,因此当任务出现错误并失败时,我们需要确定原因,此时日志的重要性就显现出来了。日志对于程序执行的监控和问题定位至关重要。在系统设计、开发和实现的过程中,必须关注输出的日志,这对于查询任务的异常分析至关重要。
通常我们会分析日志中的关键指标:
- Shuffle溢出:监控磁盘溢出次数。
- GC耗时:通过日志中的GC暂停时间判断内存配置合理性,优化堆内存分配。
分析工具
Dr.Elephant
Dr.Elephant 是一个用于分析大数据作业性能的工具。它可以帮助用户识别性能瓶颈、优化资源使用和提高作业效率。通过 Dr.Elephant,可以收集和分析作业的执行时间、资源消耗等信息,为性能调优提供数据支持。将作业的执行日志上传到Dr.Elephant,Dr.Elephant会生成详细的分析报告,指出作业的性能问题,并提供优化建议。
Dr.Elephant于2016年4月由LinkedIn开源,是一个支持Hadoop和Spark的性能监控和调优工具。Dr.Elephant能自动收集所有指标,进行数据分析,并以简单易用的方式进行呈现。与此同时,Dr.Elephant也支持对Hadoop和Spark任务进行可插拔式、配置化以及基于规则的启发式Job性能分析,并且能根据分析结果给出合适的建议,来指导开发人员进行调优以使任务有更高效率。
火焰图
火焰图是一种可视化工具,可以帮助用户直观地了解程序的执行流程和性能瓶颈。在大数据数仓调优中,火焰图可以用于分析查询执行过程中的 CPU 使用率、内存分配等情况,帮助找到性能瓶颈所在。
通常的做法是,使用性能分析工具(如perf)收集程序的执行数据,生成火焰图,通过分析火焰图找出执行时间较长的函数或代码段,进行优化。
火焰图(Flame Graph)是由Linux性能优化大师Brendan Gregg发明的。和其他的性能分析方法不同,火焰图以一个全局视野来看待时间分布,它由下向上地列出所有可能导致性能瓶颈的调用栈。
Prometheus
Prometheus 是一个开源的监控系统,广泛应用于云计算和容器化环境中。在大数据数仓中,Prometheus 可以用于收集和监控各种指标,如 CPU 使用率、内存使用率、网络流量等。通过监控这些指标,可以及时发现性能问题,并采取相应的措施进行优化。
通过部署Prometheus服务器和相关的Exporter,收集系统的监控数据,使用Prometheus的查询语言(PromQL)查询和分析数据,设置报警规则,来及时发现和处理性能问题。
Prometheus是由SoundCloud开源的监控告警解决方案,2012年开始编写代码,2015年开源,发展速度迅猛,社区活跃,并且被广泛应用于各大公司中,Prometheus通过领先的开源监控解决方案为用户的指标和告警提供了强大的技术支持。
等价重写思想
在数据库领域,等价重写思想乃是一种极具价值的优化技术。其旨在对查询表达式进行优化改写,使得改写后的表达式与原始查询等价,同时在执行效率、性能或其他方面展现出更为显著的优势。等价重写的核心目标在于通过巧妙地重新组织查询结构,充分利用数据库系统的优化策略,从而大幅降低查询的计算成本。
尽管大数据引擎在物理实现方面与关系型数据库存在着较大差异,然而,在设计思想以及实际应用过程中,这些差异并非十分突出。一方面,我们能够借助引擎自身所支持的优化功能,例如基于关系代数以及利用等价变换的规则。另一方面,我们可以通过对查询语句进行改写,进而实现优化查询语句的目的。
等价重写思想是一种基于关系代数的查询优化技术,其核心在于通过语义等价性转换生成执行效率更高的新查询表达式。
该技术遵循两大原则:
- 数学等价性:利用关系代数的结合律、交换律、分配律等规则(如投影下推、选择分解、外连接转半连接),保证重写前后的查询结果完全一致;
- 执行高效性:通过重构查询结构降低计算复杂度(如减少全表扫描)、提升索引利用率(如将
LIKE 'abc%'改写为范围查询)、优化分布式数据分片策略(如减少Shuffle数据量)。
典型技术场景:
- 子查询提升:将IN子查询转化为SEMI JOIN,避免嵌套循环执行(如SELECT * FROM film WHERE id IN (SELECT film_id FROM film_actor) → SELECT f.* FROM film f JOIN film_actor fa ON f.id=fa.film_id);
- 谓词下推:提前过滤无效数据(如将WHERE a>10 AND b<5分解为两阶段过滤);
- 常量折叠:预计算静态表达式(如WHERE a=1+1重写为WHERE a=2)。
大数据的演化区别:
| 维度 | 传统关系型数据库 | 大数据引擎 |
|---|---|---|
| 优化模式 | 自动优化为主(如CBO优化器) | 手动干预为主(需人工规避Shuffle瓶颈) |
| 核心挑战 | 复杂SQL的索引选择与执行计划稳定性 | 分布式数据倾斜与网络传输成本控制 |
| 共性技术 | 谓词下推、常量折叠、连接顺序优化 | 分区剪枝、动态资源分配、小文件合并 |
相关文章:
大数据SQL调优专题——调优切入
引入 我们都知道大数据的SQL优化,并非一蹴而就的简单任务,而是一个涉及多个环节的复杂过程。从需求提出到最终交付,任何一个环节的微小偏差都可能影响最终成果。 虽然我们的专栏名字叫大数据SQL调优,但是实际调优并不是简单对SQ…...
Idea java项目结构介绍
一般来说,一个典型的 IntelliJ IDEA Java 项目具有特定的结构,以下是对其主要部分的介绍: 项目根目录 项目的最顶层目录,包含了整个项目的所有文件和文件夹,通常以项目名称命名。在这个目录下可以找到.idea文件夹、.g…...
adb的安装
1、概念 (1)adb(android debug bridge)安卓调试桥,用于完成电脑和手机之间的通信控制。 (2)xcode来完成对于ios设备的操控,前提是有个mac电脑。 2、adb的安装 (1&…...
React + TypeScript 数据模型驱动数据字典生成示例
React TypeScript 数据模型驱动数据字典生成示例 引言:数据字典的工程价值 在现代化全栈开发中,数据字典作为业务实体与数据存储的映射桥梁,直接影响系统可维护性与团队协作效率。传统手动维护字典的方式存在同步成本高和版本管理混乱两大痛…...
Nginx 平滑升级/回滚
平滑升级和回滚的前提条件是 nginx 已经安装好,源码安装 nginx 可参考上一篇文章。在上一篇文章的基础上,nginx 已安装好且已启动,目前是 1.24 版本。 一、平滑升级 Nginx 的平滑升级(热升级)是一种 不中断服务 即可更…...
强化学习演进:GRPO 从何而来
强化学习(Reinforcement Learning, RL)是机器学习的一个分支,其核心是让智能体(Agent)通过与环境(Environment)的交互,学习如何采取最优行动(Action)以最大化…...
Uniapp 小程序复制、粘贴功能实现
在开发 Uniapp 小程序的过程中,复制和粘贴功能是非常实用且常见的交互需求。今天,我就来和大家详细分享如何在 Uniapp 中实现这两个功能。 复制功能:uni.setClipboardData方法 goResult() {uni.setClipboardData({data: this.copyContent, /…...
AOP进阶-02.通知顺序
一.通知顺序 当有多个切面类中的切入点表达式一样时,这些切面类的执行顺序是怎样的呢?如图我们将定义两个切面类,一个MyAspect2,一个MyAspect3,一个MyAspect4。执行后我们发现, 对于目标方法前的通知方法&…...
Node.js 中 fs 模块的高级用法
目录 1. 流式文件处理 示例:大文件复制 2. 文件监控 示例:使用 fs.watch 监控文件变化 3. 异步递归操作 示例:异步递归遍历目录 4. 文件权限管理 示例:修改文件权限 5. 原子操作 示例:原子重命名文件 在 Nod…...
深入探讨K8s资源管理和性能优化
#作者:曹付江 文章目录 前言:1.监控 Kubernetes 集群的资源利用率1.1 Prometheus1.2 Kubernetes 度量服务器1.3 Grafana1.4 自定义指标 2. 识别资源瓶颈2.1. 监控工具2.2. 性能剖析2.3 Kubernetes 事件和日志2.4. 群集自动扩展2.5. 负载测试…...
Buildroot 添加自定义模块-内置文件到文件系统
目录 概述实现步骤1. 创建包目录和文件结构2. 配置 Config.in3. 定义 cp_bin_files.mk4. 添加源文件install.shmy.conf 5. 配置与编译 概述 Buildroot 是一个高度可定制和模块化的嵌入式 Linux 构建系统,适用于从简单到复杂的各种嵌入式项目. buildroot的源码中bui…...
对话式AI引擎:DeepSeek技术引领多模态交互新篇章
摘要 DeepSeek技术公司推出了一项创新服务——“对话式AI引擎”,仅需两行代码即可激活任意大型AI模型的语音对话功能。这项技术使得文本型AI模型迅速转变为具备实时语音对话能力的多模态交互模型,解决了大型AI模型在语音交互方面的不足,为AI行…...
形式化数学编程在AI医疗中的探索路径分析
一、引言 1.1 研究背景与意义 在数字化时代,形式化数学编程和 AI 形式化医疗作为前沿领域,正逐渐改变着我们的生活和医疗模式。形式化数学编程是一种运用数学逻辑和严格的形式化语言来描述和验证程序的技术,它通过数学的精确性和逻辑性,确保程序的正确性和可靠性。在软件…...
HTML——前端基础1
目录 前端概述 前端能做的事情编辑 两步完成一个网页程序 前端工具的选择与安装 HTML HTML5介绍 HTML5的DOCTYPE声明 HTML基本骨架 文字标签 标题之标签 标签之段落、换行、水平线 标签之图片 标签之超文本链接 标签之文本 列表标签之有序列表 列表标签之无序…...
Blueprint —— Events
目录 一,Event Level Reset 二,Event Actor Begin Overlap 三,Event Actor End Overlap 四,Event Hit 五,Event Any Damage 六,Event Point Damage 七,Event Radial Damage 八ÿ…...
Java一揽子集合整理
Java 集合框架 List ArrayList,底层Object数组,相关方法add,remove Vector,底层Object数组,线程安全,使用 synchronized 关键字进行同步处理 Stack,继承自Vector,是一个后进先出的…...
第二十四:5.2【搭建 pinia 环境】axios 异步调用数据
第一步安装:npm install pinia 第二步:操作src/main.ts 改变里面的值的信息: <div class"count"><h2>当前求和为:{{ sum }}</h2><select v-model.number"n"> // .number 这里是…...
dubbo转http方式调用
业务背景:在当前项目下,所有前端请求均通过外层网关转发到后端这边的dubbo服务,现计划去掉网关层,由前端直接http调用后端dubbo。 解决方案:在前端调用方式不变的前提下,后端服务新建controller层…...
HybridCLR+Adressable+Springboot热更
本文章会手把手教大家如何搭建HybridCLRAdressableSpringboot热更。 创作不易,动动发财的小手点个赞。 安装华佗 首先我们按照官网的快速上手指南搭建一个简易的项目: 快速上手 | HybridCLR 注意在热更的代码里添加程序集。把用到的工具放到程序集里…...
金融行业专题|某基金公司基于超融合信创平台支持人大金仓数据库的性能评测
随着“自主可控”在 IT 基础设施领域不断深化,数据库的国产化替代也被很多金融机构提上日程。为了保证性能,大部分国产数据库都基于信创架构的裸金属服务器部署。在国产虚拟化/超融合平台上,国产数据库性能表现如何?尤其是搭配信创…...
父组件用的是原生监听,子组件用的是onClick,子组件添加了stopPropagation还是没有阻止传播
父组件用事件监听,子组件用onClick,即使子组件加了stopPropagation还是没有阻止冒泡。父组件可能使用原生的addEventListener来绑定事件,而子组件用的是React的onClick事件。这时候,虽然子组件调用了e.stopPropagation()ÿ…...
【问题解决方案】随笔 - vscode里面出现双环境解决方案
1.问题重述 (.venv) (base) 2.解决方案 看是conda还是venv环境,先给退出了 1.conda 比如Anaconda 的 (base) 环境,使用 conda deactivate2.venv deactivate然后重新激活环境即可 END...
什么是 Java 中的线程安全?
回答 Java 中的线程安全(Thread Safety)指的是在多线程环境下,当多个线程同时访问和操作共享资源(如对象、变量、数据结构等)时,能够保证程序的正确性,不会出现数据不一致、竞争条件࿰…...
【2025全网最新最全】前端Vue3框架的搭建及工程目录详解
文章目录 安装软件Node.js搭建Vue工程创建Vue工程精简Vue项目文件 Vue工程目录的解读网页标题的设置设置全局样式路由配置 安装软件Node.js 下载地址:https://nodejs.org/zh-cn/ 安装完成后,打开cmd,查看环境是否准备好 node -v npm -vnpm使用之前一定…...
大白话JavaScript闭包在实际项目中有哪些应用场景?
大白话JavaScript闭包在实际项目中有哪些应用场景? 闭包是指有权访问另一个函数作用域中的变量的函数。在实际项目中,闭包有很多应用场景,以下是一些常见的例子: 数据封装和隐私保护 场景:在开发中,有时…...
R 语言科研绘图第 27 期 --- 密度图-分组
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
QT各种版本下载安装
参考链接: 【Qt】超详细!Qt4.8.6和VS2010的配置及使用 由于QT官网一般现在进不去,所以下载一些QT版本只能通过镜像或者以前下载存储的安装包来进行,现在推荐两种方法 从参考链接中搬过来: 方案一:国内镜…...
信息系统的安全防护
文章目录 引言**1. 物理安全****2. 网络安全****3. 数据安全****4. 身份认证与访问控制****5. 应用安全****6. 日志与监控****7. 人员与管理制度****8. 其他安全措施****9. 安全防护框架**引言 从技术、管理和人员三个方面综合考虑,构建多层次、多维度的安全防护体系。 信息…...
TCPDF 任意文件读取漏洞:隐藏在 PDF 生成背后的危险
在网络安全的世界里,漏洞就像隐藏在黑暗中的“定时炸弹”,稍有不慎就会引发灾难性的后果。今天,我们要聊的是一个与 PDF 生成相关的漏洞——TCPDF 任意文件读取漏洞。这个漏洞可能让攻击者轻松读取服务器上的敏感文件,甚至获取整个…...
如何解决svn st中出现!(冲突)的问题
在 SVN(Subversion)中,svn status 命令用于查看工作副本的状态。当你看到 ! 符号时,通常表示文件或目录在工作副本中丢失(missing)。以下是解决这个问题的步骤: 1. 理解 ! 的含义 ! 表示该文件…...
