【SQL技术】不同数据库引擎 SQL 优化方案剖析
一、引言
在数据处理和分析的世界里,SQL 是不可或缺的工具。不同的数据库系统,如 MySQL、PostgreSQL(PG)、Doris 和 Hive,在架构和性能特点上存在差异,因此针对它们的 SQL 优化策略也各有不同。这些数据库中常见和不常见 SQL 语句的优化方法,涵盖排序、聚合函数、条件查询、分组等操作,同时还会涉及 Hive 和 Doris 中 UDF 函数的优化。

SQL解析器:

二、MySQL 优化策略
存储引擎介绍
- InnoDB:支持事务、行级锁、外键约束,具有良好的并发性能和数据一致性,是MySQL 5.5及以后版本的默认存储引擎。
- MyISAM:不支持事务和外键约束,具有较高的插入和查询速度,适用于以读为主的应用场景。
- Memory:数据存储在内存中,访问速度极快,但数据在服务器重启时会丢失,适用于临时数据存储。
- Archive:用于存储大量的历史数据,只支持插入和查询操作,不支持更新和删除。
- CSV:以CSV格式存储数据,适用于数据交换和导入导出。
- BlackHole:所有写入的数据都会被丢弃,适用于测试和数据过滤。

SQL执行流程:

(一)条件查询优化
-
索引使用:确保在经常用于
WHERE子句的列上创建索引。例如,如果经常根据user_id进行查询:CREATE INDEX idx_user_id ON users (user_id);
-
避免函数索引:在
WHERE子句中避免对索引列使用函数,因为这会导致索引失效。例如,以下查询会使索引失效:SELECT * FROM users WHERE YEAR(created_at) = 2024;
可以改为:
SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
(二)排序优化
-
覆盖索引:如果排序的列和查询的列可以使用同一个索引,即覆盖索引,能显著提高排序性能。例如:
CREATE INDEX idx_name_age ON users (name, age);
SELECT name, age FROM users ORDER BY name, age; -
控制排序数据量:尽量在
WHERE子句中过滤掉不必要的数据,减少排序的数据量。
(三)聚合函数优化
-
分组索引:在
GROUP BY列上创建索引,有助于提高分组聚合的性能。例如:CREATE INDEX idx_dept_salary ON employees (department_id, salary);
SELECT department_id, AVG(salary) FROM employees GROUP BY department_id;
三、PostgreSQL 优化策略
存储引擎介绍
- Heap存储引擎:是PostgreSQL的默认存储引擎,支持MVCC(多版本并发控制),适用于大多数应用场景。
- B-Tree存储引擎:适用于需要高效的范围查询和排序的场景,如索引和排序操作。
- Hash存储引擎:适用于需要快速查找的场景,如哈希表和索引。
- GiST存储引擎:适用于处理几何数据和全文搜索的场景。
- SP-GiST存储引擎:是GiST的一种变体,适用于处理空间数据的场景。
- GIN存储引擎:适用于处理数组和JSON数据的场景。
- BRIN存储引擎:适用于处理大数据集的场景,如数据仓库和日志分析。
- Bitmap存储引擎:适用于处理位图数据的场景。
- Partial存储引擎:适用于处理部分索引的场景。
- Unique存储引擎:适用于处理唯一约束的场景。

SQL执行流程:

(一)条件查询优化
-
统计信息更新:定期更新表的统计信息,确保查询优化器能够做出更准确的查询计划。使用
ANALYZE命令:ANALYZE users;
-
范围查询优化:对于范围查询,使用
BRIN(块范围索引)可以提高性能。例如:CREATE INDEX idx_created_at ON users USING BRIN (created_at);
(二)排序优化
-
并行排序:PostgreSQL 支持并行排序,可以通过调整
max_parallel_workers_per_gather参数来启用并行排序。SET max_parallel_workers_per_gather = 4;
(三)聚合函数优化
- 聚合索引:与 MySQL 类似,在
GROUP BY列上创建索引可以提高聚合性能。同时,使用GROUPING SETS、ROLLUP和CUBE等高级聚合功能时,要确保数据分布均匀。
四、Doris 优化策略
Doris SQL引擎种类
- Heap存储引擎:是Doris的默认存储引擎,支持MVCC(多版本并发控制),适用于大多数应用场景。
- B-Tree存储引擎:适用于需要高效的范围查询和排序的场景,如索引和排序操作。
- Hash存储引擎:适用于需要快速查找的场景,如哈希表和索引。
- GiST存储引擎:适用于处理几何数据和全文搜索的场景。
- SP-GiST存储引擎:是GiST的一种变体,适用于处理空间数据的场景。
- GIN存储引擎:适用于处理数组和JSON数据的场景。
- BRIN存储引擎:适用于处理大数据集的场景,如数据仓库和日志分析。
- Bitmap存储引擎:适用于处理位图数据的场景。
- Partial存储引擎:适用于处理部分索引的场景。
- Unique存储引擎:适用于处理唯一约束的场景。

