本文为您介绍如何查看并分析Query Profile,通过Query Profile快速识别影响StarRocks实例查询性能的瓶颈,并对瓶颈部分做出优化。
Query Profile概览
可视化Query Profile
StarRocks Manager支持对Profile进行可视化分析,您可以通过StarRocks Manager可视化您的Query Profile。
确认查询瓶颈
Operator花费的时间比例越大,其对应颜色就越深(支持对执行耗时排名前三的节点标注颜色)。您可以借此轻松确认查询的瓶颈。示例如下。
Query Profile优化案例
Bitmap索引
Bitmap索引是一种使用bitmap的特殊数据库索引。bitmap即为一个bit数组,一个bit的取值有0和1两种。每一个bit对应数据表中的一行,并根据该行的取值情况来决定bit的取值是0还是1。
对于基数较低且大量重复(例如,性别)的字段值,可以使用Bitmap过滤器来提高查询效率。
查询是否命中了Bitmap filter索引,可查看该查询的Profile中的BitmapIndexFilterRows字段。
创建索引
建表时创建Bitmap索引
CREATE TABLE `student_info` ( `s_stukey` bigint(20) NULL COMMENT "", `s_name` varchar(65533) NULL COMMENT "", `s_gender` varchar(65533) NULL COMMENT "", INDEX index1 (s_gender) USING BITMAP COMMENT 'index1' ) ENGINE=OLAP DUPLICATE KEY(`s_stukey`) COMMENT "OLAP" DISTRIBUTED BY HASH(`s_stukey`); INSERT INTO student_info VALUES (001,'student#000000019','male'), (002,'student#000000020','male'), (003,'student#000000021','male'), (004,'student#000000022','female');
建表后使用CREATE INDEX创建Bitmap索引
CREATE INDEX index_name ON table_name (column_name) [USING BITMAP] [COMMENT ''];
查看创建索引进度
SHOW ALTER TABLE COLUMN [FROM db_name];
查看索引
SHOW {INDEX[ES] | KEY[S] } FROM [db_name.]table_name [FROM db_name];
删除索引
DROP INDEX index_name ON [db_name.]table_name;
单列查询测试
执行Query,过滤s_gender列。
select * from student_info where s_gender='male';
查看Profile。
单击OLAP_SCAN,然后单击右侧的节点详情页签,过滤Bitmap可以看到Bitmap索引已经生效。
Bloom filter索引
Bloom filter索引可以快速判断表的数据文件中是否可能包含要查询的数据,如果不包含就跳过,从而减少扫描的数据量。Bloom Filter空间效率高,适用于高基数的列(例如,ID列)。
主键模型和明细模型中所有列都可以创建Bloom filter索引;聚合模型和更新模型中,只有维度列(即Key列)支持创建Bloom filter索引。
不支持为TINYINT、FLOAT、DOUBLE和DECIMAL类型的列创建Bloom filter索引。
Bloom filter索引只能提高包含
in
和=
过滤条件的查询效率。例如Select xxx from table where xxx in ()
和Select xxx from table where column = xxx
。查询是否命中了Bloom filter索引,可查看该查询的Profile中的BloomFilterFilterRows字段。
创建索引
建表时,通过在PROPERTIES
中指定bloom_filter_columns
来创建索引。示例如下。
CREATE TABLE table1
(
k1 BIGINT,
k2 LARGEINT,
v1 VARCHAR(2048) REPLACE,
v2 SMALLINT DEFAULT "10"
)
ENGINE = olap
PRIMARY KEY(k1, k2)
DISTRIBUTED BY HASH (k1, k2) BUCKETS 10
PROPERTIES("bloom_filter_columns" = "k1,k2"); --多个索引列之间需用逗号(,)隔开;
查看索引
SHOW CREATE TABLE table1;
修改索引
示例如下所示:
增加一个Bloom filter索引列v1。
ALTER TABLE table1 SET ("bloom_filter_columns" = "k1,k2,v1");
减少一个Bloom filter索引列k2。
ALTER TABLE table1 SET ("bloom_filter_columns" = "k1");
删除table1的所有Bloom filter索引。
ALTER TABLE table1 SET ("bloom_filter_columns" = "");
实例测试
以TPC_H中的customer表为例,在基数较高的列且非排序Key的列上增加Bloom filter索引,例如c_phone列。
ALTER TABLE tpc_h_sf100.customer SET ("bloom_filter_columns" = "c_custkey, c_phone");
查看索引,确认Bloom filter索引已添加。
SHOW CREATE TABLE tpc_h_sf100.customer;
执行Query,过滤c_phone列。
select * from tpc_h_sf100.customer where c_phone = "10-334-921-5346";
查看Profile。
单击OLAP_SCAN,然后单击右侧的节点详情页签,找到BloomFilterFilterRows指标,确认BloomFilter Index生效。
优化数据倾斜
以TPC_H中的lineitem表为例,选择非均匀分布的key作为分桶键来测试数据倾斜问题。本示例中l_tag
字段的value分布不均匀。
创建测试数据,在TPC_H中的lineitem表中新增一列,作为DISTRIBUTED字段。
CREATE TABLE `lineitem_tag` ( `l_orderkey` bigint(20) NULL COMMENT "", `l_partkey` bigint(20) NULL COMMENT "", `l_suppkey` bigint(20) NULL COMMENT "", `l_linenumber` int(11) NULL COMMENT "", `l_quantity` double NULL COMMENT "", `l_extendedprice` double NULL COMMENT "", `l_discount` double NULL COMMENT "", `l_tax` double NULL COMMENT "", `l_returnflag` varchar(65533) NULL COMMENT "", `l_linestatus` varchar(65533) NULL COMMENT "", `l_shipdate` date NULL COMMENT "", `l_commitdate` date NULL COMMENT "", `l_receiptdate` date NULL COMMENT "", `l_shipinstruct` varchar(65533) NULL COMMENT "", `l_shipmode` varchar(65533) NULL COMMENT "", `l_comment` varchar(65533) NULL COMMENT "", `l_tag` varchar(65533) default 'false' COMMENT "" ) ENGINE=OLAP DUPLICATE KEY(`l_orderkey`) COMMENT "OLAP" DISTRIBUTED BY HASH(`l_tag`) BUCKETS 96 PROPERTIES ( "replication_num" = "1", "in_memory" = "false", "storage_format" = "DEFAULT", "enable_persistent_index" = "false" ); insert into lineitem_tag select *, 'false' as l_tag from tpc_h_sf100.lineitem;
执行Query,进行全表查询。
select count(1) from lineitem_tag;
查看Profile。
单击OLAP_SCAN,在右侧的节点页签,对比MaxTime和MinTime下的SCAN,发现时间相差好几个量级,可能发生了数据倾斜。
通过优化表结构重新定义DISTRIBUTED字段。
再次查看Profile,对比MaxTime和MinTime下的SCAN,可以发现数据倾斜问题得到优化。
单表物化视图
StarRocks中的单表物化视图(Rollup)是一种特殊的索引,无法直接查询。如果您的数据仓库中存在大量复杂或重复的查询,您可以通过创建单表物化视图加速查询。
查询测试
以TPC_H中lineitem表为例,执行Query。
select l_returnflag,l_linestatus,l_shipmode,sum(l_extendedprice) from lineitem group by l_returnflag,l_linestatus,l_shipmode;
初次查询,未创建物化视图查询耗时1115毫秒。
查看Profile。
单击OLAP_SCAN,在右侧的节点页签,可以看到Rollup扫描的是lineitem表本身。
创建物化视图
CREATE MATERIALIZED VIEW material_test AS select l_returnflag,l_linestatus ,l_shipmode,sum(l_extendedprice) from lineitem group by l_returnflag,l_linestatus,l_shipmode;
验证查询是否命中单表物化视图
您可以使用EXPLAIN命令查看该查询是否命中单表物化视图。
explain select l_returnflag,l_linestatus ,l_shipmode,sum(l_extendedprice) from lineitem group by l_returnflag,l_linestatus,l_shipmode;
查看Profile。
单击OLAP_SCAN,在右侧的节点页签,可以看到命中物化视,同时Query用时也更短,耗时0.05毫秒。
确认Join左右表Plan是否合理
通常StarRocks会选择较小的表作为Join的右表。如果Query Profile显示右表的数据量明显大于左表,则该Join Plan异常。
以TPC_DH中的query72.sql为例。
select i_item_desc, w_warehouse_name, d1.d_week_seq, sum(case when p_promo_sk is null then 1 else 0 end) no_promo, sum(case when p_promo_sk is not null then 1 else 0 end) promo, count(*) total_cnt from inventory join catalog_sales on (cs_item_sk = inv_item_sk) join warehouse on (w_warehouse_sk=inv_warehouse_sk) join item on (i_item_sk = cs_item_sk) join customer_demographics on (cs_bill_cdemo_sk = cd_demo_sk) join household_demographics on (cs_bill_hdemo_sk = hd_demo_sk) join date_dim d1 on (cs_sold_date_sk = d1.d_date_sk) join date_dim d2 on (inv_date_sk = d2.d_date_sk) join date_dim d3 on (cs_ship_date_sk = d3.d_date_sk) left outer join promotion on (cs_promo_sk=p_promo_sk) join catalog_returns on (cr_item_sk = cs_item_sk and cr_order_number = cs_order_number) where d1.d_week_seq = d2.d_week_seq and inv_quantity_on_hand < cs_quantity and d3.d_date > (cast(d1.d_date AS DATE) + interval '5' day) and hd_buy_potential = '>10000' and d1.d_year = 1999 and cd_marital_status = 'D' group by i_item_desc,w_warehouse_name,d1.d_week_seq order by total_cnt desc, i_item_desc, w_warehouse_name, d1.d_week_seq limit 100;
查看Profile。
查看HASH_JOIN的节点信息,可以看到右表的数据量明显大于左表,说明该Join Plan异常。
修改
join catalog_returns
方式为left outer join
。select i_item_desc, w_warehouse_name, d1.d_week_seq, sum(case when p_promo_sk is null then 1 else 0 end) no_promo, sum(case when p_promo_sk is not null then 1 else 0 end) promo, count(*) total_cnt from inventory join catalog_sales on (cs_item_sk = inv_item_sk) join warehouse on (w_warehouse_sk=inv_warehouse_sk) join item on (i_item_sk = cs_item_sk) join customer_demographics on (cs_bill_cdemo_sk = cd_demo_sk) join household_demographics on (cs_bill_hdemo_sk = hd_demo_sk) join date_dim d1 on (cs_sold_date_sk = d1.d_date_sk) join date_dim d2 on (inv_date_sk = d2.d_date_sk) join date_dim d3 on (cs_ship_date_sk = d3.d_date_sk) left outer join promotion on (cs_promo_sk=p_promo_sk) left outer join catalog_returns on (cr_item_sk = cs_item_sk and cr_order_number = cs_order_number) where d1.d_week_seq = d2.d_week_seq and inv_quantity_on_hand < cs_quantity and d3.d_date > (cast(d1.d_date AS DATE) + interval '5' day) and hd_buy_potential = '>10000' and d1.d_year = 1999 and cd_marital_status = 'D' group by i_item_desc,w_warehouse_name,d1.d_week_seq order by total_cnt desc, i_item_desc, w_warehouse_name, d1.d_week_seq limit 100;
再次查看Profile,可以看到性能已得到优化。
确认JoinRuntimeFilter是否生效
当Join的右表构建Hash Table时,会构建Runtime Filter,该Runtime Filter会被投递到左子树,并尽可能地下推到Scan Operator。您可以在Scan Operator的节点详情选项卡上查看与JoinRuntimeFilter相关的指标。
以TPC_DH中的query72.sql为例,。
select i_item_desc, w_warehouse_name, d1.d_week_seq, sum(case when p_promo_sk is null then 1 else 0 end) no_promo, sum(case when p_promo_sk is not null then 1 else 0 end) promo, count(*) total_cnt from inventory join catalog_sales on (cs_item_sk = inv_item_sk) join warehouse on (w_warehouse_sk=inv_warehouse_sk) join item on (i_item_sk = cs_item_sk) join customer_demographics on (cs_bill_cdemo_sk = cd_demo_sk) join household_demographics on (cs_bill_hdemo_sk = hd_demo_sk) join date_dim d1 on (cs_sold_date_sk = d1.d_date_sk) join date_dim d2 on (inv_date_sk = d2.d_date_sk) join date_dim d3 on (cs_ship_date_sk = d3.d_date_sk) left outer join promotion on (cs_promo_sk=p_promo_sk) left outer join catalog_returns on (cr_item_sk = cs_item_sk and cr_order_number = cs_order_number) where d1.d_week_seq = d2.d_week_seq and inv_quantity_on_hand < cs_quantity and d3.d_date > (cast(d1.d_date AS DATE) + interval '5' day) and hd_buy_potential = '>10000' and d1.d_year = 1999 and cd_marital_status = 'D' group by i_item_desc,w_warehouse_name,d1.d_week_seq order by total_cnt desc, i_item_desc, w_warehouse_name, d1.d_week_seq limit 100;
查看Profile。
单击OLAP_SCAN,单击右侧的节点详情页签,可以看到在Scan Operator算子扫描inventory表时触发了JoinRuntimeFilter。
Colocate Join
在StarRocks中使用Colocate Join功能,需要在建表时为其指定一个Colocation Group(CG),同一CG内的表需遵循相同的Colocation Group Schema(CGS),可以保证同一CG内所有表的数据分布在相同一组BE节点上。当Join列为分桶键时,计算节点只需做本地Join,从而减少数据在节点间的传输耗时,提高查询性能。因此,Colocate Join相对于其他Join,例如Shuffle Join和Broadcast Join,可以有效避免数据网络传输开销,提高查询性能。
创建Colocation表
StarRocks仅支持对同一Database中的表进行Colocate Join操作。
CREATE TABLE tbl (k1 int, v1 int sum)
DISTRIBUTED BY HASH(k1)
BUCKETS 8
PROPERTIES(
"colocate_with" = "group1"
);
删除Colocation Group
当Group中最后一张表彻底删除后,该Group也会被自动删除。彻底删除是指从回收站中删除。通常,一张表通过DROP TABLE
命令被删除后,会在回收站默认停留一天的时间后,再被彻底删除。
查看Group信息
例如,执行以下命令,查看Group信息。
SHOW PROC '/colocation_group';
返回信息如下。
+-------------+--------------+----------+------------+----------------+----------+----------+
| GroupId | GroupName | TableIds | BucketsNum | ReplicationNum | DistCols | IsStable |
+-------------+--------------+----------+------------+----------------+----------+----------+
| 11912.11916 | 11912_group1 | 11914 | 8 | 3 | int(11) | true |
+-------------+--------------+----------+------------+----------------+----------+----------+
各参数含义如下表所示。
列名 | 描述 |
GroupId | 一个Group的全集群唯一标识。前半部分为DataBase ID,后半部分为Group ID。 |
GroupName | Group的全名。 |
TabletIds | 该Group包含的表的ID列表。 |
BucketsNum | 分桶数。 |
ReplicationNum | 副本数。 |
DistCols | Distribution columns,即分桶列类型。 |
IsStable | 该Group是否稳定。 |
您可以通过以下命令进一步查看特定Group的数据分布情况。
SHOW PROC '/colocation_group/GroupId';
SHOW PROC '/colocation_group/11912.11916';
返回信息如下。
+-------------+---------------------+
| BucketIndex | BackendIds |
+-------------+---------------------+
| 0 | 10002, 10004, 10003 |
| 1 | 10002, 10004, 10003 |
| 2 | 10002, 10004, 10003 |
| 3 | 10002, 10004, 10003 |
| 4 | 10002, 10004, 10003 |
| 5 | 10002, 10004, 10003 |
| 6 | 10002, 10004, 10003 |
| 7 | 10002, 10004, 10003 |
+-------------+---------------------+
8 rows in set (0.00 sec)
修改Group属性
ALTER TABLE tbl SET ("colocate_with" = "group_name");
以TPC_H中数据为例,执行以下操作。
use tpc_h_sf100; ALTER TABLE orders SET ("colocate_with" = "cg_tpc_orders"); ALTER TABLE lineitem SET ("colocate_with" = "cg_tpc_orders");
执行以下Query查询。
select count(1) from orders as o join lineitem as l on o.o_orderkey = l.l_orderkey;
您可以在EMR StarRocks Manager页面查询的查询计划页签,查看Colocate Join是否生效。
当
colocate
显示为true时,表示Colocate Join生效。
确认分桶或分区裁剪是否生效
您可以在EMR StarRocks Manager页面查询的查询计划页签,查看参数partition或tabletRatio,确认分区或分桶裁剪是否生效。