以下文章来源于数据极客圈 ,作者徐振超
[
数据极客圈 .
一入大数据深似海?别怕!“数据极客圈” 就是你的救生圈,走对圈子跟对人,趣析数据、畅聊趋势,快进圈子!
](#)
在大数据开发的领域中,Apache Doris 凭借其强大的性能,成为处理海量数据的有力工具。若想让 Doris 在数据处理中发挥出最大效能,查询优化必不可少。本文作为 Doris 查询优化秘籍的上篇,将深入剖析 Schema、索引优化以及使用分区裁剪优化扫表的关键策略。
一、Schema 优化:筑牢数据处理根基
Schema 就如同大厦的蓝图,合理的 Schema 设计能够充分发挥 Doris 的特性,提升系统性能;反之,不合理的 Schema 则可能成为性能瓶颈。
1.1 表引擎抉择
Doris 支持 Duplicate、Unique、Aggregate 三种表模型,其中 Unique 又细分为 Merge-On-Read(MOR)和 Merge-On-Write(MOW)。不同的表模型适用于不同的业务场景,性能表现也有所差异。打个比方,Duplicate 表模型如同高速公路,能让查询快速通行,适用于对查询性能要求极高且无数据更新需求的场景;MOW 表模型则像城市主干道,性能较为平稳;MOR 和 Aggregate 表模型类似普通街道,虽能满足基本需求,但在性能上稍显逊色。一般来说,查询性能排序为:Duplicate > MOW > MOR == Aggregate。
优化建议:当业务追求极致的查询速度,且对数据更新没有要求时,优先选择 Duplicate 表模型,就像出行追求速度时首选高速公路一样。
⚠️在 1.2 版本后,Doris 中的主键模型默认使用写时合并模式
1.2 分桶列甄选
分桶操作在 Doris 中至关重要,合理选择分桶列能够避免数据倾斜,提升系统并行处理能力。这就好比快递分拣,将快递合理分配到不同的站点,能够提高派送效率。若分桶列选择不当,就会导致数据像所有快递都集中到一个站点一样,出现数据倾斜。
例如,创建 t1 表时:
CREATE TABLE `t1` ( `c1` INT NULL, `c2` INT NULL ) ENGINE=OLAP DUPLICATE KEY(`c1`) DISTRIBUTED BY HASH(`c2`) BUCKETS 64 PROPERTIES ( "replication_allocation" = "tag.location.default: 1" );
若 c2 列的值在数据导入时全部为 null,即便设置了 64 个分桶,也会出现严重的数据倾斜。此时,将分桶列改为 c1:
CREATE TABLE `t1` ( `c1` INT NULL, `c2` INT NULL ) ENGINE=OLAP DUPLICATE KEY(`c1`) DISTRIBUTED BY HASH(`c1`) BUCKETS 64 PROPERTIES ( "replication_allocation" = "tag.location.default: 1" );
就能实现数据的均匀分布,提升系统性能。
优化建议:定期检查分桶列是否存在数据倾斜问题,可通过select 分桶列,count(*) from table group by 分桶列 order by count(*) desc limit 100;
语句进行确认。若存在数据倾斜,应更换为在业务含义上具有充分散列特性的字段作为分桶列。
1.3 Key 列设定
在三种表模型中,Doris 会依据建表 Schema 中指定的 Duplicate Key、Unique Key 或 Aggregate Key,在存储层面将数据按 Key 列排序。这就如同图书馆按照书籍类别摆放书籍,方便读者快速查找。利用这一特性,将业务查询中频繁使用的等值或范围查询列定义为 Key 列,能显著提升查询速度。
例如,对于频繁使用 c1 列进行查询的业务:
select * from t1 where t1.c1 = 1;
可在建表时将 c1 列设为 Key 列:
CREATE TABLE `t1` ( `c1` INT NULL, `c2` INT NULL ) ENGINE=OLAP DUPLICATE KEY(`c1`) DISTRIBUTED BY HASH(`c2`) BUCKETS 10 PROPERTIES ( "replication_allocation" = "tag.location.default: 1" );
优化建议:将业务查询中频繁使用的列设定为 Key 列,为数据查询提供便捷的 “索引标签”。
1.4 字段类型优化
在数据库系统中,不同类型的数据处理复杂度不同。变长类型和高精类型的数据处理相对复杂,而定长类型和低精类型的数据处理更为高效。这就好比使用复杂工具和简单工具完成任务,简单工具往往更高效。因此,在满足业务需求的前提下,应优先选择定长类型和低精类型,避免使用变长类型和高精类型。
例如,使用 BIGINT 替代 VARCHAR 或 STRING 类型的字段,用 FLOAT / INT / BIGINT 替换 DECIMAL 类型的字段:
-- 替换前 CREATE TABLE `t2` ( `id` VARCHAR(10) NULL, `amount` DECIMAL(10, 2) NULL ); -- 替换后 CREATE TABLE `t2` ( `id` BIGINT NULL, `amount` FLOAT NULL );
优化建议:在定义 Schema 类型时,遵循定长和低精优先的原则,选择更高效的 “数据处理工具”。
1.5 分区策略规划
合理的分区策略能有效减少查询时扫描的数据量,就像在大型仓库中按类别分区存放货物,找货时能快速定位。Doris 支持按时间、范围等多种方式分区。例如,对于按时间存储的业务数据,按天或按月分区,能在查询特定时间段数据时,仅扫描相关分区,大大提高查询效率。
CREATE TABLE sales ( sale_date DATE, product_id INT, amount DECIMAL(10, 2) ) PARTITION BY RANGE(sale_date) ( PARTITION p202301 VALUES LESS THAN ('2023-02-01'), PARTITION p202302 VALUES LESS THAN ('2023-03-01') ) DISTRIBUTED BY HASH(product_id) BUCKETS 16 PROPERTIES ( "replication_num" = "1" );
优化建议:根据业务数据的特点和查询需求,选择合适的分区方式和分区粒度。如果数据量增长快,可适当增加分区数量;若查询频繁涉及多个分区,可考虑调整分区范围。
1.6 数据压缩策略
CREATE TABLE logs ( log_time TIMESTAMP, log_message VARCHAR(255) ) DUPLICATE KEY(log_time) DISTRIBUTED BY HASH(log_time) BUCKETS 8 PROPERTIES ( "replication_num" = "1", "storage_format" = "V2", "compresion" = "LZ4" );
优化建议:根据数据的读写频率和存储需求,选择合适的压缩算法。对于写入频繁且对查询实时性要求高的数据,优先选择 LZ4;对于历史数据或查询频率较低的数据,可考虑使用 Zlib 以节省存储空间。
二、索引优化:打造高效数据检索工具
索引在 Doris 查询优化中起着关键作用,合理的索引设计能够大幅提升查询效率,就像精准的导航地图,帮助我们在海量数据中快速找到目标。
2.1 前缀索引运用
Doris 内置前缀索引功能,建表时会自动取表 Key 的前 36 字节作为前缀索引。这就像是地图的目录,通过前缀索引,我们可以快速定位到相关的数据。
例如,创建 t1 表时:
CREATE TABLE `t1` ( `c1` VARCHAR(10) NULL, `c2` VARCHAR(10) NULL ) ENGINE=OLAP DUPLICATE KEY(`c1`) DISTRIBUTED BY HASH(`c2`) BUCKETS 10 PROPERTIES ( "replication_allocation" = "tag.location.default: 1" );
若查询使用 c2 字段进行过滤:
select * from t1 where t1.c2 = '1';
由于 c1 在前,c2 在后,此时无法利用前缀索引的加速功能。调整列顺序后:
CREATE TABLE `t1` ( `c2` VARCHAR(10) NULL, `c1` VARCHAR(10) NULL ) ENGINE=OLAP DUPLICATE KEY(`c2`) DISTRIBUTED BY HASH(`c1`) BUCKETS 10 PROPERTIES ( "replication_allocation" = "tag.location.default: 1" );
即可利用前缀索引加速查询。
优化提示:在定义 schema 列顺序时,参考业务查询过滤中的高频高优列,以充分利用 Doris 的前缀索引加速功能。
⚠️当遇到 VARCHAR 类型时,前缀索引会直接截断。如果第一列即为 VARCHAR,那么即使没有达到 36 字节,也会直接截断,后面的列不再加入前缀索引。
2.2 倒排索引应用
Doris 支持倒排索引作为二级索引,用于加速等值、范围及文本类型的全文检索等业务场景。倒排索引就像是一个特殊的搜索引擎,它的创建和管理独立,不影响原始表 Schema 和无需重新导入表数据。
例如,对于文章表:
CREATE TABLE `articles` ( `id` INT, `title` VARCHAR(100), `content` VARCHAR(1000) ) ENGINE=OLAP DUPLICATE KEY(`id`) DISTRIBUTED BY HASH(`id`) BUCKETS 10;
创建倒排索引:
CREATE INDEX idx_content ON articles(content);
当进行关键词搜索时,倒排索引能快速定位到包含关键词的文章,提高查询效率。
优化建议:对于文本类型的全文检索,以及字符串、数值、日期时间类型字段上的等值或范围查询,均可利用倒排索引来加速查询。
三、使用分区裁剪优化扫表:精准筛选数据
分区裁剪是一种智能的数据筛选机制,就像在一个巨大的书架上找书,它能根据查询条件,精准定位到存放目标书籍的区域,而不是盲目地翻阅整个书架。当我们在 Doris 中进行查询时,分区裁剪功能会分析查询条件,仅扫描与条件相关的分区数据,跳过无关的分区,大大减少了数据扫描量,提升查询速度。
假设我们有一张存储用户行为数据的表user_behavior
,按日期进行分区:
CREATE TABLE user_behavior ( user_id INT, behavior_type VARCHAR(50), event_time DATE ) PARTITION BY RANGE(event_time) ( PARTITION p202401 VALUES LESS THAN ('2024-02-01'), PARTITION p202402 VALUES LESS THAN ('2024-03-01') ) DISTRIBUTED BY HASH(user_id) BUCKETS 10 PROPERTIES ( "replication_num" = "1" );
如果我们要查询 2024 年 1 月 15 日的用户行为数据:
SELECT * FROM user_behavior WHERE event_time = '2024-01-15';
Doris 的分区裁剪机制会识别出查询条件中的日期范围,只扫描p202401
分区的数据,而不会去扫描p202402
分区,极大地提高了查询效率。
优化建议:在设计表 Schema 时,充分考虑业务查询中常用的分区条件,合理设置分区。同时,在编写查询语句时,确保查询条件能够准确触发分区裁剪,避免全表扫描。
以上就是 Doris 查询优化秘籍上篇的主要内容,通过对 Schema、索引优化以及分区裁剪优化扫表的深入理解和运用,能够显著提升 Doris 在数据处理和查询方面的性能。下篇我们将继续探索 Doris 查询优化的其他技巧,敬请期待!
往期推荐
[
](http://mp.weixin.qq.com/s?__b...
Doris的Stream Load那些事儿,你踩过哪些“坑”?
如何排查 Apache Doris 中 "Failed to commit txn" 导入失败问题?
Doris 磁盘问题全解析:从挂盘到 Trash 问题,一文读懂!
完
●
数据极客圈子介绍
●
圈子1
Apache Doris社区是目前国内最活跃的开源社区(之一)。Apache Doris(Apache 顶级项目) 聚集了世界全国各地的用户与开发人员,致力于打造一个内容完整、持续成长的互联网开发者学习生态圈!
如果您对Apache Doris感兴趣,可以通过以下入口访问官方网站、社区论坛、GitHub和dev邮件组:
💡官网文档:https://doris.apache.org
💡社区论坛:https://ask.selectdb.com
💡GitHub:https://github.com/apache/doris
💡dev邮件组:mailto:dev@doris.apache.org
可以加作者微信(Faith\_xzc)直接进Doris官方社区群
圈子2
PowerData是由一群数据从业人员,因为热爱凝聚在一起,以开源精神为基础,组成的数据开源社区。
社区整理了一份每日一题汇总及社区分享PPT,内容涵盖大数据组件、编程语言、数据结构与算法、企业真实面试题等各个领域,帮助您提升自我,成功上岸。
可以加作者微信(Faith\_xzc)直接进PowrData官方社区群
叮咚✨ “数据极客圈” 向你敞开大门,走对圈子跟对人,行业大咖 “唠” 数据,实用锦囊天天有,就缺你咯!快快关注数据极客圈,共同成长!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。