SQL执行流程:

(一)条件查询优化
-
分区和分桶:合理使用分区和分桶可以减少数据扫描量。例如,按日期分区,按用户 ID 分桶:
CREATE TABLE sales (
sale_date DATE,
user_id INT,
amount DECIMAL(10, 2)
)
PARTITION BY RANGE(sale_date) (
PARTITION p202401 VALUES LESS THAN (‘2024-02-01’),
…
)
DISTRIBUTED BY HASH(user_id) BUCKETS 32; -
物化视图:对于频繁查询的复杂子查询,可以创建物化视图来提高查询性能。
CREATE MATERIALIZED VIEW mv_sales_summary AS
SELECT sale_date, SUM(amount) FROM sales GROUP BY sale_date;
(二)排序优化
-
预排序:在创建表时指定预排序键,Doris 会按照预排序键对数据进行排序存储,提高排序查询的性能。
CREATE TABLE orders (
order_date DATE,
order_id INT,
amount DECIMAL(10, 2)
)
ORDER BY order_date;
(三)UDF 函数优化
- 减少 UDF 调用次数:尽量将 UDF 函数的逻辑合并到 SQL 语句中,减少 UDF 调用的开销。
- 使用向量化 UDF:Doris 支持向量化 UDF,使用向量化 UDF 可以显著提高计算性能。
五、Hive 优化策略
Hive SQL引擎种类
- MapReduce引擎:这是Hive最初使用的执行引擎,它将SQL查询转换为一系列的MapReduce任务来执行。这种方式在处理大规模数据时非常有效,但由于MapReduce的启动开销较大,对于小数据量或实时性要求高的查询可能效率较低。
- Tez引擎:Tez是一种基于有向无环图(DAG)的执行引擎,它可以将多个MapReduce任务组合成一个更高效的执行计划,减少了任务的启动和调度开销,提高了查询性能。Tez特别适合处理复杂的查询和数据挖掘任务。
- Spark引擎:Spark是一种快速的、通用的大数据处理引擎,它提供了比MapReduce更高效的内存计算能力。Hive可以使用Spark作为执行引擎,通过将SQL查询转换为Spark任务来执行,从而提高查询的执行速度。
- Flink引擎:Flink是一种流处理和批处理统一的计算引擎,它提供了高效的分布式计算能力和低延迟的处理能力。Hive可以使用Flink作为执行引擎,通过将SQL查询转换为Flink任务来执行,从而提高查询的执行速度和实时性。

SQL执行流程:

