作为新一代分析型数据库,StarRocks 一直因性能卓越、功能全面而深受广大用户喜爱。在追求功能和性能的同时,易用性方面,StarRocks 也在一直围绕一线运维人员的作业细节持续提升,尤其从 V3.0 起,社区投入大量开发资源全面提升易用性。从分区分桶、导入导出、全局字典、查询观测性等各方面的操作都已变得非常简便,易用性因此成为 StarRocks 的一大产品特色,并持续受到一线运维人员的关注和认可。
本文将简要介绍如何轻松使用 StarRocks,主要涵盖分区分桶、数据导入、数据转换以及表结构优化几个方面的内容:
- 分区分桶:直接使用 date_trunc() 函数来指定分区方式,同时无需再考虑分桶键和分桶数量;
- 数据导入:从 HDFS 或云存储上导入数据时,可以使用更简单、更符合普通 SQL 语法的 INSERT from FILES 来实现;
- 数据转换:通过支持通用的 SELECT 和 JOIN 操作的 INSERT from FILES,能够更轻松、更通用地进行所需的数据转换(Transform)。这使得在导入过程中能够便捷地完成复杂的数据清洗转换工作;
- 表结构优化:可以通过 ALTER TABLE 命令进行表结构的调整和数据重组,包括重新设置分桶方式和分桶数、排序键,从而灵活响应最新的业务场景和性能需求。
分区分桶 :简单设置便能得到预期查询性能
对于很多使用 StarRocks 的同学来说,分区分桶通常是遇到的第一个门槛,一些缺乏了解的同学可能会凭感觉设置(不区分大小表,甚至没有按照最普通的 1GB ~ 10GB 一个分桶的建议),或者直接采用别人的建表模板,因而难以得到理想的查询性能,还可能因为设置的分桶数量过多而导致元数据占用内存过多。
的确,分区分桶的设置是否合理,对最终的性能表现会有显著影响,而过去在设置分区分桶时,除了需要理解不同方式有什么作用和限制,还要根据数据量大小以及常用查询 pattern 去合理地设置分桶键以及分桶数量,才能达到预期的查询性能。从 V3.0 到 V3.2,社区在这方面做了不少优化,尽量让用户更容易设置、甚至不用再管它。
推荐的分区分桶方式一般是这样的:
CREATE TABLE user_behavior_declared (
UserID int(11),
ItemID int(11),
CategoryID int(11),
BehaviorType varchar(65533),
Timestamp datetime
)
DUPLICATE KEY (CategoryID, UserId)
PARTITION BY date_trunc('day', Timestamp)
-- DISTRIBUTED BY RANDOM -- 可以不再需要设置
一般情况下,建议直接使用 date_trunc() 函数来指定分区方式(也即「时间函数表达式分区」)。绝大多数场景,按天分区都是比较合适的分区方式,并且设置这种分区方式后,系统会根据数据中相应的时间字段自动按需动态创建分区,不再需要在建表中手动设置历史分区、也不需要设定复杂的动态分区规则来创建未来分区。
对于分桶,经过 V3.1 和 V3.2 2 个版本的优化,一般用户终于可以不用再管分桶了(包括分桶键和分桶数量)。默认情况下,系统会设置 Random 分桶(当前只支持明细表),并根据集群信息、导入中的数据量、以及导入方式按需动态调整 Tablet 数量。除了更加易用外,在 Tablet 特别多、或较为实时的导入情况中,还能大量减少对内存的占用和 I/O 的开销,可谓一举两得。
数据导入:一个 SQL 指令就能从云存储导入 TB 级数据
在建完表后,接下来就是导入数据了。对于大数据量的导入来说,一般都是从 HDFS 或云存储上导入数据之前,Broker Load 是首选,现在则可以使用更简单、更符合普通 SQL 语法的 INSERT from FILES 来进行数据导入。这里以 S3 为例向大家展示新的数据导入方式到底有多简单。
在执行数据导入之前,一般会先进行简单的 SELECT,以查看数据内容:
SELECT *
FROM FILES(
'path' = 's3://starrocks-examples/user_behavior_ten_million_rows.parquet',
'format' = 'parquet',
'aws.s3.region' = 'us-east-1',
'aws.s3.use_instance_profile' = 'false',
'aws.s3.access_key' = 'AAAAAAAAAAAAAAAAAAAA',
'aws.s3.secret_key' = 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'
) LIMIT 5;
通过如上一个很简单的 SELECT 查询,你就能基本了解数据的 schema 和数据内容(因为 FILES()会根据给定的数据路径等参数自动推断出表结构),从而帮助你更简单地在建表时指定 table schema。当然,你还可以直接采用 CTAS 语句来建一个临时用的表,并通过 SHOW CREATE TABLE 来查看具体的建表信息,结合自己的需要,适当修改后即可创建最终的目标表。
通常,根据业务含义,可以设置更合适和高效的字段类型、分区分桶方式,以达到更高的查询性能。同时,通过查询数据的最大值、最小值等信息,可以更准确地了解数据的范围。
CREATE TABLE temp_tbl AS
SELECT * FROM FILES(...) LIMIT 100;
在创建好目标表后,就可以直接使用 INSERT from FILES 进行导入:
INSERT INTO user_behavior_declared
SELECT * FROM FILES(
'path' = 's3://starrocks-examples/user_behavior_ten_million_rows.parquet',
'format' = 'parquet',
'aws.s3.region' = 'us-east-1',
'aws.s3.use_instance_profile' = 'false',
'aws.s3.access_key' = 'AAAAAAAAAAAAAAAAAAAA',
'aws.s3.secret_key' = 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'
);
在导入过程中,你可以通过使用 SHOW LOAD(或者查询 information_schema.loads 表)来监视导入的进度和情况。通过检查其中的 TRACKING SQL 字段,你能够获取导入中具体数据错误的信息,这有助于纠正导入语句中可能存在的问题。
当涉及大量文件导入,尤其是在后续进行了列操作,导致前后文件的 Schema 不完全一致时,采用 INSERT from FILES 相较于 Broker Load 会更加简便。这种情况下,使用 INSERT from FILES 可以更轻松地处理不同文件之间的 Schema 差异。
一般情况下,通过 INSERT from FILES 方式,一次导入 1TB 数据基本无压力。不过,数据导入前并不总是经过精心预处理,导入时可能会因为部分数据的质量问题(比如字段缺失、导入中数据类型转换失败等),导致整个导入作业失败。所以,在导入几百 GB 以上的数据时,一般就建议使用 PIPE 来进行导入。
PIPE 是 StarRocks V3.2 新提供的封装在 INSERT from FILES 之上的功能,适用于大规模批量导入数据、以及持续导入数据的场景。
在导入大规模数据时,PIPE 命令会自动根据导入数据大小和导入文件数量将一个大导入作业拆分成很多个小导入任务并串行运行。单个文件的数据错误不会导致整个导入作业的失败。从而,可以降低作业出错重试的代价、提升数据导入的稳健性。
同时,PIPE 还能不断监听云存储目录中的新增文件或文件内容修改,并自动将变化的数据文件拆分成一个个小的导入任务,持续地将新数据导入到目标表中(需要在语句中指定 ‘AUTO_INGEST’ = ‘TRUE’)。从而不再需要用户自己维护一个批量任务调度系统,简化了数据导入的维护工作。
使用上也非常简单,在前面的 INESRT from FILES 语句前加个 CREATE PIPE 子句即可:
CREATE PIPE user_behavior_pipe
PROPERTIES (
'AUTO_INGEST' = 'FALSE', -- 在持续导入数据时需要设定为 TRUE
'BATCH_SIZE' = '100MB',
'BATCH_FILES' = '10'
)
AS
INSERT INTO user_behavior_declared
SELECT _ FROM FILES (
'path' = 's3://starrocks-examples/user-behavior-10-million-rows/_',
'format' = 'parquet',
'aws.s3.region' = 'us-east-1',
'aws.s3.use_instance_profile' = 'false',
'aws.s3.access_key' = 'AAAAAAAAAAAAAAAAAAAA',
'aws.s3.secret_key' = 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'
);
在 user_behavior_ten_million_rows/目录下,包含许多小文件。在执行过程中,将以 BATCH_FILES 的形式,即每批次导入 10 个文件(一般情况下,不需要设置 BATCH_SIZE,按默认设置即可。如果处理较大的数据集,可以将批次大小设置为大约 10GB 左右,以确保合适的处理效率)。
过程中,可以通过 SHOW PIPES 命令来查看总体进展,还可以通过 information_schema.pipe_files 表来查看具体的导入情况。PIPE 会记录每个文件的导入状态,当导入结束后,你可以查看并修复出错的数据文件,然后重新导入修正后的数据文件即可。这将显著降低由于数据质量问题导致的数据导入时出错而需要进行重试的成本。
数据转换:导入过程中就能完成复杂的数据清洗转换
通过 Broker Load 导入数据时,我们可以通过 SET(…) 子句使用一些简单的标量函数来产生新的列(衍生列)。但复杂一些的转换就不支持了,特别是列转行操作。而 INSERT from FILES 支持通用的 SELECT 和 JOIN 操作,可以更简便、更通用地实现想要的数据转换(Transform),从而在导入过程中就可以完成一些复杂的数据清洗转换工作,减少后续的再处理。
假设你的数据中有一个复杂字段 c_arr,其类型为 Array,其中每个 value 又是用#将 3 个字段拼接而成的字符串。样本数据如:[“k8s#1#SUCC”, “native#2#FAIL”],每个 value 中的 3 个字段分别代表 platform, id, status。
你现在想要在导入时把这个 Array 字段展开为多行,并且展开的每行增加对应 3 个字段:platform, id, status,那么你可以使用如下含有 JOIN 和 unnest 的方式轻松实现:
SELECT UserID, ItemID, CategoryID, BehaviorType, Timestamp, c_arr
, split(t_v.unnest, '#')[1] as platform
, cast(split(t_v.unnest, '#')[2] as INT) as id
, split(t_v.unnest, '#')[3] as status
FROM FILES (
'path' = 's3://starrocks-examples/user_behavior_ten_million_rows.parquet',
'format' = 'parquet',
'aws.s3.region' = 'us-east-1',
'aws.s3.access_key' = 'AAAAAAAAAAAAAAAAAAAA',
'aws.s3.secret_key' = 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'
), unnest(c_arr) as t_v;
这里,通过使用 unnest 的 Lateral Join 实现了数据的列转行操作,并使用 split 函数切分出了 3 个独立的字段。
表结构优化:分桶方式可随需求变化灵活调整
表结构优化是一个动态的过程,可以根据需求灵活调整。随着业务运行时间的增长、数据量的变化以及集群机器数量的调整,可能需要重新考虑分桶数量的优化配置。此外,随着业务查询模式的变化,表结构和排序可能不再适合当前主要查询类别的性能要求。
虽然 StarRocks 支持了自动设置分桶数量,也可以通过指定 Random 分桶让系统按需动态创建分桶,但你也可能觉得性能发挥得还不够极致。这时,你不只是想修改后续的分桶情况,还可能希望修改全部和部分历史分区的分布情况。在这种情况下,你可以使用 ALTER TABLE 命令,根据最新的业务场景和性能需求进行表结构的调整和数据重组,包括重新设置分桶方式、分桶数、排序键,甚至只调整部分分区的分桶数。
如果你觉得 Random 分桶就挺好了,可以使用以下语句修改原先采用 Hash 分桶方式的表:
ALTER TABLE user_behavior_declared DISTRIBUTED BY RANDOM;
如果你很清楚分桶对查询性能的影响,包括查询模式涉及到的分桶裁剪、排序键对查询性能的影响等,则可以通过如下语句修改成最合适的分桶方式和分桶数量:
ALTER TABLE user_behavior_declared DISTRIBUTED BY HASH(UserId) BUCKETS 12;
注意:
当前还只支持整表修改分桶方式。所以想改变分桶方式和分桶键,就必须重组所有分区。
如果查询中常用的过滤条件有较大的变化,使得原来的排序键不再适用大部分场景,则可以通过如下语句调整 ORDER BY:
ALTER TABLE user_behavior_declared ORDER BY (CategoryId, BehaviorType);
执行这些 ALTER TABLE 的任务可能需要一段时间,你可以通过使用 SHOW ALTER TABLE OPTIMIZE 命令来查看运行进度和情况。
易用性提升计划
显然,这些易用性的改进只是整个易用性改进计划的一部分,还有很多优化正在规划中。
- 实现统一且简单的建表语法,并解除所有表类型中的 sort key 和 table schema 的耦合。
- 进一步优化 Random 分桶中的数据组织,尽量实现 Random 分桶中的数据也能实现分桶裁剪,以提升查询性能。
- INSERT from FILES 将作为统一导入的主要形式,后续会持续增加对 CSV/JSON/Avro/Protobuf 等文件格式的支持。同时也会增加 table schema 指定、更多文件格式的参数、format/credential 封装等进一步提升易用性的功能。并且,后续还会融入 Routine Load 的功能,将流式数据的导入也统一进来。当然,如果你想导出数据,当前其实也已经支持了统一的 INSERT INTO FILES 的简便导出方式,后续也将进一步支持更多文件格式等。
- 进一步提升表结构优化功能,让系统分析常用查询模式以及数据量和数据分布,自动设置最合理的数据分布,进一步提升分区分桶的易用性。
总的来说,社区会不断改进易用性,同时期望大家多多使用、多多反馈,让我们一起打造一款强大且易用的产品。