【SQL技术】不同数据库引擎 SQL 优化方案剖析

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介: 不同数据库系统(MySQL、PostgreSQL、Doris、Hive)的SQL优化策略。存储引擎特点、SQL执行流程及常见操作(如条件查询、排序、聚合函数)的优化方法。针对各数据库,索引使用、分区裁剪、谓词下推等技术,并提供了具体的SQL示例。通用的SQL调优技巧,如避免使用`COUNT(DISTINCT)`、减少小文件问题、慎重使用`SELECT *`等。通过合理选择和应用这些优化策略,可以显著提升数据库查询性能和系统稳定性。

image.png

一、引言

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

二、MySQL 优化策略

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

(一)条件查询优化

索引使用:确保在经常用于 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存储引擎:适用于处理唯一约束的场景。
image.png
SQL执行流程:
image.png

(一)条件查询优化

统计信息更新:定期更新表的统计信息,确保查询优化器能够做出更准确的查询计划。使用 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存储引擎:适用于处理唯一约束的场景。
image.png
SQL执行流程:
image.png

(一)条件查询优化

分区和分桶:合理使用分区和分桶可以减少数据扫描量。例如,按日期分区,按用户 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 ASSELECT 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任务来执行,从而提高查询的执行速度和实时性。
image.png
SQL执行流程:
image.png

(一)条件查询优化

分区裁剪:在 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的记录数量。

(二)小文件问题

问题原因:小文件会在数据库存储和查询过程中占用过多内存,因为每个小文件都需要一定的元数据管理开销,从而导致查询效率下降。
解决方案:控制小文件产生数量,可以通过调整写入数据时的参数来实现。例如,在使用INSERT语句写入数据时,可以调整js mapreduce.output.fileoutputformat.split.maxsize和mapreduce.output.fileoutputformat.split.minsize 参
数,使数据写入更大的文件块中。
使用SequenceFile格式存储数据,这种格式对于小文件处理有较好的优化效果。例如,在创建表时指定STORED AS SEQUENCEFILE。
减少Reducer数量,避免动态分区生成过多小文件。可以通过设置hive.exec.reducers.max参数来限制Reducer的最大数量。
Hive:Doris:在数据导入阶段,可以通过调整导入参数来控制小文件的生成。例如,设置合适的批处理大小,确保每次导入的数据量足够大,避免生成过多小文件。

(三)慎重使用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。

(五)处理空值数据

问题原因:空值在数据库处理过程中可能会导致一些问题,如在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。

(六)设置并行执行任务数

解决方案:Hive:通过设置hive.exec.parallel为true开启并发执行,增加并行度。这在有多个子查询或者多个任务可以同时进行的情况下非常有效,可以提高整体查询效率。

(七)设置合理的Reducer数量

问题原因:过多的Reducer启动会消耗大量的时间和资源,因为每个Reducer都需要初始化和分配资源。
解决方案:Hive:根据输入数据量和每个Reducer处理的数据量设置合理的

七、总结

不同的数据库系统有其独特的架构和性能特点,因此 SQL 优化策略也需要因地制宜。在实际应用中,需要根据具体的业务需求和数据特点,选择合适的优化方法。同时,定期监控数据库的性能指标,不断调整优化策略,才能确保数据库系统始终保持高效稳定的运行。希望本文介绍的优化方案能为你在数据库性能优化方面提供一些有益的参考。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
19天前
|
SQL Java 数据库连接
【潜意识Java】MyBatis中的动态SQL灵活、高效的数据库查询以及深度总结
本文详细介绍了MyBatis中的动态SQL功能,涵盖其背景、应用场景及实现方式。
70 6
|
24天前
|
存储 缓存 NoSQL
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
|
2月前
|
SQL Oracle 数据库
使用访问指导(SQL Access Advisor)优化数据库业务负载
本文介绍了Oracle的SQL访问指导(SQL Access Advisor)的应用场景及其使用方法。访问指导通过分析给定的工作负载,提供索引、物化视图和分区等方面的优化建议,帮助DBA提升数据库性能。具体步骤包括创建访问指导任务、创建工作负载、连接工作负载至访问指导、设置任务参数、运行访问指导、查看和应用优化建议。访问指导不仅针对单条SQL语句,还能综合考虑多条SQL语句的优化效果,为DBA提供全面的决策支持。
93 11
|
2月前
|
存储 Oracle 关系型数据库
数据库数据恢复—ORACLE常见故障的数据恢复方案
Oracle数据库常见故障表现: 1、ORACLE数据库无法启动或无法正常工作。 2、ORACLE ASM存储破坏。 3、ORACLE数据文件丢失。 4、ORACLE数据文件部分损坏。 5、ORACLE DUMP文件损坏。
126 11
|
2月前
|
SQL 关系型数据库 MySQL
数据库数据恢复—Mysql数据库表记录丢失的数据恢复方案
Mysql数据库故障: Mysql数据库表记录丢失。 Mysql数据库故障表现: 1、Mysql数据库表中无任何数据或只有部分数据。 2、客户端无法查询到完整的信息。
|
2月前
|
SQL 监控 安全
SQL Servers审核提高数据库安全性
SQL Server审核是一种追踪和审查SQL Server上所有活动的机制,旨在检测潜在威胁和漏洞,监控服务器设置的更改。审核日志记录安全问题和数据泄露的详细信息,帮助管理员追踪数据库中的特定活动,确保数据安全和合规性。SQL Server审核分为服务器级和数据库级,涵盖登录、配置变更和数据操作等事件。审核工具如EventLog Analyzer提供实时监控和即时告警,帮助快速响应安全事件。
|
15天前
|
关系型数据库 MySQL 数据库连接
数据库连接工具连接mysql提示:“Host ‘172.23.0.1‘ is not allowed to connect to this MySQL server“
docker-compose部署mysql8服务后,连接时提示不允许连接问题解决
|
1天前
|
关系型数据库 MySQL 数据库
Docker Compose V2 安装常用数据库MySQL+Mongo
以上内容涵盖了使用 Docker Compose 安装和管理 MySQL 和 MongoDB 的详细步骤,希望对您有所帮助。
61 42
|
19天前
|
缓存 关系型数据库 MySQL
【深入了解MySQL】优化查询性能与数据库设计的深度总结
本文详细介绍了MySQL查询优化和数据库设计技巧,涵盖基础优化、高级技巧及性能监控。
152 0
|
2月前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
66 3