(一)条件查询优化
-
分区裁剪:在
WHERE子句中使用分区列进行过滤,避免全量数据扫描。例如:SELECT * FROM logs WHERE dt = ‘2024-01-01’;
-
谓词下推:启用谓词下推功能,让 Hive 在数据读取阶段就过滤掉不必要的数据。
SET hive.optimize.ppd=true;
(二)排序优化
-
使用
DISTRIBUTE BY和SORT BY:DISTRIBUTE BY用于将数据分发到不同的 reducer,SORT BY用于在每个 reducer 内部进行排序。例如:SELECT * FROM sales DISTRIBUTE BY user_id SORT BY amount DESC;
(三)聚合函数优化
-
Map 端聚合:启用 Map 端聚合可以减少数据传输量。
SET hive.map.aggr=true;
(四)UDF 函数优化
- 缓存中间结果:如果 UDF 函数的计算结果可以复用,在 UDF 内部实现缓存机制,避免重复计算。
- 使用 Hive 内置函数替代 UDF:优先使用 Hive 内置函数,因为它们经过了优化,性能通常比自定义 UDF 高。
六、SQL调优技巧
(一)慎重使用COUNT(DISTINCT col)
- 问题原因:在各个数据库中,DISTINCT操作会将所有数据保存在内存中以进行去重操作,在数据量较大时,这可能导致内存溢出(OOM)情况的发生。
- 解决方案:
- MySQL、PG:考虑使用GROUP BY和COUNT组合来代替COUNT(DISTINCT col)。例如,如果要统计某列的不同值数量,可以通过
SELECT col, COUNT(*) FROM table GROUP BY col,然后在应用层进行进一步处理得到去重后的数量。 - Doris、Hive:除了GROUP BY替代法,还可以使用ROW_NUMBER() OVER(PARTITION BY col)函数。例如在Hive中,
SELECT COUNT(*) FROM (SELECT col, ROW_NUMBER() OVER(PARTITION BY col ORDER BY col) AS row_num FROM table) WHERE row_num = 1。这种方式通过窗口函数为每个不同值分配一个序号,然后只计算序号为1的记录数量。
- MySQL、PG:考虑使用GROUP BY和COUNT组合来代替COUNT(DISTINCT col)。例如,如果要统计某列的不同值数量,可以通过
(二)小文件问题
- 问题原因:小文件会在数据库存储和查询过程中占用过多内存,因为每个小文件都需要一定的元数据管理开销,从而导致查询效率下降。
- 解决方案:
- Hive:
- 控制小文件产生数量,可以通过调整写入数据时的参数来实现。例如,在使用INSERT语句写入数据时,可以调整
mapreduce.output.fileoutputformat.split.maxsize和mapreduce.output.fileoutputformat.split.minsize参数,使数据写入更大的文件块中。 - 使用SequenceFile格式存储数据,这种格式对于小文件处理有较好的优化效果。例如,在创建表时指定
STORED AS SEQUENCEFILE。 - 减少Reducer数量,避免动态分区生成过多小文件。可以通过设置
hive.exec.reducers.max参数来限制Reducer的最大数量。
- 控制小文件产生数量,可以通过调整写入数据时的参数来实现。例如,在使用INSERT语句写入数据时,可以调整
- Doris:在数据导入阶段,可以通过调整导入参数来控制小文件的生成。例如,设置合适的批处理大小,确保每次导入的数据量足够大,避免生成过多小文件。
- Hive:
(三)慎重使用SELECT *
- 问题原因:查询所有字段意味着数据库需要处理可能存在的无效数据,这无疑是对资源的浪费,特别是在大表查询时,会增加不必要的I/O开销。
- 解决方案:无论是MySQL、PG还是Doris、Hive(*一般限制数量,不走mr会稍快),都应该指定所需字段名进行查询。例如,将
SELECT * FROM table改为SELECT col1, col2, col3 FROM table,只获取实际需要的列数据。
(四)不要在表关联后加WHERE条件
- 解决方案:
- MySQL、PG、Doris、Hive通用:采用谓词下推技术,将过滤条件尽可能放在表连接之前,提前过滤数据,减少中间结果集的数据量,从而减少数据传输和处理的开销。例如,将
SELECT * FROM table1 JOIN table2 ON table1.id = table2.id WHERE table1.col > 10改为SELECT * FROM (SELECT * FROM table1 WHERE table1.col > 10) AS sub_table1 JOIN table2 ON sub_table1.id = table2.id。
- MySQL、PG、Doris、Hive通用:采用谓词下推技术,将过滤条件尽可能放在表连接之前,提前过滤数据,减少中间结果集的数据量,从而减少数据传输和处理的开销。例如,将
(五)处理空值数据
- 问题原因:空值在数据库处理过程中可能会导致一些问题,如在MapReduce过程(特别是在Hive等基于MapReduce架构的数据库中)中的内存不足。
- 解决方案:
- MySQL、PG:在查询时过滤掉NULL数据,可以使用
IS NOT NULL或IS NULL条件进行筛选。例如,SELECT col FROM table WHERE col IS NOT NULL。 - Doris、Hive:除了过滤空值,还可以为空值赋随机数(在某些特定场景下,如避免数据倾斜)。在Hive中,可以使用
COALESCE函数来处理空值,例如SELECT COALESCE(col, 0) FROM table,这里如果col列为空,则将其替换为0。
- MySQL、PG:在查询时过滤掉NULL数据,可以使用
(六)设置并行执行任务数
- 解决方案:
- Hive:通过设置
hive.exec.parallel为true开启并发执行,增加并行度。这在有多个子查询或者多个任务可以同时进行的情况下非常有效,可以提高整体查询效率。
- Hive:通过设置
(七)设置合理的Reducer数量
- 问题原因:过多的Reducer启动会消耗大量的时间和资源,因为每个Reducer都需要初始化和分配资源。
- 解决方案:
- Hive:根据输入数据量和每个Reducer处理的数据量设置合理的
七、总结
不同的数据库系统有其独特的架构和性能特点,因此 SQL 优化策略也需要因地制宜。在实际应用中,需要根据具体的业务需求和数据特点,选择合适的优化方法。同时,定期监控数据库的性能指标,不断调整优化策略,才能确保数据库系统始终保持高效稳定的运行。希望本文介绍的优化方案能为你在数据库性能优化方面提供一些有益的参考。
相关文章:
【SQL技术】不同数据库引擎 SQL 优化方案剖析
一、引言 在数据处理和分析的世界里,SQL 是不可或缺的工具。不同的数据库系统,如 MySQL、PostgreSQL(PG)、Doris 和 Hive,在架构和性能特点上存在差异,因此针对它们的 SQL 优化策略也各有不同。这些数据库…...
RabbitMQ系列(二)基本概念之Publisher
在 RabbitMQ 中,Publisher(发布者) 是负责向 RabbitMQ 服务器发送消息的客户端角色,通常被称为“生产者”。以下是其核心功能与工作机制的详细解析: 一、核心定义与作用 消息发送者 Publisher 将消息发送到 RabbitMQ 的…...
OAK相机的抗震性测试
在工业环境中,双目视觉相机必须具备与工作环境同等的坚固性。鉴于部分客户会将我们的相机应用于恶劣环境(例如安装在重型机械上),我们依据EN 60068-2-6:2008标准对相机进行了振动耐受性测试。 测试涉及的相机型号包括:…...
2025最新Nginx高频面试题
2025最新Nginx高频面试题 摘要:本文整理了2025年企业高频Nginx面试题,覆盖核心原理、配置优化、安全防护及云原生场景实战,助你轻松应对技术面试! 核心原理篇 1. Nginx的Master-Worker架构优势是什么? 答案…...
【Kubernetes】API server 限流 之 maxinflight.go
这个文件实现了一个基于信号量(Channel)的简单限流器。 基础知识 总共有四种channel 带缓冲的channel nonMutatingChan、mutatingChan 都是带缓冲的channel ,这类channel 的特点是: 这允许最多 mutatingLimit /nonMutatingLimit 个请求同时获取令牌并执…...
推荐算法工程师的技术图谱和学习路径
推荐算法工程师的技术图谱和学习路径可以从多个维度进行概述,可以总结如下: 一、技术图谱 推荐算法工程师需要掌握的技术栈主要分为以下几个方面: 数学基础: 微积分、线性代数、概率论与统计学是推荐算法的基础,用于理解模型的数学原理和优化算法。高等数学、最优化理论…...
Milvus高性能向量数据库与大模型结合
Milvus | 高性能向量数据库,为规模而构建Milvus 是一个为 GenAI 应用构建的开源向量数据库。使用 pip 安装,执行高速搜索,并扩展到数十亿个向量。https://milvus.io/zh Milvus 是什么? Milvus 是一种高性能、高扩展性的向量数据…...
轮式机器人在复杂地形中如何选择合适的全局路径规划算法?
已思考完成 收起 嗯,用户问的是轮式机器人在复杂地形中如何选择合适的全局路径规划算法。首先,我需要理解复杂地形可能带来的挑战,比如崎岖的路面、动态障碍物、非结构化环境等等。轮式机器人在这里的运动控制需要考虑地形通过性、稳定性&…...
Metal学习笔记九:光照基础
光和阴影是使场景流行的重要要求。通过一些着色器艺术,您可以突出重要的对象、描述天气和一天中的时间并设置场景的气氛。即使您的场景由卡通对象组成,如果您没有正确地照亮它们,场景也会变得平淡无奇。 最简单的光照方法之一是 Phong 反射模…...
【字符串】最长公共前缀 最长回文子串
文章目录 14. 最长公共前缀解题思路:模拟5. 最长回文子串解题思路一:动态规划解题思路二:中心扩散法 14. 最长公共前缀 14. 最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符…...
Linux提权之详细总结版(完结)
这里是我写了折磨多提权的指令的总结 我这里毫无保留分享给大家哦 首先神魔是提权 我们完整的渗透测试的流程是(个人总结的) 首先提升权限是我们拿到webshell之后的事情,如何拿到webshell,怎末才能拿到webshell,朋友们等我更新,持续更新中,下一篇更新的是windows提权 好了 废…...
week 3 - More on Collections - Lecture 3
一、Motivation 1. Java支持哪种类型的一维数据结构? Java中用于在单一维度中存储数据的数据结构,如arrays or ArrayLists. 2. 如何在Java下创建一维数据结构?(1-dimensional data structure) 定义和初始化这些一…...
Pwntools 的详细介绍、安装指南、配置说明
Pwntools:Python 开源安全工具箱 一、Pwntools 简介 Pwntools 是一个由 Security researcher 开发的 高效 Python 工具库,专为密码学研究、漏洞利用、协议分析和逆向工程设计。它集成了数百个底层工具的功能,提供统一的 Python API 接口&am…...
PLC(电力载波通信)网络机制介绍
1. 概述 1.1 什么是PLC 电力载波通讯即PLC,是英文Power line Carrier的简称。 电力载波是电力系统特有的通信方式,电力载波通讯是指利用现有电力线,通过载波方式将模拟或数字信号进行高速传输的技术。最大特点是不需要重新架设网络…...
Qt监控系统远程回放/录像文件远程下载/录像文件打上水印/批量多线程极速下载
一、前言说明 在做这个功能的时候,着实费了点心思,好在之前做ffmpeg加密解密的时候,已经打通了极速加密保存文件,主要就是之前的类中新增了进度提示信号,比如当前已经处理到哪个position位置,发个信号出来…...
自学微信小程序的第八天
DAY8 1、使用动画API即可完成动画效果的制作,先通过wx.createAnimation()方法获取Animation实例,然后调用Animation实例的方法实现动画效果。 表40:wx.createAnimation()方法的常用选项 选项 类型 说明 duration number 动画持续时间,单位为毫秒,默认值为400毫秒 timing…...
【java】@Transactional导致@DS注解切换数据源失效
最近业务中出现了多商户多租户的逻辑,所以需要分库,项目框架使用了mybatisplus所以我们自然而然的选择了同是baomidou开发的dynamic.datasource来实现多数据源的切换。在使用初期程序运行都很好,但之后发现在调用com.baomidou.mybatisplus.ex…...
003 SpringBoot集成Kafka操作
4.SpringBoot集成Kafka 文章目录 4.SpringBoot集成Kafka1.入门示例2.yml完整配置3.关键配置注释说明1. 生产者优化参数2. 消费者可靠性配置3. 监听器高级特性4. 安全认证配置 4.配置验证方法5.不同场景配置模板场景1:高吞吐日志收集场景2:金融级事务消息…...
Android SystemUI开发(一)
frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUI.java frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java 关键文件 SystemUI 关键服务 简介 Dependency.class:处理系统依赖关系,提供资源或服…...
C#贪心算法
贪心算法:生活与代码中的 “最优选择大师” 在生活里,我们常常面临各种选择,都希望能做出最有利的决策。比如在超市大促销时,面对琳琅满目的商品,你总想用有限的预算买到价值最高的东西。贪心算法,就像是一…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...

