[Doc] refactor query tuning best practice (#60935)
|
|
@ -440,5 +440,41 @@
|
|||
"theme.unlistedContent.message": {
|
||||
"message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.",
|
||||
"description": "The unlisted content banner message"
|
||||
},
|
||||
"theme.docs.DocCard.categoryDescription.plurals": {
|
||||
"message": "{count}項目",
|
||||
"description": "The default description for a category card in the generated index about how many items this category includes"
|
||||
},
|
||||
"theme.blog.author.pageTitle": {
|
||||
"message": "{authorName} - {nPosts}",
|
||||
"description": "The title of the page for a blog author"
|
||||
},
|
||||
"theme.blog.authorsList.pageTitle": {
|
||||
"message": "著者一覧",
|
||||
"description": "The title of the authors page"
|
||||
},
|
||||
"theme.blog.authorsList.viewAll": {
|
||||
"message": "すべての著者を見る",
|
||||
"description": "The label of the link targeting the blog authors page"
|
||||
},
|
||||
"theme.blog.author.noPosts": {
|
||||
"message": "この著者による投稿はまだありません。",
|
||||
"description": "The text for authors with 0 blog post"
|
||||
},
|
||||
"theme.contentVisibility.unlistedBanner.title": {
|
||||
"message": "非公開のページ",
|
||||
"description": "The unlisted content banner title"
|
||||
},
|
||||
"theme.contentVisibility.unlistedBanner.message": {
|
||||
"message": "このページは非公開です。 検索対象外となり、このページのリンクに直接アクセスできるユーザーのみに公開されます。",
|
||||
"description": "The unlisted content banner message"
|
||||
},
|
||||
"theme.contentVisibility.draftBanner.title": {
|
||||
"message": "下書きのページ",
|
||||
"description": "The draft content banner title"
|
||||
},
|
||||
"theme.contentVisibility.draftBanner.message": {
|
||||
"message": "このページは下書きです。開発環境でのみ表示され、本番環境のビルドには含まれません。",
|
||||
"description": "The draft content banner message"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"title": {
|
||||
"message": "Blog",
|
||||
"description": "The title for the blog used in SEO"
|
||||
},
|
||||
"description": {
|
||||
"message": "Blog",
|
||||
"description": "The description for the blog used in SEO"
|
||||
},
|
||||
"sidebar.title": {
|
||||
"message": "Recent posts",
|
||||
"description": "The label for the left sidebar"
|
||||
}
|
||||
}
|
||||
|
|
@ -462,5 +462,37 @@
|
|||
"sidebar.docs.link.DBT": {
|
||||
"message": "DBT",
|
||||
"description": "The label for link DBT in sidebar docs, linking to https://github.com/StarRocks/dbt-starrocks/blob/main/README.md"
|
||||
},
|
||||
"sidebar.docs.category.Best Practices": {
|
||||
"message": "Best Practices",
|
||||
"description": "The label for category Best Practices in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Query Tuning": {
|
||||
"message": "クエリチューニング",
|
||||
"description": "The label for category Query Tuning in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Query Tuning.link.generated-index.title": {
|
||||
"message": "クエリチューニングのベストプラクティス",
|
||||
"description": "The generated-index page title for category Query Tuning in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Query Tuning.link.generated-index.description": {
|
||||
"message": "StarRocks でクエリを分析、チューニング、最適化する方法を学びます。",
|
||||
"description": "The generated-index page description for category Query Tuning in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.データ分散": {
|
||||
"message": "データ分散",
|
||||
"description": "The label for category データ分散 in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Iceberg catalog": {
|
||||
"message": "Iceberg catalog",
|
||||
"description": "The label for category Iceberg catalog in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.meta-functions": {
|
||||
"message": "meta-functions",
|
||||
"description": "The label for category meta-functions in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.システムメタデータベース": {
|
||||
"message": "システムメタデータベース",
|
||||
"description": "The label for category システムメタデータベース in sidebar docs"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -416,5 +416,41 @@
|
|||
"theme.unlistedContent.message": {
|
||||
"message": "此页面未列出。搜索引擎不会对其索引,只有拥有直接链接的用户才能访问。",
|
||||
"description": "The unlisted content banner message"
|
||||
},
|
||||
"theme.docs.DocCard.categoryDescription.plurals": {
|
||||
"message": "{count} 个项目",
|
||||
"description": "The default description for a category card in the generated index about how many items this category includes"
|
||||
},
|
||||
"theme.blog.author.pageTitle": {
|
||||
"message": "{authorName} - {nPosts}",
|
||||
"description": "The title of the page for a blog author"
|
||||
},
|
||||
"theme.blog.authorsList.pageTitle": {
|
||||
"message": "Authors",
|
||||
"description": "The title of the authors page"
|
||||
},
|
||||
"theme.blog.authorsList.viewAll": {
|
||||
"message": "View All Authors",
|
||||
"description": "The label of the link targeting the blog authors page"
|
||||
},
|
||||
"theme.blog.author.noPosts": {
|
||||
"message": "This author has not written any posts yet.",
|
||||
"description": "The text for authors with 0 blog post"
|
||||
},
|
||||
"theme.contentVisibility.unlistedBanner.title": {
|
||||
"message": "未列出页",
|
||||
"description": "The unlisted content banner title"
|
||||
},
|
||||
"theme.contentVisibility.unlistedBanner.message": {
|
||||
"message": "此页面未列出。搜索引擎不会对其索引,只有拥有直接链接的用户才能访问。",
|
||||
"description": "The unlisted content banner message"
|
||||
},
|
||||
"theme.contentVisibility.draftBanner.title": {
|
||||
"message": "Draft page",
|
||||
"description": "The draft content banner title"
|
||||
},
|
||||
"theme.contentVisibility.draftBanner.message": {
|
||||
"message": "This page is a draft. It will only be visible in dev and be excluded from the production build.",
|
||||
"description": "The draft content banner message"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -562,5 +562,41 @@
|
|||
"sidebar.docs.category.系统元数据库": {
|
||||
"message": "系统元数据库",
|
||||
"description": "The label for category 系统元数据库 in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Best Practices": {
|
||||
"message": "Best Practices",
|
||||
"description": "The label for category Best Practices in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Query Tuning": {
|
||||
"message": "查询调优",
|
||||
"description": "The label for category Query Tuning in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Query Tuning.link.generated-index.title": {
|
||||
"message": "查询调优最佳实践",
|
||||
"description": "The generated-index page title for category Query Tuning in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Query Tuning.link.generated-index.description": {
|
||||
"message": "学习如何在 StarRocks 中分析、调优和优化查询。",
|
||||
"description": "The generated-index page description for category Query Tuning in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.数据分布": {
|
||||
"message": "数据分布",
|
||||
"description": "The label for category 数据分布 in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Iceberg catalog": {
|
||||
"message": "Iceberg catalog",
|
||||
"description": "The label for category Iceberg catalog in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.Caching": {
|
||||
"message": "Caching",
|
||||
"description": "The label for category Caching in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.meta-functions": {
|
||||
"message": "meta-functions",
|
||||
"description": "The label for category meta-functions in sidebar docs"
|
||||
},
|
||||
"sidebar.docs.category.dictionary": {
|
||||
"message": "dictionary",
|
||||
"description": "The label for category dictionary in sidebar docs"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -526,31 +526,7 @@
|
|||
"dirName": "administration/user_privs"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Performance Tuning",
|
||||
"link": {
|
||||
"type": "doc",
|
||||
"id": "cover_pages/performance_tuning"
|
||||
},
|
||||
"items": [
|
||||
"administration/Query_planning",
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Query Profile",
|
||||
"link": {
|
||||
"type": "doc",
|
||||
"id": "administration/query_profile_overview"
|
||||
},
|
||||
"items": [
|
||||
"administration/query_profile_text_based_analysis",
|
||||
"administration/query_profile_details"
|
||||
]
|
||||
},
|
||||
"administration/Profiling"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,356 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
---
|
||||
|
||||
# Query analysis
|
||||
|
||||
How to optimize query performance is a frequently asked question. Slow queries impair user experience as well as cluster performance. It is important to analyze and optimize query performance.
|
||||
|
||||
You can view query information in `fe/log/fe.audit.log`. Each query corresponds to a `QueryID` that can be used to search for the `QueryPlan` and `Profile` of a query. `QueryPlan` is the execution plan generated by FE by parsing SQL statements. `Profile` is BE execution result and contains information such as the time consumed by each step and the volume of data processed at each step.
|
||||
|
||||
## Plan analysis
|
||||
|
||||
In StarRocks, the lifecycle of an SQL statement can be divided into three phases: query parsing, query planning, and query execution. Query parsing is generally not a bottleneck because the required QPS of analytical workloads is not high.
|
||||
|
||||
Query performance in StarRocks is determined by query planning and query execution. Query planning is responsible for coordinating operators (Join/Order/Aggregate), and query execution is responsible for running specific operations.
|
||||
|
||||
A query plan provides the DBA with a macro perspective to access query information. A query plan is the key to query performance and a good resource for the DBA to reference. The following code snippet uses `TPCDS query96` as an example to show how to view a query plan.
|
||||
|
||||
Use the [EXPLAIN](../sql-reference/sql-statements/cluster-management/plan_profile/EXPLAIN.md) statement to view the plan of a query.
|
||||
|
||||
```SQL
|
||||
EXPLAIN select count(*)
|
||||
from store_sales
|
||||
,household_demographics
|
||||
,time_dim
|
||||
, store
|
||||
where ss_sold_time_sk = time_dim.t_time_sk
|
||||
and ss_hdemo_sk = household_demographics.hd_demo_sk
|
||||
and ss_store_sk = s_store_sk
|
||||
and time_dim.t_hour = 8
|
||||
and time_dim.t_minute >= 30
|
||||
and household_demographics.hd_dep_count = 5
|
||||
and store.s_store_name = 'ese'
|
||||
order by count(*) limit 100;
|
||||
```
|
||||
|
||||
There are two types of query plans–logical query plan and physical query plan. The query plan described here refers to the logical query plan. The query plan corresponding to `TPCDS query96.sq`l is shown below.
|
||||
|
||||
```sql
|
||||
+------------------------------------------------------------------------------+
|
||||
| Explain String |
|
||||
+------------------------------------------------------------------------------+
|
||||
| PLAN FRAGMENT 0 |
|
||||
| OUTPUT EXPRS:<slot 11> |
|
||||
| PARTITION: UNPARTITIONED |
|
||||
| RESULT SINK |
|
||||
| 12:MERGING-EXCHANGE |
|
||||
| limit: 100 |
|
||||
| tuple ids: 5 |
|
||||
| |
|
||||
| PLAN FRAGMENT 1 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 12 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 8:TOP-N |
|
||||
| | order by: <slot 11> ASC |
|
||||
| | offset: 0 |
|
||||
| | limit: 100 |
|
||||
| | tuple ids: 5 |
|
||||
| | |
|
||||
| 7:AGGREGATE (update finalize) |
|
||||
| | output: count(*) |
|
||||
| | group by: |
|
||||
| | tuple ids: 4 |
|
||||
| | |
|
||||
| 6:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: left hash join node can not do colocate |
|
||||
| | equal join conjunct: `ss_store_sk` = `s_store_sk` |
|
||||
| | tuple ids: 0 2 1 3 |
|
||||
| | |
|
||||
| |----11:EXCHANGE |
|
||||
| | tuple ids: 3 |
|
||||
| | |
|
||||
| 4:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: left hash join node can not do colocate |
|
||||
| | equal join conjunct: `ss_hdemo_sk`=`household_demographics`.`hd_demo_sk`|
|
||||
| | tuple ids: 0 2 1 |
|
||||
| | |
|
||||
| |----10:EXCHANGE |
|
||||
| | tuple ids: 1 |
|
||||
| | |
|
||||
| 2:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: table not in same group |
|
||||
| | equal join conjunct: `ss_sold_time_sk` = `time_dim`.`t_time_sk` |
|
||||
| | tuple ids: 0 2 |
|
||||
| | |
|
||||
| |----9:EXCHANGE |
|
||||
| | tuple ids: 2 |
|
||||
| | |
|
||||
| 0:OlapScanNode |
|
||||
| TABLE: store_sales |
|
||||
| PREAGGREGATION: OFF. Reason: `ss_sold_time_sk` is value column |
|
||||
| partitions=1/1 |
|
||||
| rollup: store_sales |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 0 |
|
||||
| |
|
||||
| PLAN FRAGMENT 2 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 11 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 5:OlapScanNode |
|
||||
| TABLE: store |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `store`.`s_store_name` = 'ese' |
|
||||
| partitions=1/1 |
|
||||
| rollup: store |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 3 |
|
||||
| |
|
||||
| PLAN FRAGMENT 3 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 10 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 3:OlapScanNode |
|
||||
| TABLE: household_demographics |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `household_demographics`.`hd_dep_count` = 5 |
|
||||
| partitions=1/1 |
|
||||
| rollup: household_demographics |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 1 |
|
||||
| |
|
||||
| PLAN FRAGMENT 4 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 09 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 1:OlapScanNode |
|
||||
| TABLE: time_dim |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `time_dim`.`t_hour` = 8, `time_dim`.`t_minute` >= 30 |
|
||||
| partitions=1/1 |
|
||||
| rollup: time_dim |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 2 |
|
||||
+------------------------------------------------------------------------------+
|
||||
128 rows in set (0.02 sec)
|
||||
```
|
||||
|
||||
Query 96 shows a query plan that involves several StarRocks concepts.
|
||||
|
||||
|Name|Explanation|
|
||||
|--|--|
|
||||
|avgRowSize|The average size of the scanned data rows|
|
||||
|cardinality|The total number of data rows in the scanned table|
|
||||
|colocate|Whether the table is in colocate mode|
|
||||
|numNodes|The number of nodes to be scanned|
|
||||
|rollup|Materialized view|
|
||||
|preaggregation|Pre-aggregation|
|
||||
|predicates|Predicates, the query filters|
|
||||
|
||||
The query plan of Query 96 is divided into five fragments, numbered from 0 to 4. The query plan can be read one by one in a bottom-up manner.
|
||||
|
||||
Fragment 4 is responsible for scanning the `time_dim` table and executing the related query condition (i.e. `time_dim.t_hour = 8 and time_dim.t_minute >= 30`) in advance. This step is also known as predicate pushdown. StarRocks decides whether to enable `PREAGGREGATION` for aggregation tables. In the previous figure, preaggregation of `time_dim` is disabled. In this case, all dimension columns of `time_dim` are read, which may negatively affect performance if there are many dimension columns in the table. If the `time_dim` table selects `range partition` for data division, several partitions will be hit in the query plan and irrelevant partitions will be automatically filtered out. If there is a materialized view, StarRocks will automatically select the materialized view based on the query. If there is no materialized view, the query will automatically hit the base table (for example, `rollup: time_dim` in the previous figure).
|
||||
|
||||
When the scan is complete, Fragment 4 ends. Data will be passed to other fragments, as indicated by EXCHANGE ID : 09 in the previous figure, to the receiving node labeled 9.
|
||||
|
||||
For the query plan of Query 96, Fragment 2, 3, and 4 have similar functions but they are responsible for scanning different tables. Specifically, the `Order/Aggregation/Join` operations in the query are performed in Fragment 1.
|
||||
|
||||
Fragment 1 uses the `BROADCAST` method to perform `Order/Aggregation/Join` operations i, that is, to broadcast the small table to the large table. If both tables are large, we recommend that you use the `SHUFFLE` method. Currently, StarRocks only supports `HASH JOIN`. The `colocate` field is used to show that the two joined tables are partitioned and bucketed in the same way, so that the join operation can be performed locally without migrating the data. When the Join operation is complete, the upper-level `aggregation`, `order by`, and `top-n` operations will be performed.
|
||||
|
||||
By removing the specific expressions (only keep the operators), the query plan can be presented in a more macroscopic view, as shown in the following figure.
|
||||
|
||||

|
||||
|
||||
## Query hint
|
||||
|
||||
Query hints are directives or comments that explicitly suggest the query optimizer on how to execute a query. Currently, StarRocks supports three types of hints: system variable hint (`SET_VAR`), user-defined variable hint (`SET_USER_VARIABLE`), and Join hint. Hints only take effect within a single query.
|
||||
|
||||
### System variable hint
|
||||
|
||||
You can use a `SET_VAR` hint to set one or more [system variables](../sql-reference/System_variable.md) in SELECT and SUBMIT TASK statements, and then execute the statements. You can also use a `SET_VAR` hint in the SELECT clause included in other statements, such as CREATE MATERIALIZED VIEW AS SELECT and CREATE VIEW AS SELECT. Note that if the `SET_VAR` hint is used in the SELECT clause of CTE, the `SET_VAR` hint does not take effect even if the statement is executed successfully.
|
||||
|
||||
Compared with [the general usage of system variables](../sql-reference/System_variable.md) which takes effect at the session level, the `SET_VAR` hint takes effect at the statement level and does not impact the entire session.
|
||||
|
||||
#### Syntax
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_VAR(key=value [, key = value]) */ ...
|
||||
SUBMIT [/*+ SET_VAR(key=value [, key = value]) */] TASK ...
|
||||
```
|
||||
|
||||
#### Examples
|
||||
|
||||
To specify the aggregation mode for an aggregate query, use the `SET_VAR` hint to set the system variables `streaming_preaggregation_mode` and `new_planner_agg_stage` in the aggregate query.
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_VAR (streaming_preaggregation_mode = 'force_streaming',new_planner_agg_stage = '2') */ SUM(sales_amount) AS total_sales_amount FROM sales_orders;
|
||||
```
|
||||
|
||||
To specify the execution timeout for a SUBMIT TASK statement, use the `SET_VAR` Hint to set the system variable `insert_timeout` in the SUBMIT TASK statement.
|
||||
|
||||
|
||||
```SQL
|
||||
SUBMIT /*+ SET_VAR(insert_timeout=3) */ TASK AS CREATE TABLE temp AS SELECT count(*) AS cnt FROM tbl1;
|
||||
```
|
||||
|
||||
To specify the subquery execution timeout for creating a materialized view, use the `SET_VAR` hint to set the system variable `query_timeout` in the SELECT clause.
|
||||
|
||||
```SQL
|
||||
CREATE MATERIALIZED VIEW mv
|
||||
PARTITION BY dt
|
||||
DISTRIBUTED BY HASH(`key`)
|
||||
BUCKETS 10
|
||||
REFRESH ASYNC
|
||||
AS SELECT /*+ SET_VAR(query_timeout=500) */ * from dual;
|
||||
```
|
||||
|
||||
### User-defined variable hint
|
||||
|
||||
You can use a `SET_USER_VARIABLE` hint to set one or more [user-defined variables](../sql-reference/user_defined_variables.md) in the SELECT statements or INSERT statements. If other statements contain a SELECT clause, you can also use the `SET_USER_VARIABLE` hint in that SELECT clause. Other statements can be SELECT statements and INSERT statements, but cannot be CREATE MATERIALIZED VIEW AS SELECT statements and CREATE VIEW AS SELECT statements. Note that if the `SET_USER_VARIABLE` hint is used in the SELECT clause of CTE, the `SET_USER_VARIABLE` hint does not take effect even if the statement is executed successfully. Since v3.2.4, StarRocks supports the user-defined variable hint.
|
||||
|
||||
Compared with [the general usage of user-defined variables](../sql-reference/user_defined_variables.md) which takes effect at the session level, the `SET_USER_VARIABLE` hint takes effect at the statement level and does not impact the entire session.
|
||||
|
||||
#### Syntax
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
INSERT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
```
|
||||
|
||||
#### Examples
|
||||
|
||||
The following SELECT statement references scalar subqueries `select max(age) from users` and `select min(name) from users`, so you can use a `SET_USER_VARIABLE` hint to set these two scalar subqueries as user-defined variables and then run the query.
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_USER_VARIABLE (@a = (select max(age) from users), @b = (select min(name) from users)) */ * FROM sales_orders where sales_orders.age = @a and sales_orders.name = @b;
|
||||
```
|
||||
|
||||
### Join hint
|
||||
|
||||
For multi-table Join queries, the optimizer usually selects the optimal Join execution method. In special cases, you can use a Join hint to explicitly suggest the Join execution method to the optimizer or disable Join Reorder. Currently, a Join hint supports suggesting Shuffle Join, Broadcast Join, Bucket Shuffle Join, or Colocate Join as a Join execution method. When a Join hint is used, the optimizer does not perform Join Reorder. So you need to select the smaller table as the right table. Additionally, when suggesting [Colocate Join](../using_starrocks/Colocate_join.md) or Bucket Shuffle Join as the Join execution method, make sure that the data distribution of the joined table meets the requirements of these Join execution methods. Otherwise, the suggested Join execution method cannot take effect.
|
||||
|
||||
#### Syntax
|
||||
|
||||
```SQL
|
||||
... JOIN { [BROADCAST] | [SHUFFLE] | [BUCKET] | [COLOCATE] | [UNREORDER]} ...
|
||||
```
|
||||
|
||||
:::note
|
||||
Join Hint is case-insensitive.
|
||||
:::
|
||||
|
||||
#### Examples
|
||||
|
||||
- Shuffle Join
|
||||
|
||||
If you need to shuffle the data rows with the same bucketing key values from tables A and B onto the same machine before a Join operation is performed, you can hint the Join execution method as Shuffle Join.
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [SHUFFLE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Broadcast Join
|
||||
|
||||
If table A is a large table and table B is a small table, you can hint the Join execution method as Broadcast Join. The data of the table B is fully broadcasted to the machines on which the data of table A resides, and then the Join operation is performed. Compared to Shuffle Join, Broadcast Join saves the cost of shuffling the data of table A.
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BROADCAST] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Bucket Shuffle Join
|
||||
|
||||
If the Join equijoin expression in the Join query contains the bucketing key of table A, especially when both tables A and B are large tables, you can hint the Join execution method as Bucket Shuffle Join. The data of table B is shuffled to the machines on which the data of table A resides, according to the data distribution of table A, and then the Join operation is performed. Compared to Broadcast Join, Bucket Shuffle Join significantly reduces data transferring because the data of table B is shuffled only once globally.
|
||||
Tables participating in Bucket Shuffle Join must be either non-partitioned or colocated.
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BUCKET] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Colocate Join
|
||||
|
||||
If tables A and B belong to the same Colocation Group which is specified during table creation, the data rows with the same bucketing key values from tables A and B are distributed on the same BE node. When the Join equijoin expression contains the bucketing key of tables A and B in the Join query, you can hint the Join execution method as Colocate Join. Data with the same key values are directly joined locally, reducing the time spent on data transmission between nodes and improving query performance.
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
#### View Join execution method
|
||||
|
||||
Use the `EXPLAIN` command to view the actual Join execution method. If the returned result shows that the Join execution method matches the Join hint, it means that the Join hint is effective.
|
||||
|
||||
```SQL
|
||||
EXPLAIN select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||

|
||||
|
||||
## SQL fingerprint
|
||||
|
||||
SQL fingerprint is used to optimize slow queries and improve system resource utilization. StarRocks uses the SQL fingerprint feature to normalize SQL statements in the slow query log (`fe.audit.log.slow_query`), categorizes the SQL statements into different types, and calculates the MD5 hash value of each SQL type to identify slow queries. The MD5 hash value is specified by the field `Digest`.
|
||||
|
||||
```SQL
|
||||
2021-12-27 15:13:39,108 [slow_query] |Client=172.26.xx.xxx:54956|User=root|Db=default_cluster:test|State=EOF|Time=2469|ScanBytes=0|ScanRows=0|ReturnRows=6|StmtId=3|QueryId=824d8dc0-66e4-11ec-9fdc-00163e04d4c2|IsQuery=true|feIp=172.26.92.195|Stmt=select count(*) from test_basic group by id_bigint|Digest=51390da6b57461f571f0712d527320f4
|
||||
```
|
||||
|
||||
SQL statement normalization transforms a statement text into a more normalized format and preserves only important statement structure.
|
||||
|
||||
- Preserves object identifiers, such as database and table names.
|
||||
|
||||
- Converts constants into a question mark (?).
|
||||
|
||||
- Deletes comments and formats spaces.
|
||||
|
||||
For example, the following two SQL statements belong to the same type after normalization.
|
||||
|
||||
- SQL statements before normalization
|
||||
|
||||
```SQL
|
||||
SELECT * FROM orders WHERE customer_id=10 AND quantity>20
|
||||
|
||||
|
||||
|
||||
SELECT * FROM orders WHERE customer_id = 20 AND quantity > 100
|
||||
```
|
||||
|
||||
- SQL statement after normalization
|
||||
|
||||
```SQL
|
||||
SELECT * FROM orders WHERE customer_id=? AND quantity>?
|
||||
```
|
||||
|
|
@ -97,7 +97,7 @@ After a partition is created, you can move on to the next step.
|
|||
- `user`: your cluster username. You MUST have the privilege to load data (LOAD_PRIV) into the table.
|
||||
- `password`: your user password.
|
||||
- `secret_key`: the key (string, must not be longer than 16 bytes) used to encrypt the password. If this parameter is not set, it indicates that the password in **plugin.conf** will not be encrypted, and you only need to specify the plaintext password in `password`. If this parameter is specified, it indicates that the password is encrypted by this key, and you need to specify the encrypted string in `password`. The encrypted password can be generated in StarRocks using the `AES_ENCRYPT` function: `SELECT TO_BASE64(AES_ENCRYPT('password','secret_key'));`.
|
||||
- `enable_compute_all_query_digest`: whether to generate Hash SQL fingerprint for all queries (StarRocks only enable SQL fingerprint for slow queries by default). Note that the fingerprint calculation in the plugin is different from that of FE, which will [normalize the SQL statement](../Query_planning.md#sql-fingerprint), while the plugin does not. The fingerprint calculation will consume additional computing resources if this feature is enabled.
|
||||
- `enable_compute_all_query_digest`: whether to generate Hash SQL fingerprint for all queries (StarRocks only enable SQL fingerprint for slow queries by default). Note that the fingerprint calculation in the plugin is different from that of FE, which will [normalize the SQL statement](../../best_practices/query_tuning/query_planning.md#sql-fingerprint), while the plugin does not. The fingerprint calculation will consume additional computing resources if this feature is enabled.
|
||||
- `filter`: the filter conditions for audit log loading. This parameter is based on the [WHERE parameter](../../sql-reference/sql-statements/loading_unloading/STREAM_LOAD.md#opt_properties) in Stream Load, i.e. `-H “where: <condition>”`, defaults to an empty string. Example: `filter=isQuery=1 and clientIp like '127.0.0.1%' and user='root'`.
|
||||
|
||||
4. Zip the files back into a package.
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
keywords: ['profile', 'query']
|
||||
---
|
||||
|
||||
# Query Profile Overview
|
||||
|
||||
This topic introduces how to view and analyze the Query Profile. The Query Profile records execution information for all working nodes involved in a query. You can quickly identify bottlenecks affecting the query performance through Query Profile.
|
||||
|
||||
From v3.3.0 onwards, StarRocks supports providing Query Profile for data loading with INSERT INTO FILES() and Broker Load. For details of the metrics involved, see [OlapTableSink Operator](./query_profile_details.md#olaptablesink-operator).
|
||||
|
||||
## Enable Query Profile
|
||||
|
||||
You can enable Query Profile by setting the variable `enable_profile` to `true`:
|
||||
|
||||
```SQL
|
||||
SET enable_profile = true;
|
||||
```
|
||||
|
||||
### Enable Query Profile for Slow Queries
|
||||
|
||||
It is not recommended to enable Query Profile in a production environment on a global, long-term basis. This is because the data collection and processing of Query Profile may impose additional burdens on the system. However, if you need to capture and analyze slow queries, you can enable Query Profile only for slow queries. This can be achieved by setting the variable `big_query_profile_threshold` to a time duration greater than `0s`. For example, if this variable is set to `30s`, it means that only queries with an execution time exceeding 30 seconds will trigger Query Profile. This ensures system performance while effectively monitoring slow queries.
|
||||
|
||||
```SQL
|
||||
-- 30 seconds
|
||||
SET global big_query_profile_threshold = '30s';
|
||||
|
||||
-- 500 milliseconds
|
||||
SET global big_query_profile_threshold = '500ms';
|
||||
|
||||
-- 60 minutes
|
||||
SET global big_query_profile_threshold = '60m';
|
||||
```
|
||||
|
||||
### Enable Runtime Query Profile
|
||||
|
||||
Some queries may take a long time to execute, ranging from seconds to hours. Often, it is challenging to determine whether a query is still in progress or the system has crashed before the query completes. To address this issue, StarRocks introduced the Runtime Query Profile feature in v3.1 and later. This feature allows you to collect and report Query Profile data at fixed time intervals during query execution. This gives you the insight into the query's execution progress and potential bottlenecks in real-time, without waiting for the query to finish. In this way, you can monitor and optimize the query process more effectively.
|
||||
|
||||
When Query Profile is enabled, this feature is automatically activated, with a default reporting interval of 10 seconds. You can adjust the interval by modifying the variable `runtime_profile_report_interval`:
|
||||
|
||||
```SQL
|
||||
SET runtime_profile_report_interval = 30;
|
||||
```
|
||||
|
||||
Runtime Query Profile has the same format and content as regular Query Profile. You can analyze Runtime Query Profile just like analyzing regular Query Profile to understand the performance metrics of queries running in the cluster.
|
||||
|
||||
### Configure Query Profile Behavior
|
||||
|
||||
The configuration settings are either session variables or FE dynamic configuration items.
|
||||
|
||||
#### Session Variables
|
||||
|
||||
##### enable_profile
|
||||
|
||||
- **Valid values**: true/false
|
||||
- **Default value**: false
|
||||
- **Description**: Whether to enable Query Profile. `true` means to enable this feature.
|
||||
|
||||
|
||||
##### pipeline_profile_level
|
||||
|
||||
- **Valid values**: 1/2
|
||||
- **Default value**: 1
|
||||
- **Description**: Set the level of Query Profile. `1` indicates merging the metrics of the Query Profile; `2` indicates retaining the original structure of the Query Profile. If this item is set as `2`, all visualization analysis tools will no longer be applicable, therefore, it is generally not recommended to change this value.
|
||||
|
||||
|
||||
##### runtime_profile_report_interval
|
||||
|
||||
- **Valid values**: Positive integer
|
||||
- **Default value**: 10
|
||||
- **Description**: The report interval of Runtime Query Profile. Unit: seconds.
|
||||
|
||||
|
||||
##### big_query_profile_threshold
|
||||
|
||||
- **Valid values**: String
|
||||
- **Default value**: `0s`
|
||||
- **Description**: If the execution time of a big query exceeds this value, Query Profile is automatically enabled for this query. Setting this item to `0s` indicates this feature is disabled. Its value can be represented by a integral number followed by a unit, where the units can be `ms`, `s`, `m`.
|
||||
|
||||
|
||||
#### FE Dynamic Configuration Items
|
||||
|
||||
##### enable_statistics_collect_profile
|
||||
|
||||
- **Valid values**: true/false
|
||||
- **Default value**: false
|
||||
- **Description**: Whether to enable Query Profile for statistics collection-related queries. `true` means to enable this feature.
|
||||
|
||||
##### profile_info_format
|
||||
|
||||
- **Valid values**: default/json
|
||||
- **Default value**: default
|
||||
- **Description**: The format of the Profile output by the system. When set to `default`, Profile is of the default format. When set to `json`, the system outputs Profile in JSON format.
|
||||
|
||||
### Obtain Query Profile via Web UI
|
||||
|
||||
Follow these steps to obtain Query Profile:
|
||||
|
||||
1. Access `http://<fe_ip>:<fe_http_port>` in your browser.
|
||||
2. On the page that appears, click **queries** in the top navigation.
|
||||
3. In the **Finished Queries** list, select the query you want to analyze and click the link in the **Profile** column.
|
||||
|
||||

|
||||
|
||||
You will be redirected to the detailed page of the selected Query Profile.
|
||||
|
||||

|
||||
|
||||
### Obtain Query Profile via get_query_profile
|
||||
|
||||
The following example shows how to obtain Query Profile via the function get_query_profile:
|
||||
|
||||
```sql
|
||||
-- Enable the profiling feature.
|
||||
set enable_profile = true;
|
||||
-- Run a simple query.
|
||||
select 1;
|
||||
-- Get the query_id of the query.
|
||||
select last_query_id();
|
||||
+--------------------------------------+
|
||||
| last_query_id() |
|
||||
+--------------------------------------+
|
||||
| bd3335ce-8dde-11ee-92e4-3269eb8da7d1 |
|
||||
+--------------------------------------+
|
||||
-- Obtain the query profile.
|
||||
select get_query_profile('502f3c04-8f5c-11ee-a41f-b22a2c00f66b')\G
|
||||
```
|
||||
|
||||
## Analyze Query Profile
|
||||
|
||||
The raw content generated by Query Profile may contain numerous metrics. For detailed description of these metrics, see [Query Profile Structure and Detailed Metrics](./query_profile_details.md).
|
||||
|
||||
However, most users may find that it is not easy to analyze this raw text directly. To address this issue, StarRocks provides a [Text-based Query Profile Visualized Analysis](./query_profile_text_based_analysis.md) method. You can use this feature to gain a more intuitive understanding of the complex Query Profile.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
label: Query Tuning
|
||||
position: 200
|
||||
collapsed: true
|
||||
link:
|
||||
type: generated-index
|
||||
title: Query Tuning Best Practices
|
||||
description: Learn how to analyze, tune, and optimize queries in StarRocks.
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 70
|
||||
---
|
||||
|
||||
# Query Hint
|
||||
|
||||
Query hints are directives or comments that explicitly suggest the query optimizer on how to execute a query. Currently, StarRocks supports three types of hints: system variable hint (`SET_VAR`), user-defined variable hint (`SET_USER_VARIABLE`), and Join hint. Hints only take effect within a single query.
|
||||
|
||||
## System variable hint
|
||||
|
||||
You can use a `SET_VAR` hint to set one or more [system variables](../../sql-reference/System_variable.md) in SELECT and SUBMIT TASK statements, and then execute the statements. You can also use a `SET_VAR` hint in the SELECT clause included in other statements, such as CREATE MATERIALIZED VIEW AS SELECT and CREATE VIEW AS SELECT. Note that if the `SET_VAR` hint is used in the SELECT clause of CTE, the `SET_VAR` hint does not take effect even if the statement is executed successfully.
|
||||
|
||||
Compared with [the general usage of system variables](../../sql-reference/System_variable.md) which takes effect at the session level, the `SET_VAR` hint takes effect at the statement level and does not impact the entire session.
|
||||
|
||||
### Syntax
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_VAR(key=value [, key = value]) */ ...
|
||||
SUBMIT [/*+ SET_VAR(key=value [, key = value]) */] TASK ...
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
To specify the aggregation mode for an aggregate query, use the `SET_VAR` hint to set the system variables `streaming_preaggregation_mode` and `new_planner_agg_stage` in the aggregate query.
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_VAR (streaming_preaggregation_mode = 'force_streaming',new_planner_agg_stage = '2') */ SUM(sales_amount) AS total_sales_amount FROM sales_orders;
|
||||
```
|
||||
|
||||
To specify the execution timeout for a SUBMIT TASK statement, use the `SET_VAR` Hint to set the system variable `insert_timeout` in the SUBMIT TASK statement.
|
||||
|
||||
```SQL
|
||||
SUBMIT /*+ SET_VAR(insert_timeout=3) */ TASK AS CREATE TABLE temp AS SELECT count(*) AS cnt FROM tbl1;
|
||||
```
|
||||
|
||||
To specify the subquery execution timeout for creating a materialized view, use the `SET_VAR` hint to set the system variable `query_timeout` in the SELECT clause.
|
||||
|
||||
```SQL
|
||||
CREATE MATERIALIZED VIEW mv
|
||||
PARTITION BY dt
|
||||
DISTRIBUTED BY HASH(`key`)
|
||||
BUCKETS 10
|
||||
REFRESH ASYNC
|
||||
AS SELECT /*+ SET_VAR(query_timeout=500) */ * from dual;
|
||||
```
|
||||
|
||||
## User-defined variable hint
|
||||
|
||||
You can use a `SET_USER_VARIABLE` hint to set one or more [user-defined variables](../../sql-reference/user_defined_variables.md) in the SELECT statements or INSERT statements. If other statements contain a SELECT clause, you can also use the `SET_USER_VARIABLE` hint in that SELECT clause. Other statements can be SELECT statements and INSERT statements, but cannot be CREATE MATERIALIZED VIEW AS SELECT statements and CREATE VIEW AS SELECT statements. Note that if the `SET_USER_VARIABLE` hint is used in the SELECT clause of CTE, the `SET_USER_VARIABLE` hint does not take effect even if the statement is executed successfully. Since v3.2.4, StarRocks supports the user-defined variable hint.
|
||||
|
||||
Compared with [the general usage of user-defined variables](../../sql-reference/user_defined_variables.md) which takes effect at the session level, the `SET_USER_VARIABLE` hint takes effect at the statement level and does not impact the entire session.
|
||||
|
||||
### Syntax
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
INSERT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
The following SELECT statement references scalar subqueries `select max(age) from users` and `select min(name) from users`, so you can use a `SET_USER_VARIABLE` hint to set these two scalar subqueries as user-defined variables and then run the query.
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_USER_VARIABLE (@a = (select max(age) from users), @b = (select min(name) from users)) */ * FROM sales_orders where sales_orders.age = @a and sales_orders.name = @b;
|
||||
```
|
||||
|
||||
## Join hint
|
||||
|
||||
For multi-table Join queries, the optimizer usually selects the optimal Join execution method. In special cases, you can use a Join hint to explicitly suggest the Join execution method to the optimizer or disable Join Reorder. Currently, a Join hint supports suggesting Shuffle Join, Broadcast Join, Bucket Shuffle Join, or Colocate Join as a Join execution method. When a Join hint is used, the optimizer does not perform Join Reorder. So you need to select the smaller table as the right table. Additionally, when suggesting [Colocate Join](../../using_starrocks/Colocate_join.md) or Bucket Shuffle Join as the Join execution method, make sure that the data distribution of the joined table meets the requirements of these Join execution methods. Otherwise, the suggested Join execution method cannot take effect.
|
||||
|
||||
### Syntax
|
||||
|
||||
```SQL
|
||||
... JOIN { [BROADCAST] | [SHUFFLE] | [BUCKET] | [COLOCATE] | [UNREORDER]} ...
|
||||
```
|
||||
|
||||
:::note
|
||||
Join Hint is case-insensitive.
|
||||
:::
|
||||
|
||||
### Examples
|
||||
|
||||
- Shuffle Join
|
||||
|
||||
If you need to shuffle the data rows with the same bucketing key values from tables A and B onto the same machine before a Join operation is performed, you can hint the Join execution method as Shuffle Join.
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [SHUFFLE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Broadcast Join
|
||||
|
||||
If table A is a large table and table B is a small table, you can hint the Join execution method as Broadcast Join. The data of the table B is fully broadcasted to the machines on which the data of table A resides, and then the Join operation is performed. Compared to Shuffle Join, Broadcast Join saves the cost of shuffling the data of table A.
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BROADCAST] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Bucket Shuffle Join
|
||||
|
||||
If the Join equijoin expression in the Join query contains the bucketing key of table A, especially when both tables A and B are large tables, you can hint the Join execution method as Bucket Shuffle Join. The data of table B is shuffled to the machines on which the data of table A resides, according to the data distribution of table A, and then the Join operation is performed. Compared to Broadcast Join, Bucket Shuffle Join significantly reduces data transferring because the data of table B is shuffled only once globally.
|
||||
Tables participating in Bucket Shuffle Join must be either non-partitioned or colocated.
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BUCKET] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Colocate Join
|
||||
|
||||
If tables A and B belong to the same Colocation Group which is specified during table creation, the data rows with the same bucketing key values from tables A and B are distributed on the same BE node. When the Join equijoin expression contains the bucketing key of tables A and B in the Join query, you can hint the Join execution method as Colocate Join. Data with the same key values are directly joined locally, reducing the time spent on data transmission between nodes and improving query performance.
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
### View Join execution method
|
||||
|
||||
Use the `EXPLAIN` command to view the actual Join execution method. If the returned result shows that the Join execution method matches the Join hint, it means that the Join hint is effective.
|
||||
|
||||
```SQL
|
||||
EXPLAIN select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
# Introduction to Query Tuning
|
||||
|
||||
Query tuning is essential for achieving high performance and reliability in StarRocks. This directory brings together practical guides, reference materials, and actionable recipes to help you analyze, diagnose, and optimize query performance at every stage—from writing SQL to interpreting execution details.
|
||||
|
||||
|
||||
Effective query tuning in StarRocks typically follows a top-down process:
|
||||
|
||||
1. **Identify the Problem**
|
||||
- Detect slow queries, high resource usage, or unexpected results.
|
||||
- In StarRocks, leverage built-in monitoring tools, query history, and audit logs to quickly identify problematic queries or unusual patterns.
|
||||
- See: **[Query Tuning Recipes](./query_profile_tuning_recipes.md)** for symptom-driven diagnosis and **[Query Profile Overview](./query_profile_overview.md)** for accessing query history and profiles.
|
||||
|
||||
2. **Collect and Analyze Execution Information**
|
||||
- Obtain the query plan using `EXPLAIN` or `EXPLAIN ANALYZE`.
|
||||
- Enable and review the Query Profile to gather detailed execution metrics.
|
||||
- See: **[Query Plan Overview](./query_planning.md)** for understanding query plans, **[Explain Analyze & Text-Based Profile Analysis](./query_profile_text_based_analysis.md)** for step-by-step analysis, and **[Query Profile Overview](./query_profile_overview.md)** for enabling and interpreting profiles.
|
||||
|
||||
3. **Locate the Root Cause**
|
||||
- Pinpoint which stage or operator is consuming the most time or resources.
|
||||
- Check for common issues: suboptimal join order, missing indexes, data distribution problems, or inefficient SQL patterns.
|
||||
- See: **[Query Profile Metrics](./query_profile_operator_metrics.md)** for a glossary of metrics and operators, and **[Query Tuning Recipes](./query_profile_tuning_recipes.md)** for root cause analysis.
|
||||
|
||||
4. **Apply Tuning Strategies**
|
||||
- SQL Rewrite: rewrite or optimize the SQL query (e.g., add filters, avoid SELECT *).
|
||||
- Schema tuning: add indexes, change table types, partitioning, clustering.
|
||||
- Query plan tuning: use hints or variables to guide the optimizer if necessary.
|
||||
- Execution tuning: tune session variables for specific workloads.
|
||||
- See: **[Schema Tuning Recipes](./schema_tuning.md)** for schema-level optimizations, **[Query Hint](./query_hint.md)** for optimizer hints, and **[Query Tuning Recipes](./query_profile_tuning_recipes.md)** for plan tuning and execution tuning.
|
||||
|
||||
5. **Validate and Iterate**
|
||||
- Rerun the query and compare performance before and after changes.
|
||||
- Review the new query plan and profile to ensure improvements.
|
||||
- Repeat the process as needed for further optimization.
|
||||
|
||||
|
||||
Whether you're a DBA, developer, or data engineer, these resources will help you:
|
||||
- Diagnose and resolve slow or resource-intensive queries
|
||||
- Understand optimizer choices and execution details
|
||||
- Apply best practices and advanced tuning strategies
|
||||
|
||||
Start with the overview, dive into the references as needed, and use the recipes and tips to solve real-world performance challenges in StarRocks.
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 20
|
||||
---
|
||||
|
||||
# Query Plan
|
||||
|
||||
Optimizing query performance is a common challenge in analytics systems. Slow queries can impair user experience and overall cluster performance. In StarRocks, understanding and interpreting query plans and query profiles is the foundation for diagnosing and improving slow queries. These tools help you:
|
||||
- Identify bottlenecks and expensive operations
|
||||
- Spot suboptimal join strategies or missing indexes
|
||||
- Understand how data is filtered, aggregated, and moved
|
||||
- Troubleshoot and optimize resource usage
|
||||
|
||||
A **query plan** is a detailed roadmap generated by the StarRocks FE that describes how your SQL statement will be executed. It breaks down the query into a series of operations—such as scans, joins, aggregations, and sorts—and determines the most efficient way to perform them.
|
||||
|
||||
StarRocks provides several ways to inspect the query plan:
|
||||
|
||||
1. **EXPLAIN statement**:
|
||||
Use `EXPLAIN` to display the logical or physical execution plan for a query. You can add options to control the output:
|
||||
- `EXPLAIN LOGICAL <query>`: Shows the simplified plan.
|
||||
- `EXPLAIN <query>`: Shows the basic phyical plan
|
||||
- `EXPLAIN VERBOSE <query>`: Shows the physical plan with detailed information.
|
||||
- `EXPLAIN COSTS <query>`: Includes estimated costs for each operation, which is used to diagnose the statistics issue
|
||||
|
||||
2. **EXPLAIN ANALYZE**:
|
||||
Use `EXPLAIN ANALYZE <query>` to execute the query and display the actual execution plan along with real runtime statistics. See the [Explain Anlayze](./query_profile_text_based_analysis.md) documentation for details.
|
||||
|
||||
Example:
|
||||
```sql
|
||||
EXPLAIN ANALYZE SELECT * FROM sales_orders WHERE amount > 1000;
|
||||
```
|
||||
|
||||
3. **Query Profile**:
|
||||
After running a query, you can view its detailed execution profile, which includes timing, resource usage, and operator-level statistics. See the [Query Profile](./query_profile_overview.md) documentation for how to access and interpret this information.
|
||||
- **SQL commands**: `SHOW PROFILELIST` and `ANALYZE PROFILE FOR <query_id>`: can be used to retrieval the execution profile for a specific query.
|
||||
- **FE HTTP Service**: Access query profiles via the StarRocks FE web UI by navigating to the **Query** or **Profile** section, where you can search for and inspect query execution details.
|
||||
- **Managed Version**: In cloud or managed deployments, use the provided web console or monitoring dashboard to view query plans and profiles, often with enhanced visualization and filtering options.
|
||||
|
||||
|
||||
Typically, the query plan is used to diagnose issues related to how a query is planned and optimized, while the query profile helps identify performance problems during query execution. In the following sections, we'll explore the key concepts of query execution and walk through a concrete example of analyzing a query plan.
|
||||
|
||||
|
||||
## Query Execution Flow
|
||||
The lifecycle of a query in StarRocks consists of three main phases:
|
||||
1. **Planning**: The query undergoes parsing, analysis, and optimization, culminating in the generation of a query plan.
|
||||
2. **Scheduling**: The scheduler and coordinator distribute the plan to all participating backend nodes.
|
||||
3. **Execution**: The plan is executed using the pipeline execution engine.
|
||||
|
||||

|
||||
|
||||
**Plan Structure**
|
||||
|
||||
The StarRocks plan is hierarchical:
|
||||
- **Fragment**: Top-level slice of work; each fragment spawns multiple **FragmentInstances** that run on different backend nodes.
|
||||
- **Pipeline**: Within an instance, a pipeline strings operators together; several **PipelineDrivers** run the same pipeline concurrently on separate CPU cores.
|
||||
- **Operator**: The atomic step—scan, join, aggregate—that actually processes data.
|
||||
|
||||

|
||||
|
||||
**Pipeline Execution Engine**
|
||||
|
||||
The Pipeline Engine executes the query plan in a parallel and efficient manner, handling complex plans and large data volumes for high performance and scalability.
|
||||
|
||||

|
||||
|
||||
**Metric Merging Strategy**
|
||||
|
||||
By default, StarRocks merges the FragmentInstance and PipelineDriver layers to reduce profile volume, resulting in a simplified three-layer structure:
|
||||
- Fragment
|
||||
- Pipeline
|
||||
- Operator
|
||||
|
||||
You can control this merging behavior through the session variable `pipeline_profile_level`.
|
||||
|
||||
## Example
|
||||
|
||||
### How to Read a Query Plan and Profile
|
||||
|
||||
1. **Understand the structure**: Query plans are split into fragments, each representing a stage of execution. Read from the bottom up: scan nodes first, then joins, aggregations, and finally the result.
|
||||
|
||||
2. **Overall analysis**:
|
||||
- Check total runtime, memory usage, and CPU/wall time ratio.
|
||||
- Find slow operators by sorting by operator time.
|
||||
- Ensure filters are pushed down where possible.
|
||||
- Look for data skew (uneven operator times or row counts).
|
||||
- Monitor for high memory or disk spill; adjust join order or use rollup views if needed.
|
||||
- Use materialized views and query hints (`BROADCAST`, `SHUFFLE`, `COLOCATE`) to optimize as needed.
|
||||
|
||||
2. **Scan operations**: Look for `OlapScanNode` or similar. Note which tables are scanned, what filters are applied, and if pre-aggregation or materialized views are used.
|
||||
|
||||
3. **Join operations**: Identify join types (`HASH JOIN`, `BROADCAST`, `SHUFFLE`, `COLOCATE`, `BUCKET SHUFFLE`). The join method affects performance:
|
||||
- **Broadcast**: Small table sent to all nodes; good for small tables.
|
||||
- **Shuffle**: Rows are partitioned and shuffled; good for large tables.
|
||||
- **Colocate**: Tables partitioned the same way; enables local joins.
|
||||
- **Bucket Shuffle**: Only one table is shuffled to reduce network cost.
|
||||
|
||||
4. **Aggregation and sorting**: Look for `AGGREGATE`, `TOP-N`, or `ORDER BY`. These can be expensive with large or high-cardinality data.
|
||||
|
||||
5. **Data movement**: `EXCHANGE` nodes show data transfer between fragments or nodes. Too much data movement can hurt performance.
|
||||
|
||||
6. **Predicate pushdown**: Filters applied early (at scan) reduce downstream data. Check `PREDICATES` or `PushdownPredicates` to see which filters are pushed down.
|
||||
|
||||
|
||||
### Example Query Plan
|
||||
|
||||
```sql
|
||||
EXPLAIN select count(*)
|
||||
from store_sales
|
||||
,household_demographics
|
||||
,time_dim
|
||||
, store
|
||||
where ss_sold_time_sk = time_dim.t_time_sk
|
||||
and ss_hdemo_sk = household_demographics.hd_demo_sk
|
||||
and ss_store_sk = s_store_sk
|
||||
and time_dim.t_hour = 8
|
||||
and time_dim.t_minute >= 30
|
||||
and household_demographics.hd_dep_count = 5
|
||||
and store.s_store_name = 'ese'
|
||||
order by count(*) limit 100;
|
||||
```
|
||||
|
||||
The output is a hierarchical plan showing how StarRocks will execute the query, broken into fragments and operators. Here is a simplified example of a query plan fragment:
|
||||
|
||||
```
|
||||
PLAN FRAGMENT 1
|
||||
6:HASH JOIN (BROADCAST)
|
||||
|-- 4:HASH JOIN (BROADCAST)
|
||||
| |-- 2:HASH JOIN (BROADCAST)
|
||||
| | |-- 0:OlapScanNode (store_sales)
|
||||
| | |-- 1:OlapScanNode (time_dim)
|
||||
| |-- 3:OlapScanNode (household_demographics)
|
||||
|-- 5:OlapScanNode (store)
|
||||
```
|
||||
|
||||
- **OlapScanNode**: Scans a table, possibly with filters and pre-aggregation.
|
||||
- **HASH JOIN (BROADCAST)**: Joins two tables by broadcasting the smaller one.
|
||||
- **Fragments**: Each fragment can be executed in parallel on different nodes.
|
||||
|
||||
The query plan of Query 96 is divided into five fragments, numbered from 0 to 4. The query plan can be read one by one in a bottom-up manner.
|
||||
|
||||
Fragment 4 is responsible for scanning the `time_dim` table and executing the related query condition (i.e. `time_dim.t_hour = 8 and time_dim.t_minute >= 30`) in advance. This step is also known as predicate pushdown. StarRocks decides whether to enable `PREAGGREGATION` for aggregation tables. In the previous figure, preaggregation of `time_dim` is disabled. In this case, all dimension columns of `time_dim` are read, which may negatively affect performance if there are many dimension columns in the table. If the `time_dim` table selects `range partition` for data division, several partitions will be hit in the query plan and irrelevant partitions will be automatically filtered out. If there is a materialized view, StarRocks will automatically select the materialized view based on the query. If there is no materialized view, the query will automatically hit the base table (for example, `rollup: time_dim` in the previous figure).
|
||||
|
||||
When the scan is complete, Fragment 4 ends. Data will be passed to other fragments, as indicated by EXCHANGE ID : 09 in the previous figure, to the receiving node labeled 9.
|
||||
|
||||
For the query plan of Query 96, Fragment 2, 3, and 4 have similar functions but they are responsible for scanning different tables. Specifically, the `Order/Aggregation/Join` operations in the query are performed in Fragment 1.
|
||||
|
||||
Fragment 1 uses the `BROADCAST` method to perform `Order/Aggregation/Join` operations, that is, to broadcast the small table to the large table. If both tables are large, we recommend that you use the `SHUFFLE` method. Currently, StarRocks only supports `HASH JOIN`. The `colocate` field is used to show that the two joined tables are partitioned and bucketed in the same way, so that the join operation can be performed locally without migrating the data. When the Join operation is complete, the upper-level `aggregation`, `order by`, and `top-n` operations will be performed.
|
||||
|
||||
By removing the specific expressions (only keep the operators), the query plan can be presented in a more macroscopic view, as shown in the following figure.
|
||||
|
||||

|
||||
|
|
@ -1,114 +1,14 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
keywords: ['profile', 'query']
|
||||
sidebar_position: 80
|
||||
---
|
||||
|
||||
# Query Profile Structure and Metrics
|
||||
# Query Profile Metrics
|
||||
|
||||
## Overview
|
||||
> Authoritative reference for raw metrics emitted by **StarRocks Query Profile**, grouped by operator.
|
||||
> Use it as a glossary; for troubleshooting guidance jump to **query_profile_tuning_recipes.md**.
|
||||
|
||||
A Query Profile is a detailed report that provides insights into the execution of a SQL query within StarRocks. It offers a comprehensive view of the query's performance, including the time spent on each operation, the amount of data processed, and other relevant metrics. This information is invaluable for optimizing query performance, identifying bottlenecks, and troubleshooting issues.
|
||||
|
||||
:::tip Why this matters
|
||||
80% of real-world slow queries are solved by spotting one of three red-flag metrics. This cheat-sheet gets you there before you drown in numbers.
|
||||
:::
|
||||
|
||||
## Quick-Start
|
||||
|
||||
Profile a recent query:
|
||||
|
||||
### 1. List recent query IDs
|
||||
|
||||
A query ID is needed to analyze a query profile. Use `SHOW PROFILELIST;`:
|
||||
|
||||
```sql
|
||||
SHOW PROFILELIST;
|
||||
```
|
||||
|
||||
:::tip
|
||||
`SHOW PROFILELIST` is detailed in [Text-based Query Profile Visualized Analysis](./query_profile_text_based_analysis.md). See that page if you are getting started.
|
||||
:::
|
||||
|
||||
### 2. Open the profile side-by-side with your SQL
|
||||
|
||||
Run `ANALYZE PROFILE FOR <query_id>\G` or click **Profile** in the CelerData Web UI.
|
||||
|
||||
### 3. Skim the “Execution Overview” banner
|
||||
|
||||
Examine key metrics for overall execution performance:
|
||||
- QueryExecutionWallTime: Total wall clock time for query execution
|
||||
- QueryPeakMemoryUsagePerNode: Peak memory usage per node, with values exceeding 80% of BE memory indicating potential risks of data spill or Out-of-Memory (OOM) errors
|
||||
- QueryCumulativeCpuTime / WallTime < 0.5 * num_cpu_cores means CPU is waiting (likely I/O or network)
|
||||
|
||||
If none fire, your query is usually fine—stop here.
|
||||
|
||||
### 4. Drill one level deeper
|
||||
|
||||
Identify the operators that consume the most time or the most memory, analyze their metrics, and determine the underlying cause to pinpoint performance bottlenecks.
|
||||
|
||||
The "Operator Metrics" section offers numerous guidelines to aid in identifying the root cause of performance issues.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Query Execution Flow
|
||||
|
||||
The comprehensive execution flow of a SQL query involves the following stages:
|
||||
1. **Planning**: The query undergoes parsing, analysis, and optimization, culminating in the generation of a query plan.
|
||||
2. **Scheduling**: The scheduler and coordinator work together to distribute the query plan to all participating backend nodes.
|
||||
3. **Execution**: The query plan is executed using the pipeline execution engine.
|
||||
|
||||

|
||||
|
||||
### Query Plan Structure
|
||||
|
||||
The StarRocks execution engine is designed to execute queries in a distributed manner, and the structure of a Query Profile reflects this design. The following components make up the distributed query plan:
|
||||
|
||||
- **Fragment**: The highest level of the execution tree, representing a logical unit of work. A query can be divided into one or more fragments.
|
||||
- **FragmentInstance**: Each fragment is instantiated multiple times, with each instance (FragmentInstance) executed on a different computing node. This allows for parallel processing across nodes.
|
||||
- **Pipeline**: A FragmentInstance is further divided into multiple pipelines, which are sequences of connected Operator instances. Pipelines define the execution path for a FragmentInstance.
|
||||
- **PipelineDriver**: To maximize the utilization of computing resources, each pipeline can have multiple instances, known as PipelineDrivers. These drivers execute the pipeline in parallel, leveraging multiple computing cores.
|
||||
- **Operator**: The fundamental execution unit, an Operator instance is a part of a PipelineDriver. Operators implement specific algorithms, such as aggregation, join, or scan, to process data.
|
||||
|
||||

|
||||
|
||||
### Pipeline Execution Engine Concepts
|
||||
|
||||
The Pipeline Engine is a key component of the StarRocks execution engine. It is responsible for executing the query plan in a parallel and efficient manner. The Pipeline Engine is designed to handle complex query plans and large volumes of data, ensuring high performance and scalability.
|
||||
|
||||
Key concepts in the Pipeline Engine:
|
||||
- **Operator**: A fundamental unit of execution responsible for implementing specific algorithms (e.g., aggregation, join, scan)
|
||||
- **Pipeline**: A sequence of connected Operator instances representing the execution path
|
||||
- **PipelineDriver**: Multiple instances of a pipeline for parallel execution
|
||||
- **Schedule**: Non-blocking scheduling of pipelines using user-space time-slicing
|
||||
|
||||

|
||||
|
||||
### Metric Merging Strategy
|
||||
|
||||
By default, StarRocks merges the FragmentInstance and PipelineDriver layers to reduce profile volume, resulting in a simplified three-layer structure:
|
||||
- Fragment
|
||||
- Pipeline
|
||||
- Operator
|
||||
|
||||
You can control this merging behavior through the session variable `pipeline_profile_level`:
|
||||
- `1` (Default): Merged three-layer structure
|
||||
- `2`: Original five-layer structure
|
||||
- Other values: Treated as `1`
|
||||
|
||||
When merging metrics, different strategies are used based on metric type:
|
||||
|
||||
- **Time-related metrics**: Take the average
|
||||
- Example: `OperatorTotalTime` is the average time consumption
|
||||
- `__MAX_OF_OperatorTotalTime` and `__MIN_OF_OperatorTotalTime` record extremes
|
||||
|
||||
- **Non-time-related metrics**: Sum the values
|
||||
- Example: `PullChunkNum` is the sum across all instances
|
||||
- `__MAX_OF_PullChunkNum` and `__MIN_OF_PullChunkNum` record extremes
|
||||
|
||||
- **Constant metrics**: Same value across all instances (e.g., `DegreeOfParallelism`)
|
||||
|
||||
Significant differences between MIN and MAX values often indicate data skew, particularly in aggregation and join operations.
|
||||
|
||||
## Query Profile Metrics
|
||||
|
||||
### Summary Metrics
|
||||
|
||||
|
|
@ -220,7 +120,7 @@ Fragment-level execution details:
|
|||
|
||||
Pipeline execution details and relationships:
|
||||
|
||||

|
||||

|
||||
|
||||
Key relationships:
|
||||
- DriverTotalTime = ActiveTime + PendingTime + ScheduleTime
|
||||
|
|
@ -268,73 +168,6 @@ Key relationships:
|
|||
### Scan Operator
|
||||
|
||||
|
||||
To facilitate a better understanding of the various metrics within the Scan Operator, the following diagram demonstrates the associations between these metrics and storage structures.
|
||||
|
||||

|
||||
|
||||
|
||||
To retrieve data from disk and apply the predicates, the storage engine utilize several techniques:
|
||||
1. **Data Storage**: Encoded and compressed data is stored on disk in segments, accompanied by various indices.
|
||||
2. **Index Filtering**: The engine leverages indices such as BitmapIndex, BloomfilterIndex, ZonemapIndex, ShortKeyIndex, and NGramIndex to skip unnecessary data.
|
||||
3. **Pushdown Predicates**: Simple predicates, like `a > 1`, are pushed down to evaluate on specific columns.
|
||||
4. **Late Materialization**: Only the required columns and filtered rows are retrieved from disk.
|
||||
5. **Non-Pushdown Predicates**: Predicates that cannot be pushed down are evaluated.
|
||||
6. **Projection Expression**: Expressions, such as `SELECT a + 1`, are computed.
|
||||
|
||||
#### Common Performance Bottlenecks and Their Solutions:
|
||||
|
||||
##### Heavy Raw I/O or Slow Storage
|
||||
|
||||
**Red-flag metrics / symptoms**: BytesRead, RawRowsRead, CompressedBytesRead, ScanTime, IOTaskExecTime dominate
|
||||
|
||||
**Why it slows down OLAP scan**: Disk (or object-store) read bandwidth becomes the constraint
|
||||
|
||||
**Solutions**: Put hot data on NVMe/SSD, Enable storage cache
|
||||
|
||||
##### Poor Predicate
|
||||
|
||||
**Red-flag metrics / symptoms**: PushdownPredicates≈0; ExprFilterRows dominates; LIKE '%x%' or other complicated predicates
|
||||
|
||||
**Why it slows down OLAP scan**: More rows flow into CPU thread-pool because filters aren’t applied in storage layer
|
||||
|
||||
**Solutions**: Rewrite filters to simple comparisons, Build targeted MVs/indexes
|
||||
|
||||
##### Low DOP or Thread-pool Saturation
|
||||
|
||||
**Red-flag metrics / symptoms**: High IOTaskWaitTime; low PeakIOTasks
|
||||
|
||||
**Why it slows down OLAP scan**: Too few parallel scan tasks or threads blocked waiting for I/O slots
|
||||
|
||||
**Solutions**: Increase the disk bandwidth or enlarge the cache
|
||||
|
||||
##### Tablet / Data Skew Across BEs
|
||||
|
||||
**Red-flag metrics / symptoms**: Large max-min gap for OperatorTotalTime or BytesRead; one tablet own most data
|
||||
|
||||
**Why it slows down OLAP scan**: One thread does disproportionate work, all others idle
|
||||
|
||||
**Solutions**: Hash-bucket on high-cardinality key; Increase number of buckets
|
||||
|
||||
##### Fragmented Rowsets & Tiny Segments
|
||||
|
||||
**Red-flag metrics / symptoms**: High RowsetsReadCount / SegmentsReadCount; long SegmentInit time
|
||||
|
||||
**Why it slows down OLAP scan**: Many small files force frequent open/seek calls
|
||||
|
||||
**Solutions**: Increase compactions threads or execute manual compacctions; Batch mini-loads
|
||||
|
||||
##### High number of soft-deleted records
|
||||
|
||||
**Red-flag metrics / symptoms**: High DeleteFilterRows
|
||||
|
||||
**Why it slows down OLAP scan**: Soft-delete will apply the delete predicate when reading
|
||||
|
||||
**Solutions**: Compact the data; Reduce the frequency of delete operations
|
||||
|
||||
|
||||
The Scan Operator utilizes an additional thread pool for executing IO tasks. Therefore, the relationship between time metrics for this node is illustrated below:
|
||||
|
||||

|
||||
|
||||
#### OLAP Scan Operator
|
||||
|
||||
|
|
@ -448,82 +281,6 @@ Typical scenarios that can make Exchange Operator the bottleneck of a query:
|
|||
|
||||
### Aggregate Operator
|
||||
|
||||

|
||||
Aggregate Operator is responsible for executing aggregation functions, `GROUP BY`, and `DISTINCT`.
|
||||
|
||||
|
||||
**Multi forms of aggregation algorithm**
|
||||
|
||||
| Form | When the planner chooses it | Internal data structure | Highlights / caveats |
|
||||
|------|----------------------------|-------------------------|-----------------------|
|
||||
| Hash aggregation | keys fit into memory; cardinality not extreme | Compact hash table with SIMD probing | default path, excellent for modest key counts |
|
||||
| Sorted aggregation | input already ordered on the GROUP BY keys | Simple row comparison + running state | zero hash table cost, often 2-3× faster on probing heavy skews |
|
||||
| Spillable aggregation (3.2+) | hash table outsizes memory limit | Hybrid hash/merge with disk spill partitions | prevents OOM, preserves pipeline parallelism |
|
||||
|
||||
**Multi-Stage Distributed Aggregation**
|
||||
|
||||
In StarRocks the aggregation is implemented in distributed manner, which can be multi-stage depends on the query pattern and optimizer decision.
|
||||
|
||||
```
|
||||
┌─────────┐ ┌──────────┐ ┌────────────┐ ┌────────────┐
|
||||
│ Stage 0 │ local │ Stage 1 │ shard/ │ Stage 2 │ gather/│ Stage 3 │ final
|
||||
│ Partial │───► │ Update │ hash │ Merge │ shard │ Finalize │ output
|
||||
└─────────┘ └──────────┘ └────────────┘ └────────────┘
|
||||
```
|
||||
|
||||
| Stages | When Used | What Happens |
|
||||
|--------|------------|--------------|
|
||||
| One-stage | The `DISTRIBUTED BY` is a subset of `GROUP BY`, the partitions are colocated | Partial aggregates immediately become the final result. |
|
||||
| Two-stage (local + global) | Typical distributed `GROUP BY` | Stage 0 inside each BE collapses duplicates adaptively; Stage 1 shuffles data based on `GROUP BY` then perform global aggregation |
|
||||
| Three-stage (local + shuffle + final) | Heavy `DISTINCT` and high-cardianlity `GROUP BY` | Stage 0 as above; Stage 1 shuffles by `GROUP BY`, then aggregate by `GROUP BY` and `DISTINCT`; Stage 2 merges partial state as `GROUP BY` |
|
||||
| Four-stage (local + partial + intermediate + final) | Heavy `DISTINCT` and low-cardinality `GROUP BY` | Introduce an additional stage to shuffle by `GROUP BY` and `DISTINCT` to avoid single-point bottleneck |
|
||||
|
||||
|
||||
**Common Performance Bottlenecks and Their Solutions:**
|
||||
|
||||
### Bottleneck Cause
|
||||
|
||||
#### High-cardinality `GROUP BY` → oversize hash table
|
||||
|
||||
**Red-flag metrics / symptoms**: HashTableSize, HashTableMemoryUsage, and AggComputeTime balloon; query gets close to memory limit
|
||||
|
||||
**Why it hurts Agg operators**: Hash-aggregate builds one entry per group; if millions of groups land in RAM the hash table becomes CPU- and memory-bound and can even spill
|
||||
|
||||
**Solutions**: Enable sorted streaming aggregate; Add pre-aggregated MVs or roll-ups; Reduce key width / cast to `INT`
|
||||
|
||||
#### Data-skewed shuffle between partial → final stages
|
||||
|
||||
**Red-flag metrics / symptoms**: Huge gap in HashTableSize or InputRowCount across instances; one fragment’s AggComputeTime dwarfs others
|
||||
|
||||
**Why it hurts Agg operators**: A single backend receives most of the hot keys and blocks the pipeline
|
||||
|
||||
**Solutions**: Add salt column in the aggregation; Use `DISTINCT [skew]` hint
|
||||
|
||||
#### Expensive or `DISTINCT`-style aggregate functions (e.g., `ARRAY_AGG`, `HLL_UNION`, `BITMAP_UNION`, `COUNT(DISTINCT)`)
|
||||
|
||||
**Red-flag metrics / symptoms**: AggregateFunctions dominates operator time; CPU still near 100 % after hash build finishes
|
||||
|
||||
**Why it hurts Agg operators**: State-heavy aggregation functions keep sizable sketches and run SIMD-heavy loops each row
|
||||
|
||||
**Solutions**: Pre-compute HLL/Bitmap columns at ingest; Use approx_count_distinct or multi_distinct_* where accuracy allows;
|
||||
|
||||
#### Poor first-stage (partial) aggregation
|
||||
|
||||
**Red-flag metrics / symptoms**: Very large InputRowCount, but AggComputeTime is modest; PassThroughRowCount is high; upstream EXCHANGE shows massive BytesSent
|
||||
|
||||
**Why it hurts Agg operators**: If partial aggregation on each BE doesn't pre-aggregate the dataset well, most raw rows traverse the network and pile up in the final AGG
|
||||
|
||||
**Solutions**: Confirm plan shows two- or three-stage aggregation; Rewrite query to simple `GROUP BY` keys so optimizer can push partial AGG; set streaming_preaggregation_mode = 'force_preaggregation'
|
||||
|
||||
#### Heavy expression evaluation on `GROUP BY` keys
|
||||
|
||||
**Red-flag metrics / symptoms**: ExprComputeTime high relative to `AggComputeTime`
|
||||
|
||||
**Why it hurts Agg operators**: Complex functions on every row before hashing dominate CPU
|
||||
|
||||
**Solutions**: Materialize computed keys in a sub-query or generated column; Use column dictionary / pre-encoded values; Project downstream instead
|
||||
|
||||
|
||||
**Metrics List**
|
||||
|
||||
| Metric | Description |
|
||||
|
|
@ -547,111 +304,6 @@ In StarRocks the aggregation is implemented in distributed manner, which can be
|
|||
|
||||
### Join Operator
|
||||
|
||||

|
||||
|
||||
Join Operator is responsible for implementing explicit join or implicit joins.
|
||||
|
||||
During execution the join operator is split into Build (hash-table construction) and Probe phases that run in parallel inside the pipeline engine. Vector chunks (up to 4096 rows) are batch-hashed with SIMD; consumed keys generate runtime filters—Bloom or IN filters—pushed back to upstream scans to cut probe input early.
|
||||
|
||||
**Join Strategies**
|
||||
|
||||
StarRocks relies on a vectorized, pipeline-friendly hash-join core that can be wired into four physical strategies the cost-based optimizer weighs at plan time:
|
||||
|
||||
| Strategy | When the optimizer picks it | What makes it fast |
|
||||
|----------|-----------------------------|---------------------|
|
||||
| Colocate Join | Both tables belong to the same colocation group (identical bucket keys, bucket count, and replica layout).  | No network shuffle: each BE joins only its local buckets. |
|
||||
| Bucket-Shuffle Join | One of join tables has the same buckket key with join key | Only need to shuffle one join table, which can reduce the network cost |
|
||||
| Broadcast Join | Build side is very small (row/byte thresholds or explicit hint).  | Small table is replicated to every probe node; avoids shuffling large table. |
|
||||
| Shuffle (Hash) Join | General case, keys don’t align. | Hash-partition each row on the join key so probes are balanced across BEs. |
|
||||
|
||||
|
||||
**When joins become the bottleneck**
|
||||
|
||||
#### Build-side table too large for RAM
|
||||
|
||||
**Profile symptoms / hot metrics**: BuildRows, HashTableSize, BuildHashTableTime dominate; memory near limit or spills
|
||||
|
||||
**Why it hurts**: Hash table has to live in memory, can become slow if it cannot fit into CPU cache
|
||||
|
||||
**Solutions**:
|
||||
- smaller table as build side
|
||||
- Add pre-aggregation or selective projection
|
||||
- Boost query/BE memory or enable hash-spill
|
||||
|
||||
#### Large join probe time
|
||||
|
||||
**Profile symptoms / hot metrics**: High SearchHashTableTime
|
||||
|
||||
**Why it hurts**: Inefficient data clustering can lead to poor CPU cache locality
|
||||
|
||||
**Solutions**: Optimize data clustering by sorting the probe table on join keys
|
||||
|
||||
#### Excessive Output Columns
|
||||
|
||||
**Profile symptoms / hot metrics**: High OutputBuildColumnTime or OutputProbeColumnTime
|
||||
|
||||
**Why it hurts**: The processing of numerous output columns necessitates substantial data copying, which can be CPU-intensive
|
||||
|
||||
**Solutions**: Optimize output columns by reducing their number; Exclude heavy columns from output; Consider retrieving unnecessary columns post-join
|
||||
|
||||
#### Data skew after shuffle
|
||||
|
||||
**Profile symptoms / hot metrics**: One fragment’s ProbeRows ≫ others; OperatorTotalTime highly unbalanced
|
||||
|
||||
**Why it hurts**: A single BE receives most hot keys; others go idle
|
||||
|
||||
**Solutions**:
|
||||
- Use higher-cardinality key
|
||||
- pad composite key (concat(key,'-',mod(id,16)))
|
||||
|
||||
#### Broadcasting a not-so-small table
|
||||
|
||||
**Profile symptoms / hot metrics**: Join type is BROADCAST; BytesSent and SendBatchTime soar on every BE
|
||||
|
||||
**Why it hurts**: O(N²) network traffic and deserialisation
|
||||
|
||||
**Solutions**:
|
||||
- Let optimizer pick shuffle (`SET broadcast_row_limit = lower`)
|
||||
- Force shuffle hint
|
||||
- Analyze table to collect statistics.
|
||||
|
||||
#### Missing or ineffective runtime filters
|
||||
|
||||
**Profile symptoms / hot metrics**: JoinRuntimeFilterEvaluate small, scans still read full table
|
||||
|
||||
**Why it hurts**: Scans push all rows into probe side, wasting CPU & I/O
|
||||
|
||||
**Solutions**: Rewrite join predicate to pure equality so RF can be generated; Avoid doing type casting in join key
|
||||
|
||||
#### Non-equi (nested-loop) join sneak-in
|
||||
|
||||
**Profile symptoms / hot metrics**: Join node shows `CROSS` or `NESTLOOP`; ProbeRows*BuildRows skyrockets
|
||||
|
||||
**Why it hurts**: O(rows×rows) comparisons; no hash key
|
||||
|
||||
**Solutions**:
|
||||
- Add proper equality predicate or pre-filter
|
||||
- Materialise predicate result in temporary table, then re-join
|
||||
|
||||
#### Hash-key casting / expression cost
|
||||
|
||||
**Profile symptoms / hot metrics**: High ExprComputeTime; hash function time rivals probe time
|
||||
|
||||
**Why it hurts**: Keys must be cast or evaluated per row before hashing
|
||||
|
||||
**Solutions**:
|
||||
- Store keys with matching types
|
||||
- Pre-compute complex expressions into generated columns
|
||||
|
||||
#### No colocation on large join
|
||||
|
||||
**Profile symptoms / hot metrics**: Shuffle join between fact and dimension though buckets match
|
||||
|
||||
**Why it hurts**: Random placement forces shuffle every query
|
||||
|
||||
**Solutions**:
|
||||
- Put two tables in the same colocation group
|
||||
- Verify identical bucket count/key before ingest
|
||||
|
||||
**Metrics List**
|
||||
|
||||
|
|
@ -704,23 +356,6 @@ StarRocks relies on a vectorized, pipeline-friendly hash-join core that can be w
|
|||
|
||||
### Merge Operator
|
||||
|
||||
For ease of understanding various metrics, Merge can be represented as the following state mechanism:
|
||||
|
||||
```plaintext
|
||||
┌────────── PENDING ◄──────────┐
|
||||
│ │
|
||||
│ │
|
||||
├──────────────◄───────────────┤
|
||||
│ │
|
||||
▼ │
|
||||
INIT ──► PREPARE ──► SPLIT_CHUNK ──► FETCH_CHUNK ──► FINISHED
|
||||
▲
|
||||
|
|
||||
| one traverse from leaf to root
|
||||
|
|
||||
▼
|
||||
PROCESS
|
||||
```
|
||||
|
||||
|
||||
| Metric | Description | Level |
|
||||
|
|
@ -803,3 +438,4 @@ OlapTableSink Operator is responsible for performing the `INSERT INTO <table>` o
|
|||
| `PrepareDataTime` | Total time consumption for the data preparation phase, including data format conversion and data quality check. |
|
||||
| `SendDataTime` | Local time consumption for sending the data, including time for serializing and compressing data, and for submitting tasks to the sender queue. |
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
keywords: ['profile', 'query']
|
||||
sidebar_position: 30
|
||||
---
|
||||
|
||||
# Query Profile Overview
|
||||
|
||||
## Introduction
|
||||
|
||||
Query Profile records execution information for all working nodes involved in a query, helping you quickly identify bottlenecks affecting query performance. It is a powerful tool for diagnosing and tuning query performance in StarRocks.
|
||||
|
||||
> From v3.3.0 onwards, StarRocks supports providing Query Profile for data loading with INSERT INTO FILES() and Broker Load. For details of the metrics involved, see [OlapTableSink Operator](./query_profile_operator_metrics.md#olaptablesink-operator).
|
||||
|
||||
## How to Enable Query Profile
|
||||
|
||||
### Enable Query Profile
|
||||
|
||||
You can enable Query Profile by setting the variable `enable_profile` to `true`:
|
||||
|
||||
```SQL
|
||||
SET enable_profile = true;
|
||||
SET GLOBAL enable_profile = true;
|
||||
```
|
||||
|
||||
### Query Profile for Slow Queries
|
||||
|
||||
It is not recommended to enable Query Profile globally in production for long periods, as it may impose additional system overhead. To capture and analyze only slow queries, set the variable `big_query_profile_threshold` to a time duration greater than `0s`. For example, setting it to `30s` means only queries exceeding 30 seconds will trigger Query Profile.
|
||||
|
||||
```SQL
|
||||
-- 30 seconds
|
||||
SET global big_query_profile_threshold = '30s';
|
||||
|
||||
-- 500 milliseconds
|
||||
SET global big_query_profile_threshold = '500ms';
|
||||
|
||||
-- 60 minutes
|
||||
SET global big_query_profile_threshold = '60m';
|
||||
```
|
||||
|
||||
### Runtime Query Profile
|
||||
|
||||
For long-running queries, it can be difficult to determine progress or detect issues before completion. The Runtime Query Profile feature (v3.1+) collects and reports Query Profile data at fixed intervals during execution, providing real-time insight into query progress and bottlenecks.
|
||||
|
||||
When Query Profile is enabled, Runtime Query Profile is automatically activated with a default reporting interval of 10 seconds. Adjust the interval with `runtime_profile_report_interval`:
|
||||
|
||||
```SQL
|
||||
SET runtime_profile_report_interval = 30;
|
||||
```
|
||||
|
||||
### Configurations
|
||||
|
||||
| Configuration Item | Type | Valid Values | Default | Description |
|
||||
|-----------------------------------|--------------|-------------------|---------|---------------------------------------------------------------------------------------------|
|
||||
| enable_profile | Session Var | true/false | false | Enable Query Profile |
|
||||
| pipeline_profile_level | Session Var | 1/2 | 1 | 1: merge metrics; 2: retain original structure (disables visualization tools) |
|
||||
| runtime_profile_report_interval | Session Var | Positive integer | 10 | Runtime Query Profile report interval (seconds) |
|
||||
| big_query_profile_threshold | Session Var | String | 0s | Enable Query Profile for queries exceeding this duration (e.g., '30s', '500ms', '60m') |
|
||||
| enable_statistics_collect_profile | FE Dynamic | true/false | false | Enable Query Profile for statistics collection-related queries |
|
||||
|
||||
## How to Obtain Query Profile
|
||||
|
||||
### Via Web UI
|
||||
|
||||
1. Access `http://<fe_ip>:<fe_http_port>` in your browser.
|
||||
2. Click **queries** in the top navigation.
|
||||
3. In the **Finished Queries** list, select the query you want to analyze and click the link in the **Profile** column.
|
||||
|
||||

|
||||
|
||||
You will be redirected to the detailed page of the selected Query Profile.
|
||||
|
||||

|
||||
|
||||
### Via SQL Function (`get_query_profile`)
|
||||
|
||||
Example workflow:
|
||||
- `last_query_id()`: Returns the ID of the most recently executed query in your session. Useful for quickly retrieving the profile of your last query.
|
||||
- `show profilelist;`: Lists recent queries along with their IDs and status. Use this to find the `query_id` needed for profile analysis.
|
||||
- `get_query_profile('<query_id>')`: Returns the detailed execution profile for the specified query. Use this to analyze how a query was executed and where time or resources were spent.
|
||||
|
||||
|
||||
```sql
|
||||
-- Enable the profiling feature.
|
||||
set enable_profile = true;
|
||||
-- Run a simple query.
|
||||
select 1;
|
||||
-- Get the query_id of the query.
|
||||
select last_query_id();
|
||||
+--------------------------------------+
|
||||
| last_query_id() |
|
||||
+--------------------------------------+
|
||||
| bd3335ce-8dde-11ee-92e4-3269eb8da7d1 |
|
||||
+--------------------------------------+
|
||||
-- Get the list of profiles
|
||||
show profilelist;
|
||||
-- Obtain the query profile.
|
||||
select get_query_profile('502f3c04-8f5c-11ee-a41f-b22a2c00f66b')\G
|
||||
```
|
||||
|
||||
### In Managed Version
|
||||
|
||||
In StarRocks Managed (Enterprise) environments, you can conveniently access query profiles directly from the query history in the web console. The managed UI provides an intuitive, visual representation of each query's execution profile, making it easy to analyze performance and identify bottlenecks without manual SQL commands.
|
||||
|
||||
## Interpret Query Profile
|
||||
|
||||
### Explain Analyze
|
||||
|
||||
Most users may find it challenging to analyze the raw text directly. StarRocks provides a [Text-based Query Profile Visualized Analysis](./query_profile_text_based_analysis.md) method for a more intuitive understanding.
|
||||
|
||||
### Manged Version
|
||||
|
||||
In the StarRocks Enterprise Edition (EE), the Managed Version provides a built-in visualization tool for query profiles. This tool offers an interactive, graphical interface that makes it much easier to interpret complex query execution details compared to raw text output.
|
||||
|
||||
**Key features of the visualization tool include:**
|
||||
- **Operator-level breakdown:** View the execution plan as a tree or graph, with each operator's metrics (time, rows, memory) clearly displayed.
|
||||
- **Bottleneck highlighting:** Quickly identify slow or resource-intensive operators through color-coded indicators.
|
||||
- **Drill-down capability:** Click on any operator to see detailed statistics, including input/output rows, CPU time, memory usage, and more.
|
||||
|
||||
**How to use:**
|
||||
1. Open the StarRocks Managed web console.
|
||||
2. Navigate to the **Query** or **Query History** section.
|
||||
3. Select a query and click the **Profile** or **Visualize** button.
|
||||
4. Explore the visualized profile to analyze performance and identify optimization opportunities.
|
||||
|
||||
This visualization tool is exclusive to the Managed/Enterprise Edition and is designed to accelerate troubleshooting and performance tuning for complex workloads.
|
||||
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 60
|
||||
---
|
||||
|
||||
# Text-based Query Profile Visualized Analysis
|
||||
# Explain Analyze
|
||||
|
||||
This document explains how to obtain and analyze text-based Query Profiles in StarRocks. It will help you understand query performance and find ways to optimize your SQL queries.
|
||||
|
||||
How to obtain and analyze text-based Query Profiles through a MySQL client.
|
||||
|
||||
## Analyze Profiles of Existing Queries Using ANALYZE PROFILE
|
||||
|
||||
To analyze the text-based Profile of an existing (historical or running) query in you cluster, you first need to use the [SHOW PROFILELIST](../sql-reference/sql-statements/cluster-management/plan_profile/SHOW_PROFILELIST.md) statement to obtain a summary of the query. This command lists all queries that have finished successfully, failed with error, and those are still running (for more than 10 seconds and not yet finished). Through this statement, you can get the corresponding Query ID for subsequent analysis. The syntax is as follows:
|
||||
To analyze the text-based Profile of an existing (historical or running) query in you cluster, you first need to use the [SHOW PROFILELIST](../../sql-reference/sql-statements/cluster-management/plan_profile/SHOW_PROFILELIST.md) statement to obtain a summary of the query. This command lists all queries that have finished successfully, failed with error, and those are still running (for more than 10 seconds and not yet finished). Through this statement, you can get the corresponding Query ID for subsequent analysis. The syntax is as follows:
|
||||
|
||||
```SQL
|
||||
SHOW PROFILELIST [LIMIT <num>];
|
||||
|
|
@ -35,7 +37,7 @@ Output:
|
|||
+--------------------------------------+---------------------+-------+----------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
Once you have the Query ID, you can proceed with Query Profile analysis using the [ANALYZE PROFILE](../sql-reference/sql-statements/cluster-management/plan_profile/ANALYZE_PROFILE.md) statement. The syntax is as follows:
|
||||
Once you have the Query ID, you can proceed with Query Profile analysis using the [ANALYZE PROFILE](../../sql-reference/sql-statements/cluster-management/plan_profile/ANALYZE_PROFILE.md) statement. The syntax is as follows:
|
||||
|
||||
```SQL
|
||||
ANALYZE PROFILE FROM '<Query_ID>' [, <Node_ID> [, ...] ]
|
||||
|
|
@ -62,11 +64,11 @@ The Profile includes the following sections:
|
|||
|
||||
Example 1: Querying the Query Profile without specifying node ID.
|
||||
|
||||

|
||||

|
||||
|
||||
Example 2: Querying the Query Profile and specifying node ID as `0`. StarRocks returns all detailed metrics for Node ID `0` and highlights metrics with high usage for easier problem identification.
|
||||
|
||||

|
||||

|
||||
|
||||
In addition, the above methods also support the display and analysis of Runtime Query Profile, that is, Profile generated for running queries. When the Query Profile feature is enabled, you can use this method to obtain the Profile of queries that are currently running for more than 10 seconds.
|
||||
|
||||
|
|
@ -83,11 +85,11 @@ Compared to those of the finished queries, the text-based Query Profile for runn
|
|||
|
||||
Example:
|
||||
|
||||

|
||||

|
||||
|
||||
## Simulate a query for Profile Analysis Using EXPLAIN ANALYZE
|
||||
|
||||
StarRocks provides the [EXPLAIN ANALYZE](../sql-reference/sql-statements/cluster-management/plan_profile/EXPLAIN_ANALYZE.md) statement, allowing you to simulate and analyze the profile of a query directly. The syntax is as follows:
|
||||
StarRocks provides the [EXPLAIN ANALYZE](../../sql-reference/sql-statements/cluster-management/plan_profile/EXPLAIN_ANALYZE.md) statement, allowing you to simulate and analyze the profile of a query directly. The syntax is as follows:
|
||||
|
||||
```SQL
|
||||
EXPLAIN ANALYZE <sql_statement>
|
||||
|
|
@ -99,15 +101,15 @@ Currently, `EXPLAIN ANALYZE` supports two types of SQL statements: SELECT statem
|
|||
|
||||
Example 1: Simulate and analyze a SELECT statement. The query result are discarded.
|
||||
|
||||

|
||||

|
||||
|
||||
Example 2: Simulate and analyze an INSERT INTO statement. The loading transaction will be aborted.
|
||||
|
||||

|
||||

|
||||
|
||||
## Limitations
|
||||
|
||||
- `EXPLAIN ANALYZE INSERT INTO` statements are only supported for tables in the default catalog.
|
||||
- To achieve better visual effects, the output text contains ANSI characters to provide color, highlighting, and other features. It is recommended to use the MyCLI client. For clients that do not support ANSI features, such as the MySQL client, there may be some slight display disorders. Usually, they will not affect the usage. For example:
|
||||
|
||||

|
||||

|
||||
|
|
@ -0,0 +1,200 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
keywords: ['profile', 'query']
|
||||
sidebar_position: 40
|
||||
---
|
||||
|
||||
# Query Tuning Recipes
|
||||
|
||||
> A pragmatic playbook: **symptom → root cause → proven fixes**.
|
||||
> Use it when you’ve opened a profile and spotted a red-flag metric but still need to answer “_now what?_”.
|
||||
|
||||
---
|
||||
|
||||
## 1 · Fast Diagnosis Workflow
|
||||
|
||||
1. **Skim the Execution Overview**
|
||||
If `QueryPeakMemoryUsagePerNode > 80 %` or `QuerySpillBytes > 1 GB`, jump straight to the memory & spill recipes.
|
||||
|
||||
2. **Find the slowest Pipeline / Operator**
|
||||
⟶ In *Query Profile UI* click **Sort by OperatorTotalTime %**.
|
||||
The hottest operator tells you which recipe block to read next (Scan, Join, Aggregate, …).
|
||||
|
||||
3. **Confirm the bottleneck subtype**
|
||||
Each recipe begins with its *signature* metric pattern. Match those before trying the fixes.
|
||||
|
||||
---
|
||||
|
||||
## 2 · Recipes by Operator
|
||||
|
||||
### 2.1 OLAP / Connector Scan [[metrics]](./query_profile_operator_metrics.md#scan-operator)
|
||||
|
||||
To facilitate a better understanding of the various metrics within the Scan Operator, the following diagram demonstrates the associations between these metrics and storage structures.
|
||||
|
||||

|
||||
|
||||
|
||||
To retrieve data from disk and apply the predicates, the storage engine utilize several techniques:
|
||||
1. **Data Storage**: Encoded and compressed data is stored on disk in segments, accompanied by various indices.
|
||||
2. **Index Filtering**: The engine leverages indices such as BitmapIndex, BloomfilterIndex, ZonemapIndex, ShortKeyIndex, and NGramIndex to skip unnecessary data.
|
||||
3. **Pushdown Predicates**: Simple predicates, like `a > 1`, are pushed down to evaluate on specific columns.
|
||||
4. **Late Materialization**: Only the required columns and filtered rows are retrieved from di sk.
|
||||
5. **Non-Pushdown Predicates**: Predicates that cannot be pushed down are evaluated.
|
||||
6. **Projection Expression**: Expressions, such as `SELECT a + 1`, are computed.
|
||||
|
||||
The Scan Operator utilizes an additional thread pool for executing IO tasks. Therefore, the relationship between time metrics for this node is illustrated below:
|
||||
|
||||

|
||||
|
||||
|
||||
#### Common performance bottlenecks
|
||||
|
||||
**Cold or slow storage** – When `BytesRead`, `ScanTime`, or `IOTaskExecTime` dominate and disk I/O hovers around 80‑100 %, the scan is hitting cold or under‑provisioned storage. Move hot data to NVMe/SSD, enable the storage cache, or—if you’re scanning S3/HDFS—raise `remote_cache_capacity`.
|
||||
|
||||
**Filter push‑down missing** – If `PushdownPredicates` stays near 0 while `ExprFilterRows` is high, predicates aren’t reaching the storage layer. Rewrite them as simple comparisons (avoid `%LIKE%` and wide `OR` chains) or add zonemap/Bloom indexes or materialized views so they can be pushed down.
|
||||
|
||||
**Thread‑pool starvation** – A high `IOTaskWaitTime` together with a low `PeakIOTasks` signals that the I/O thread pool is saturated. Increase `max_io_threads` on the BE or enlarge the cache to let more tasks run concurrently.
|
||||
|
||||
**Data skew across tablets** – A wide gap between the maximum and minimum `OperatorTotalTime` means some tablets do much more work than others. Re‑bucket on a higher‑cardinality key or increase the bucket count to spread the load.
|
||||
|
||||
**Rowset/segment fragmentation** – Exploding `RowsetsReadCount`/`SegmentsReadCount` plus a long `SegmentInitTime` indicate many tiny rowsets. Trigger a manual compaction and batch small loads so segments merge up‑front.
|
||||
|
||||
**Accumulated soft deletes** – A large `DeleteFilterRows` implies heavy soft‑delete usage. Run BE compaction to purge tombstones and consolidate the delete bitmap.
|
||||
|
||||
### 2.2 Aggregate [[metrics]](./query_profile_operator_metrics.md#aggregate-operator)
|
||||
|
||||

|
||||
Aggregate Operator is responsible for executing aggregation functions, `GROUP BY`, and `DISTINCT`.
|
||||
|
||||
|
||||
**Multi forms of aggregation algorithm**
|
||||
|
||||
| Form | When the planner chooses it | Internal data structure | Highlights / caveats |
|
||||
|------|----------------------------|-------------------------|-----------------------|
|
||||
| Hash aggregation | keys fit into memory; cardinality not extreme | Compact hash table with SIMD probing | default path, excellent for modest key counts |
|
||||
| Sorted aggregation | input already ordered on the GROUP BY keys | Simple row comparison + running state | zero hash table cost, often 2-3× faster on probing heavy skews |
|
||||
| Spillable aggregation (3.2+) | hash table outsizes memory limit | Hybrid hash/merge with disk spill partitions | prevents OOM, preserves pipeline parallelism |
|
||||
|
||||
**Multi-Stage Distributed Aggregation**
|
||||
|
||||
In StarRocks the aggregation is implemented in distributed manner, which can be multi-stage depends on the query pattern and optimizer decision.
|
||||
|
||||
```
|
||||
┌─────────┐ ┌──────────┐ ┌────────────┐ ┌────────────┐
|
||||
│ Stage 0 │ local │ Stage 1 │ shard/ │ Stage 2 │ gather/│ Stage 3 │ final
|
||||
│ Partial │───► │ Update │ hash │ Merge │ shard │ Finalize │ output
|
||||
└─────────┘ └──────────┘ └────────────┘ └────────────┘
|
||||
```
|
||||
|
||||
| Stages | When Used | What Happens |
|
||||
|--------|------------|--------------|
|
||||
| One-stage | The `DISTRIBUTED BY` is a subset of `GROUP BY`, the partitions are colocated | Partial aggregates immediately become the final result. |
|
||||
| Two-stage (local + global) | Typical distributed `GROUP BY` | Stage 0 inside each BE collapses duplicates adaptively; Stage 1 shuffles data based on `GROUP BY` then perform global aggregation |
|
||||
| Three-stage (local + shuffle + final) | Heavy `DISTINCT` and high-cardianlity `GROUP BY` | Stage 0 as above; Stage 1 shuffles by `GROUP BY`, then aggregate by `GROUP BY` and `DISTINCT`; Stage 2 merges partial state as `GROUP BY` |
|
||||
| Four-stage (local + partial + intermediate + final) | Heavy `DISTINCT` and low-cardinality `GROUP BY` | Introduce an additional stage to shuffle by `GROUP BY` and `DISTINCT` to avoid single-point bottleneck |
|
||||
|
||||
|
||||
|
||||
#### Common performance bottlenecks
|
||||
|
||||
|
||||
**High‑cardinality GROUP BY** – When `HashTableSize` or `HashTableMemoryUsage` balloons toward the memory limit, the grouping key is too wide or too distinct. Enable sorted streaming aggregation (`enable_streaming_preaggregation = true`), create a roll‑up materialized view, or cast wide string keys to `INT`.
|
||||
|
||||
**Shuffle skew** – Large differences in `HashTableSize` or `InputRowCount` across fragments reveal an unbalanced shuffle. Add a salt column to the key or use the `DISTINCT [skew]` hint so rows distribute evenly.
|
||||
|
||||
**State‑heavy aggregate functions** – If `AggregateFunctions` dominates runtime and the functions include `HLL_`, `BITMAP_`, or `COUNT(DISTINCT)`, enormous state objects are being moved around. Pre‑compute HLL/bitmap sketches during ingestion or switch to approximate variants.
|
||||
|
||||
**Partial aggregation degraded** – A huge `InputRowCount` with modest `AggComputeTime`, plus massive `BytesSent` in the upstream EXCHANGE, means pre‑aggregation was bypassed. Force it back on with `SET streaming_preaggregation_mode = "force_preaggregation"`.
|
||||
|
||||
**Expensive key expressions** – When `ExprComputeTime` rivals `AggComputeTime`, the GROUP BY keys are computed row by row. Materialize those expressions in a sub‑query or promote them to generated columns.
|
||||
|
||||
### 2.3 Join [[metrics]](./query_profile_operator_metrics.md#join-operator)
|
||||
|
||||

|
||||
|
||||
Join Operator is responsible for implementing explicit join or implicit joins.
|
||||
|
||||
During execution the join operator is split into Build (hash-table construction) and Probe phases that run in parallel inside the pipeline engine. Vector chunks (up to 4096 rows) are batch-hashed with SIMD; consumed keys generate runtime filters—Bloom or IN filters—pushed back to upstream scans to cut probe input early.
|
||||
|
||||
**Join Strategies**
|
||||
|
||||
StarRocks relies on a vectorized, pipeline-friendly hash-join core that can be wired into four physical strategies the cost-based optimizer weighs at plan time:
|
||||
|
||||
| Strategy | When the optimizer picks it | What makes it fast |
|
||||
|----------|-----------------------------|---------------------|
|
||||
| Colocate Join | Both tables belong to the same colocation group (identical bucket keys, bucket count, and replica layout).  | No network shuffle: each BE joins only its local buckets. |
|
||||
| Bucket-Shuffle Join | One of join tables has the same buckket key with join key | Only need to shuffle one join table, which can reduce the network cost |
|
||||
| Broadcast Join | Build side is very small (row/byte thresholds or explicit hint).  | Small table is replicated to every probe node; avoids shuffling large table. |
|
||||
| Shuffle (Hash) Join | General case, keys don’t align. | Hash-partition each row on the join key so probes are balanced across BEs. |
|
||||
|
||||
#### Common performance bottlenecks
|
||||
|
||||
**Oversized build side** – Spikes in `BuildHashTableTime` and `HashTableMemoryUsage` show the build side has outgrown memory. Swap probe/build tables, pre‑filter the build table, or enable hash spilling.
|
||||
|
||||
**Cache‑unfriendly probe** – When `SearchHashTableTime` dominates, the probe side is not cache‑efficient. Sort the probe rows on the join keys and enable runtime filters.
|
||||
|
||||
**Shuffle skew** – If a single fragment’s `ProbeRows` dwarfs all others, the data is skewed. Switch to a higher‑cardinality key or append a salt such as `key || mod(id, 16)`.
|
||||
|
||||
**Accidental broadcast** – Join type **BROADCAST** with huge `BytesSent` means a table you thought was small isn’t. Lower `broadcast_row_limit` or enforce shuffle with the `SHUFFLE` hint.
|
||||
|
||||
**Missing runtime filters** – A tiny `JoinRuntimeFilterEvaluate` together with full‑table scans suggests runtime filters never propagated. Rewrite the join as pure equality and make sure the column types line up.
|
||||
|
||||
**Non‑equi fallback** – When the operator type is `CROSS` or `NESTLOOP`, an inequality or function prevents a hash join. Add a true equality predicate or pre‑filter the larger table.
|
||||
|
||||
### 2.4 Exchange (Network) [[metrics]](./query_profile_operator_metrics.md#exchange-operator)
|
||||
|
||||
**Oversized shuffle or broadcast** – If `NetworkTime` exceeds 30 % and `BytesSent` is large, the query is shipping too much data. Re‑evaluate the join strategy or enable exchange compaction (`pipeline_enable_exchange_compaction`).
|
||||
|
||||
**Receiver backlog** – High `WaitTime` in the sink with sender queues that stay full indicates the receiver cannot keep up. Increase the receiver thread pool (`brpc_num_threads`) and confirm NIC bandwidth and QoS settings.
|
||||
|
||||
### 2.5 Sort / Merge / Window
|
||||
|
||||
For ease of understanding various metrics, Merge can be represented as the following state mechanism:
|
||||
|
||||
```plaintext
|
||||
┌────────── PENDING ◄──────────┐
|
||||
│ │
|
||||
│ │
|
||||
├──────────────◄───────────────┤
|
||||
│ │
|
||||
▼ │
|
||||
INIT ──► PREPARE ──► SPLIT_CHUNK ──► FETCH_CHUNK ──► FINISHED
|
||||
▲
|
||||
|
|
||||
| one traverse from leaf to root
|
||||
|
|
||||
▼
|
||||
PROCESS
|
||||
```
|
||||
|
||||
|
||||
|
||||
**Sort spilling** – When `MaxBufferedBytes` rises above roughly 2 GB or `SpillBytes` is non‑zero, the sort phase is spilling to disk. Add a `LIMIT`, pre‑aggregate upstream, or raise `sort_spill_threshold` if the machine has enough memory.
|
||||
|
||||
**Merge starvation** – A high `PendingStageTime` tells you the merge is waiting for upstream chunks. Optimise the producer operator first or enlarge pipeline buffers.
|
||||
|
||||
**Wide window partitions** – Huge `PeakBufferedRows` inside a window operator point to very broad partitions or an ORDER BY lacking frame limits. Partition more granularly, add `RANGE BETWEEN` bounds, or materialise intermediate aggregates.
|
||||
|
||||
---
|
||||
|
||||
## 3 · Memory & Spill Cheatsheet
|
||||
|
||||
| Threshold | What to watch | Practical action |
|
||||
| --- | --- | --- |
|
||||
| **80 %** of BE memory | `QueryPeakMemoryUsagePerNode` | Lower session `exec_mem_limit` or add BE RAM |
|
||||
| Spill detected (`SpillBytes` > 0) | `QuerySpillBytes`, per-operator `SpillBlocks` | Increase memory limit; upgrade to SR 3.2+ for hybrid hash/merge spill |
|
||||
|
||||
---
|
||||
|
||||
## 4 · Template for Your Post-mortem
|
||||
|
||||
```text
|
||||
1. Symptom
|
||||
– Slow stage: Aggregate (OperatorTotalTime 68 %)
|
||||
– Red-flag: HashTableMemoryUsage 9 GB (> exec_mem_limit)
|
||||
2. Root cause
|
||||
– GROUP BY high-cardinality UUID
|
||||
3. Fix applied
|
||||
– Added sorted streaming agg + roll-up MV
|
||||
4. Outcome
|
||||
– Query runtime ↓ from 95 s ➜ 8 s; memory peak 0.7 GB```
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 50
|
||||
---
|
||||
|
||||
# Performance Optimization
|
||||
# Schema Tuning Recipes
|
||||
|
||||
This document provides practical tips and best practices for optimizing query performance in StarRocks through effective schema design and foundational table choices. By understanding how different table types, keys, and distribution strategies impact query execution, you can significantly improve both speed and resource efficiency. Use these guidelines to make informed decisions when designing schemas, selecting table types, and tuning your StarRocks environment for high-performance analytics.
|
||||
|
||||
|
||||
## Table Type Selection
|
||||
|
||||
|
|
@ -83,7 +87,7 @@ PROPERTIES(
|
|||
);
|
||||
~~~
|
||||
|
||||
For more information about colocate join and replica management, see [Colocate join](../using_starrocks/Colocate_join.md)
|
||||
For more information about colocate join and replica management, see [Colocate join](../../using_starrocks/Colocate_join.md)
|
||||
|
||||
## Flat table and star schema
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
---
|
||||
|
||||
#
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
<DocCardList />
|
||||
|
|
@ -24,7 +24,7 @@ get_query_profile(x)
|
|||
|
||||
## Return value
|
||||
|
||||
The query profile contains the following fields. For more information about the query profile, see [Query Profile](../../../administration/query_profile_overview.md).
|
||||
The query profile contains the following fields. For more information about the query profile, see [Query Profile](../../../best_practices/query_tuning/query_profile_overview.md).
|
||||
|
||||
```SQL
|
||||
Query:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ displayed_sidebar: docs
|
|||
|
||||
# ANALYZE PROFILE
|
||||
|
||||
ANALYZE PROFILE analyzes a specific query profile on a per-fragment basis, and displays it in a tree structure. For more information about query profile, see [Query Profile Overview](../../../../administration/query_profile_overview.md).
|
||||
ANALYZE PROFILE analyzes a specific query profile on a per-fragment basis, and displays it in a tree structure. For more information about query profile, see [Query Profile Overview](../../../../best_practices/query_tuning/query_profile_overview.md).
|
||||
|
||||
This feature is supported from v3.1 onwards.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ displayed_sidebar: docs
|
|||
|
||||
# EXPLAIN
|
||||
|
||||
EXPLAIN shows the logical or physical execution plans for a query statement. For instructions on how to analyze a query plan, refer to [Plan analysis](../../../../administration/Query_planning.md#plan-analysis).
|
||||
EXPLAIN shows the logical or physical execution plans for a query statement. For instructions on how to analyze a query plan, refer to [Plan analysis](../../../../best_practices/query_tuning/query_planning.md#plan-analysis).
|
||||
|
||||
:::tip
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ displayed_sidebar: docs
|
|||
|
||||
# EXPLAIN ANALYZE
|
||||
|
||||
EXPLAIN ANALYZE executes the specified SQL statement, and shows the query profile of this statement. For more information about query profile, see [Query Profile Overview](../../../../administration/query_profile_overview.md).
|
||||
EXPLAIN ANALYZE executes the specified SQL statement, and shows the query profile of this statement. For more information about query profile, see [Query Profile Overview](../../../../best_practices/query_tuning/query_profile_overview.md).
|
||||
|
||||
This feature is supported from v3.1 onwards.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ displayed_sidebar: docs
|
|||
|
||||
# SHOW PROFILELIST
|
||||
|
||||
SHOW PROFILELIST lists the query profile records cached in your StarRocks cluster. For more information about query profile, see [Query Profile Overview](../../../../administration/query_profile_overview.md).
|
||||
SHOW PROFILELIST lists the query profile records cached in your StarRocks cluster. For more information about query profile, see [Query Profile Overview](../../../../best_practices/query_tuning/query_profile_overview.md).
|
||||
|
||||
This feature is supported from v3.1 onwards.
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ SELECT select_expr[, select_expr ...]
|
|||
> - From v3.1 onwards, each synchronous materialized view can support more than one aggregate function for each column of the base table, for example, query statements such as `select b, sum(a), min(a) from table group by b`.
|
||||
> - From v3.1 onwards, synchronous materialized views support complex expressions for SELECT and aggregate functions, for example, query statements such as `select b, sum(a + 1) as sum_a1, min(cast (a as bigint)) as min_a from table group by b` or `select abs(b) as col1, a + 1 as col2, cast(a as bigint) as col3 from table`. The following restrictions are imposed on the complex expression used for synchronous materialized views:
|
||||
> - Each complex expression must have an alias and different aliases must be assigned to different complex expressions among all the synchronous materialized views of a base table. For example, query statements `select b, sum(a + 1) as sum_a from table group by b` and `select b, sum(a) as sum_a from table group by b` cannot be used to create synchronous materialized views for a same base table. You can set different aliases for a complex expression.
|
||||
> - You can check whether your queries are rewritten by the synchronous materialized views created with complex expressions by executing `EXPLAIN <sql_statement>`. For more information, see [Query analysis](../../../administration/Query_planning.md).
|
||||
> - You can check whether your queries are rewritten by the synchronous materialized views created with complex expressions by executing `EXPLAIN <sql_statement>`. For more information, see [Query analysis](../../../best_practices/query_tuning/query_planning.md).
|
||||
|
||||
- WHERE (optional)
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ The value range for `bitmap_max_filter_ratio` is 1-1000. If `bitmap_max_filter_r
|
|||
### Advantages
|
||||
|
||||
- Bitmap indexes can quickly locate the row numbers of queried column values, suitable for point queries or small-range queries.
|
||||
- Bitmap indexes can optimize multi-dimensional queries involving union and intersection operations (OR and AND operations).
|
||||
- Bitmap indexes can optimize multi-dimensional queries involving union and intersection operations (`OR` and `AND` operations).
|
||||
|
||||
## Considerations
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ DROP INDEX lo_orderdate_index ON lineorder_partial;
|
|||
|
||||
### Verify whether the bitmap index accelerates queries
|
||||
|
||||
Check the `BitmapIndexFilterRows` field in the query Profile. For information on viewing the Profile, refer to [Query analysis](../../administration/Query_planning.md).
|
||||
Check the `BitmapIndexFilterRows` field in the query Profile. For information on viewing the Profile, refer to [Query analysis](../../best_practices/query_tuning/query_planning.md).
|
||||
|
||||
## Performance test on bitmap index
|
||||
|
||||
|
|
|
|||
|
|
@ -112,4 +112,4 @@ Alternatively, you can also create [synchronous materialized views](../../using_
|
|||
|
||||
## How to verify whether the Prefix index accelerates queries
|
||||
|
||||
After executing a query, you can check whether the Prefix index takes effect and view its filtering effect from detailed metrics, such as `ShortKeyFilterRows`, in the scan node in the [Query Profile](../../administration/query_profile_overview.md).
|
||||
After executing a query, you can check whether the Prefix index takes effect and view its filtering effect from detailed metrics, such as `ShortKeyFilterRows`, in the scan node in the [Query Profile](../../best_practices/query_tuning/query_profile_overview.md).
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ SELECT flat_json_meta(<json_column>)
|
|||
FROM <table_name>[_META_];
|
||||
```
|
||||
|
||||
You can verify whether the executed query benefits from Flat JSON optimization through the [Query Profile](../administration/query_profile_overview.md) by observing the following metrics:
|
||||
You can verify whether the executed query benefits from Flat JSON optimization through the [Query Profile](../best_practices/query_tuning/query_profile_overview.md) by observing the following metrics:
|
||||
- `PushdownAccessPaths`: The number of sub-field paths pushed down to storage.
|
||||
- `AccessPathHits`: The number of times Flat JSON sub-fields are hit, with detailed information on the specific JSON hit.
|
||||
- `AccessPathUnhits`: The number of times Flat JSON sub-fields are not hit, with detailed information on the specific JSON not hit.
|
||||
|
|
@ -134,7 +134,7 @@ You can verify whether the executed query benefits from Flat JSON optimization t
|
|||
SELECT get_json_string(k2,'\$.Bool') FROM t1 WHERE k2->'arr' = '[10,20,30]';
|
||||
```
|
||||
|
||||
7. View Flat JSON-related metrics in the [Query Profile](../administration/query_profile_overview.md)
|
||||
7. View Flat JSON-related metrics in the [Query Profile](../best_practices/query_tuning/query_profile_overview.md)
|
||||
```yaml
|
||||
PushdownAccessPaths: 2
|
||||
- Table: t1
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ Among all the information returned, you can focus on the following metrics:
|
|||
- `QueryMemCost`: Total memory cost of the query.
|
||||
- Other metrics for individual operators, such as join operators and aggregate operators.
|
||||
|
||||
For detailed information on how to check the query profile and understand other metrics, see [Analyze query profile](../../administration/query_profile_overview.md).
|
||||
For detailed information on how to check the query profile and understand other metrics, see [Analyze query profile](../../best_practices/query_tuning/query_profile_overview.md).
|
||||
|
||||
### Verify whether queries are rewritten by an asynchronous materialized view
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ In scenarios involving query rewriting, if you use a very complex query statemen
|
|||
|
||||
## Best practices
|
||||
|
||||
In real-world business scenarios, you can identify queries with high execution latency and resource consumption by analyzing audit logs or big query logs. You can further use [query profiles](../../../administration/query_profile_overview.md) to pinpoint the specific stages where the query is slow. The following sections provide instructions and examples on how to boost data lake query performance with materialized views.
|
||||
In real-world business scenarios, you can identify queries with high execution latency and resource consumption by analyzing audit logs or big query logs. You can further use [query profiles](../../../best_practices/query_tuning/query_profile_overview.md) to pinpoint the specific stages where the query is slow. The following sections provide instructions and examples on how to boost data lake query performance with materialized views.
|
||||
|
||||
### Case One: Accelerate join calculation in data lake
|
||||
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 747 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 414 KiB |
|
|
@ -1,354 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
---
|
||||
|
||||
# クエリ分析
|
||||
|
||||
クエリパフォーマンスを最適化する方法は、よくある質問です。遅いクエリはユーザーエクスペリエンスやクラスターパフォーマンスに悪影響を与えます。クエリパフォーマンスを分析し、最適化することが重要です。
|
||||
|
||||
`fe/log/fe.audit.log` でクエリ情報を確認できます。各クエリには `QueryID` が対応しており、これを使用してクエリの `QueryPlan` と `Profile` を検索できます。`QueryPlan` は、FE が SQL ステートメントを解析して生成する実行プランです。`Profile` は BE の実行結果で、各ステップにかかる時間や各ステップで処理されるデータ量などの情報を含みます。
|
||||
|
||||
## プラン分析
|
||||
|
||||
StarRocks では、SQL ステートメントのライフサイクルはクエリ解析、クエリプランニング、クエリ実行の3つのフェーズに分けられます。分析ワークロードに必要な QPS は高くないため、クエリ解析は一般的にボトルネックにはなりません。
|
||||
|
||||
StarRocks におけるクエリパフォーマンスは、クエリプランニングとクエリ実行によって決まります。クエリプランニングはオペレーター (Join/Order/Aggregate) を調整する役割を担い、クエリ実行は具体的な操作を実行する役割を担います。
|
||||
|
||||
クエリプランは、DBA にクエリ情報をマクロ的に把握するための手段を提供します。クエリプランはクエリパフォーマンスの鍵であり、DBA が参照するための良いリソースです。以下のコードスニペットは、`TPCDS query96` を例にとり、クエリプランの確認方法を示しています。
|
||||
|
||||
[EXPLAIN](../sql-reference/sql-statements/cluster-management/plan_profile/EXPLAIN.md) ステートメントを使用して、クエリのプランを確認します。
|
||||
|
||||
~~~SQL
|
||||
EXPLAIN select count(*)
|
||||
from store_sales
|
||||
,household_demographics
|
||||
,time_dim
|
||||
, store
|
||||
where ss_sold_time_sk = time_dim.t_time_sk
|
||||
and ss_hdemo_sk = household_demographics.hd_demo_sk
|
||||
and ss_store_sk = s_store_sk
|
||||
and time_dim.t_hour = 8
|
||||
and time_dim.t_minute >= 30
|
||||
and household_demographics.hd_dep_count = 5
|
||||
and store.s_store_name = 'ese'
|
||||
order by count(*) limit 100;
|
||||
~~~
|
||||
|
||||
クエリプランには2種類あります。論理クエリプランと物理クエリプランです。ここで説明するクエリプランは論理クエリプランを指します。`TPCDS query96.sql` に対応するクエリプランは以下の通りです。
|
||||
|
||||
~~~sql
|
||||
+------------------------------------------------------------------------------+
|
||||
| Explain String |
|
||||
+------------------------------------------------------------------------------+
|
||||
| PLAN FRAGMENT 0 |
|
||||
| OUTPUT EXPRS:<slot 11> |
|
||||
| PARTITION: UNPARTITIONED |
|
||||
| RESULT SINK |
|
||||
| 12:MERGING-EXCHANGE |
|
||||
| limit: 100 |
|
||||
| tuple ids: 5 |
|
||||
| |
|
||||
| PLAN FRAGMENT 1 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 12 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 8:TOP-N |
|
||||
| | order by: <slot 11> ASC |
|
||||
| | offset: 0 |
|
||||
| | limit: 100 |
|
||||
| | tuple ids: 5 |
|
||||
| | |
|
||||
| 7:AGGREGATE (update finalize) |
|
||||
| | output: count(*) |
|
||||
| | group by: |
|
||||
| | tuple ids: 4 |
|
||||
| | |
|
||||
| 6:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: left hash join node can not do colocate |
|
||||
| | equal join conjunct: `ss_store_sk` = `s_store_sk` |
|
||||
| | tuple ids: 0 2 1 3 |
|
||||
| | |
|
||||
| |----11:EXCHANGE |
|
||||
| | tuple ids: 3 |
|
||||
| | |
|
||||
| 4:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: left hash join node can not do colocate |
|
||||
| | equal join conjunct: `ss_hdemo_sk`=`household_demographics`.`hd_demo_sk`|
|
||||
| | tuple ids: 0 2 1 |
|
||||
| | |
|
||||
| |----10:EXCHANGE |
|
||||
| | tuple ids: 1 |
|
||||
| | |
|
||||
| 2:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: table not in same group |
|
||||
| | equal join conjunct: `ss_sold_time_sk` = `time_dim`.`t_time_sk` |
|
||||
| | tuple ids: 0 2 |
|
||||
| | |
|
||||
| |----9:EXCHANGE |
|
||||
| | tuple ids: 2 |
|
||||
| | |
|
||||
| 0:OlapScanNode |
|
||||
| TABLE: store_sales |
|
||||
| PREAGGREGATION: OFF. Reason: `ss_sold_time_sk` is value column |
|
||||
| partitions=1/1 |
|
||||
| rollup: store_sales |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 0 |
|
||||
| |
|
||||
| PLAN FRAGMENT 2 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 11 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 5:OlapScanNode |
|
||||
| TABLE: store |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `store`.`s_store_name` = 'ese' |
|
||||
| partitions=1/1 |
|
||||
| rollup: store |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 3 |
|
||||
| |
|
||||
| PLAN FRAGMENT 3 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 10 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 3:OlapScanNode |
|
||||
| TABLE: household_demographics |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `household_demographics`.`hd_dep_count` = 5 |
|
||||
| partitions=1/1 |
|
||||
| rollup: household_demographics |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 1 |
|
||||
| |
|
||||
| PLAN FRAGMENT 4 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 09 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 1:OlapScanNode |
|
||||
| TABLE: time_dim |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `time_dim`.`t_hour` = 8, `time_dim`.`t_minute` >= 30 |
|
||||
| partitions=1/1 |
|
||||
| rollup: time_dim |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 2 |
|
||||
+------------------------------------------------------------------------------+
|
||||
128 rows in set (0.02 sec)
|
||||
~~~
|
||||
|
||||
クエリ 96 は、いくつかの StarRocks の概念を含むクエリプランを示しています。
|
||||
|
||||
|名前|説明|
|
||||
|--|--|
|
||||
|avgRowSize|スキャンされたデータ行の平均サイズ|
|
||||
|cardinality|スキャンされたテーブルのデータ行の総数|
|
||||
|colocate|テーブルがコロケートモードかどうか|
|
||||
|numNodes|スキャンするノードの数|
|
||||
|rollup|マテリアライズドビュー|
|
||||
|preaggregation|事前集計|
|
||||
|predicates|クエリフィルター|
|
||||
|
||||
クエリ 96 のクエリプランは、0 から 4 までの番号が付けられた 5 つのフラグメントに分かれています。クエリプランは、下から上に一つずつ読んでいくことができます。
|
||||
|
||||
フラグメント 4 は、`time_dim` テーブルをスキャンし、関連するクエリ条件 (例えば、`time_dim.t_hour = 8 and time_dim.t_minute >= 30`) を事前に実行する役割を担っています。このステップは、述語プッシュダウンとも呼ばれます。StarRocks は、集計テーブルに対して `PREAGGREGATION` を有効にするかどうかを決定します。前の図では、`time_dim` の事前集計は無効になっています。この場合、`time_dim` のすべてのディメンション列が読み取られ、テーブルに多くのディメンション列がある場合、パフォーマンスに悪影響を及ぼす可能性があります。`time_dim` テーブルがデータ分割のために `range partition` を選択している場合、クエリプランでいくつかのパーティションがヒットし、無関係なパーティションは自動的にフィルタリングされます。マテリアライズドビューがある場合、StarRocks はクエリに基づいて自動的にマテリアライズドビューを選択します。マテリアライズドビューがない場合、クエリは自動的にベーステーブルにヒットします (例えば、前の図の `rollup: time_dim`)。
|
||||
|
||||
スキャンが完了すると、フラグメント 4 は終了します。データは、前の図で示されているように EXCHANGE ID : 09 によって、受信ノードラベル 9 に渡されます。
|
||||
|
||||
クエリ 96 のクエリプランでは、フラグメント 2、3、4 は似た機能を持っていますが、異なるテーブルをスキャンする役割を担っています。具体的には、クエリ内の `Order/Aggregation/Join` 操作はフラグメント 1 で実行されます。
|
||||
|
||||
フラグメント 1 は、`BROADCAST` メソッドを使用して `Order/Aggregation/Join` 操作を実行します。つまり、小さなテーブルを大きなテーブルにブロードキャストします。両方のテーブルが大きい場合は、`SHUFFLE` メソッドを使用することをお勧めします。現在、StarRocks は `HASH JOIN` のみをサポートしています。`colocate` フィールドは、結合された 2 つのテーブルが同じ方法でパーティション分割およびバケット化されていることを示し、データを移動せずにローカルでジョイン操作を実行できることを示します。ジョイン操作が完了すると、上位レベルの `aggregation`、`order by`、および `top-n` 操作が実行されます。
|
||||
|
||||
特定の式を削除し (オペレーターのみを保持)、クエリプランをよりマクロ的な視点で提示することができます。以下の図に示されています。
|
||||
|
||||

|
||||
|
||||
## クエリヒント
|
||||
|
||||
クエリヒントは、クエリオプティマイザにクエリの実行方法を明示的に提案する指示またはコメントです。現在、StarRocks は 3 種類のヒントをサポートしています: システム変数ヒント (`SET_VAR`)、ユーザー定義変数ヒント (`SET_USER_VARIABLE`)、および Join ヒントです。ヒントは単一のクエリ内でのみ効果を発揮します。
|
||||
|
||||
### システム変数ヒント
|
||||
|
||||
`SET_VAR` ヒントを使用して、SELECT および SUBMIT TASK ステートメントで 1 つ以上の [システム変数](../sql-reference/System_variable.md) を設定し、ステートメントを実行できます。また、CREATE MATERIALIZED VIEW AS SELECT および CREATE VIEW AS SELECT などの他のステートメントに含まれる SELECT 句でも `SET_VAR` ヒントを使用できます。CTE の SELECT 句で `SET_VAR` ヒントを使用した場合、ステートメントが正常に実行されても `SET_VAR` ヒントは効果を発揮しないことに注意してください。
|
||||
|
||||
[システム変数の一般的な使用法](../sql-reference/System_variable.md) と比較して、`SET_VAR` ヒントはステートメントレベルで効果を発揮し、セッション全体には影響を与えません。
|
||||
|
||||
#### 構文
|
||||
|
||||
~~~SQL
|
||||
[...] SELECT /*+ SET_VAR(key=value [, key = value]) */ ...
|
||||
SUBMIT [/*+ SET_VAR(key=value [, key = value]) */] TASK ...
|
||||
~~~
|
||||
|
||||
#### 例
|
||||
|
||||
集計クエリの集計モードを指定するには、`SET_VAR` ヒントを使用して、集計クエリでシステム変数 `streaming_preaggregation_mode` と `new_planner_agg_stage` を設定します。
|
||||
|
||||
~~~SQL
|
||||
SELECT /*+ SET_VAR (streaming_preaggregation_mode = 'force_streaming',new_planner_agg_stage = '2') */ SUM(sales_amount) AS total_sales_amount FROM sales_orders;
|
||||
~~~
|
||||
|
||||
SUBMIT TASK ステートメントの実行タイムアウトを指定するには、`SET_VAR` ヒントを使用して、SUBMIT TASK ステートメントでシステム変数 `insert_timeout` を設定します。
|
||||
|
||||
~~~SQL
|
||||
SUBMIT /*+ SET_VAR(insert_timeout=3) */ TASK AS CREATE TABLE temp AS SELECT count(*) AS cnt FROM tbl1;
|
||||
~~~
|
||||
|
||||
マテリアライズドビューを作成するためのサブクエリの実行タイムアウトを指定するには、`SET_VAR` ヒントを使用して、SELECT 句でシステム変数 `query_timeout` を設定します。
|
||||
|
||||
~~~SQL
|
||||
CREATE MATERIALIZED VIEW mv
|
||||
PARTITION BY dt
|
||||
DISTRIBUTED BY HASH(`key`)
|
||||
BUCKETS 10
|
||||
REFRESH ASYNC
|
||||
AS SELECT /*+ SET_VAR(query_timeout=500) */ * from dual;
|
||||
~~~
|
||||
|
||||
### ユーザー定義変数ヒント
|
||||
|
||||
`SET_USER_VARIABLE` ヒントを使用して、SELECT ステートメントまたは INSERT ステートメントで 1 つ以上の [ユーザー定義変数](../sql-reference/user_defined_variables.md) を設定できます。他のステートメントに SELECT 句が含まれている場合、その SELECT 句でも `SET_USER_VARIABLE` ヒントを使用できます。他のステートメントは SELECT ステートメントおよび INSERT ステートメントであることができますが、CREATE MATERIALIZED VIEW AS SELECT ステートメントおよび CREATE VIEW AS SELECT ステートメントでは使用できません。CTE の SELECT 句で `SET_USER_VARIABLE` ヒントを使用した場合、ステートメントが正常に実行されても `SET_USER_VARIABLE` ヒントは効果を発揮しないことに注意してください。v3.2.4 以降、StarRocks はユーザー定義変数ヒントをサポートしています。
|
||||
|
||||
[ユーザー定義変数の一般的な使用法](../sql-reference/user_defined_variables.md) と比較して、`SET_USER_VARIABLE` ヒントはステートメントレベルで効果を発揮し、セッション全体には影響を与えません。
|
||||
|
||||
#### 構文
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
INSERT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
```
|
||||
|
||||
#### 例
|
||||
|
||||
以下の SELECT ステートメントは、スカラーサブクエリ `select max(age) from users` と `select min(name) from users` を参照しています。そのため、`SET_USER_VARIABLE` ヒントを使用して、これらの 2 つのスカラーサブクエリをユーザー定義変数として設定し、クエリを実行できます。
|
||||
|
||||
~~~SQL
|
||||
SELECT /*+ SET_USER_VARIABLE (@a = (select max(age) from users), @b = (select min(name) from users)) */ * FROM sales_orders where sales_orders.age = @a and sales_orders.name = @b;
|
||||
~~~
|
||||
|
||||
### Join ヒント
|
||||
|
||||
複数テーブルのジョインクエリにおいて、オプティマイザは通常、最適なジョイン実行方法を選択します。特別な場合には、ジョインヒントを使用して、オプティマイザにジョイン実行方法を明示的に提案したり、ジョインリオーダーを無効にすることができます。現在、ジョインヒントは、Shuffle Join、Broadcast Join、Bucket Shuffle Join、または Colocate Join をジョイン実行方法として提案することをサポートしています。ジョインヒントが使用されると、オプティマイザはジョインリオーダーを実行しません。そのため、小さいテーブルを右側のテーブルとして選択する必要があります。さらに、ジョイン実行方法として [Colocate Join](../using_starrocks/Colocate_join.md) または Bucket Shuffle Join を提案する場合、結合されたテーブルのデータ分布がこれらのジョイン実行方法の要件を満たしていることを確認してください。そうでない場合、提案されたジョイン実行方法は効果を発揮しません。
|
||||
|
||||
#### 構文
|
||||
|
||||
~~~SQL
|
||||
... JOIN { [BROADCAST] | [SHUFFLE] | [BUCKET] | [COLOCATE] | [UNREORDER]} ...
|
||||
~~~
|
||||
|
||||
> **注意**
|
||||
>
|
||||
> ジョインヒントは大文字小文字を区別しません。
|
||||
|
||||
#### 例
|
||||
|
||||
- Shuffle Join
|
||||
|
||||
ジョイン操作が実行される前に、テーブル A と B から同じバケッティングキー値を持つデータ行を同じマシンにシャッフルする必要がある場合、ジョイン実行方法を Shuffle Join としてヒントを与えることができます。
|
||||
|
||||
~~~SQL
|
||||
select k1 from t1 join [SHUFFLE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
~~~
|
||||
|
||||
- Broadcast Join
|
||||
|
||||
テーブル A が大きなテーブルで、テーブル B が小さなテーブルの場合、ジョイン実行方法を Broadcast Join としてヒントを与えることができます。テーブル B のデータは、テーブル A のデータが存在するマシンに完全にブロードキャストされ、その後ジョイン操作が実行されます。Shuffle Join と比較して、Broadcast Join はテーブル A のデータをシャッフルするコストを節約します。
|
||||
|
||||
~~~SQL
|
||||
select k1 from t1 join [BROADCAST] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
~~~
|
||||
|
||||
- Bucket Shuffle Join
|
||||
|
||||
ジョインクエリのジョイン等値結合式にテーブル A のバケッティングキーが含まれている場合、特にテーブル A と B の両方が大きなテーブルである場合、ジョイン実行方法を Bucket Shuffle Join としてヒントを与えることができます。テーブル B のデータは、テーブル A のデータ分布に従って、テーブル A のデータが存在するマシンにシャッフルされ、その後ジョイン操作が実行されます。Broadcast Join と比較して、Bucket Shuffle Join はデータ転送を大幅に削減します。なぜなら、テーブル B のデータはグローバルに一度だけシャッフルされるからです。Bucket Shuffle Join に参加するテーブルは、非パーティション化されているか、コロケートされている必要があります。
|
||||
|
||||
~~~SQL
|
||||
select k1 from t1 join [BUCKET] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
~~~
|
||||
|
||||
- Colocate Join
|
||||
|
||||
テーブル A と B がテーブル作成時に指定された同じ Colocation Group に属している場合、テーブル A と B から同じバケッティングキー値を持つデータ行は同じ BE ノードに分散されます。ジョインクエリのジョイン等値結合式にテーブル A と B のバケッティングキーが含まれている場合、ジョイン実行方法を Colocate Join としてヒントを与えることができます。同じキー値を持つデータはローカルで直接結合され、ノード間のデータ転送にかかる時間を削減し、クエリパフォーマンスを向上させます。
|
||||
|
||||
~~~SQL
|
||||
select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
~~~
|
||||
|
||||
#### ジョイン実行方法の確認
|
||||
|
||||
`EXPLAIN` コマンドを使用して、実際のジョイン実行方法を確認します。返された結果がジョインヒントと一致する場合、ジョインヒントが有効であることを意味します。
|
||||
|
||||
~~~SQL
|
||||
EXPLAIN select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
~~~
|
||||
|
||||

|
||||
|
||||
## SQL フィンガープリント
|
||||
|
||||
SQL フィンガープリントは、遅いクエリを最適化し、システムリソースの利用を向上させるために使用されます。StarRocks は、遅いクエリログ (`fe.audit.log.slow_query`) で SQL フィンガープリント機能を使用して SQL ステートメントを正規化し、SQL ステートメントを異なるタイプに分類し、各 SQL タイプの MD5 ハッシュ値を計算して遅いクエリを識別します。MD5 ハッシュ値は、フィールド `Digest` によって指定されます。
|
||||
|
||||
~~~SQL
|
||||
2021-12-27 15:13:39,108 [slow_query] |Client=172.26.xx.xxx:54956|User=root|Db=default_cluster:test|State=EOF|Time=2469|ScanBytes=0|ScanRows=0|ReturnRows=6|StmtId=3|QueryId=824d8dc0-66e4-11ec-9fdc-00163e04d4c2|IsQuery=true|feIp=172.26.92.195|Stmt=select count(*) from test_basic group by id_bigint|Digest=51390da6b57461f571f0712d527320f4
|
||||
~~~
|
||||
|
||||
SQL ステートメントの正規化は、ステートメントテキストをより正規化された形式に変換し、重要なステートメント構造のみを保持します。
|
||||
|
||||
- データベース名やテーブル名などのオブジェクト識別子を保持します。
|
||||
|
||||
- 定数を疑問符 (?) に変換します。
|
||||
|
||||
- コメントを削除し、スペースをフォーマットします。
|
||||
|
||||
例えば、以下の 2 つの SQL ステートメントは、正規化後に同じタイプに属します。
|
||||
|
||||
- 正規化前の SQL ステートメント
|
||||
|
||||
~~~SQL
|
||||
SELECT * FROM orders WHERE customer_id=10 AND quantity>20
|
||||
|
||||
|
||||
|
||||
SELECT * FROM orders WHERE customer_id = 20 AND quantity > 100
|
||||
~~~
|
||||
|
||||
- 正規化後の SQL ステートメント
|
||||
|
||||
~~~SQL
|
||||
SELECT * FROM orders WHERE customer_id=? AND quantity>?
|
||||
~~~
|
||||
|
|
@ -91,7 +91,7 @@ SHOW PARTITIONS FROM starrocks_audit_db__.starrocks_audit_tbl__;
|
|||
- `user`: クラスターのユーザー名。このユーザーはテーブルにデータをロードする権限 (LOAD_PRIV) を持っている必要があります。
|
||||
- `password`: ユーザーパスワード。
|
||||
- `secret_key`: パスワードを暗号化するために使用されるキー(文字列、16 バイトを超えてはならない)。このパラメータが設定されていない場合、**plugin.conf** 内のパスワードは暗号化されず、`password` に平文のパスワードを指定するだけで済みます。このパラメータが指定されている場合、パスワードはこのキーで暗号化されていることを示し、`password` に暗号化された文字列を指定する必要があります。暗号化されたパスワードは、StarRocks で `AES_ENCRYPT` 関数を使用して生成できます:`SELECT TO_BASE64(AES_ENCRYPT('password','secret_key'));`。
|
||||
- `enable_compute_all_query_digest`: すべてのクエリに対して Hash SQL フィンガープリントを生成するかどうか(StarRocks はデフォルトでスロークエリに対してのみ SQL フィンガープリントを有効にしています)。プラグインでのフィンガープリント計算は FE のものとは異なり、[SQL ステートメントを正規化](../Query_planning.md#sql-fingerprint) しますが、プラグインはしません。この機能を有効にすると、フィンガープリント計算は追加の計算リソースを消費します。
|
||||
- `enable_compute_all_query_digest`: すべてのクエリに対して Hash SQL フィンガープリントを生成するかどうか(StarRocks はデフォルトでスロークエリに対してのみ SQL フィンガープリントを有効にしています)。プラグインでのフィンガープリント計算は FE のものとは異なり、[SQL ステートメントを正規化](../../best_practices/query_tuning/query_planning.md#sql-fingerprint) しますが、プラグインはしません。この機能を有効にすると、フィンガープリント計算は追加の計算リソースを消費します。
|
||||
- `filter`: 監査ログロードのフィルター条件。このパラメータは Stream Load の [WHERE パラメータ](../../sql-reference/sql-statements/loading_unloading/STREAM_LOAD.md#opt_properties) に基づいており、`-H “where: <condition>”` として指定され、デフォルトは空の文字列です。例:`filter=isQuery=1 and clientIp like '127.0.0.1%' and user='root'`。
|
||||
|
||||
4. ファイルを再度パッケージに圧縮します。
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
keywords: ['profile', 'query']
|
||||
---
|
||||
|
||||
# Query Profile 概要
|
||||
|
||||
このトピックでは、Query Profile の表示と分析方法を紹介します。Query Profile は、クエリに関与するすべての作業ノードの実行情報を記録します。Query Profile を通じて、クエリパフォーマンスに影響を与えるボトルネックを迅速に特定できます。
|
||||
|
||||
v3.3.0 以降、StarRocks は INSERT INTO FILES() および Broker Load を使用したデータロードのための Query Profile の提供をサポートしています。関連するメトリクスの詳細については、[OlapTableSink Operator](./query_profile_details.md#olaptablesink-operator) を参照してください。
|
||||
|
||||
## Query Profile の有効化
|
||||
|
||||
Query Profile を有効にするには、変数 `enable_profile` を `true` に設定します。
|
||||
|
||||
```SQL
|
||||
SET enable_profile = true;
|
||||
```
|
||||
|
||||
### 遅いクエリのための Query Profile の有効化
|
||||
|
||||
本番環境で Query Profile をグローバルかつ長期間にわたって有効にすることは推奨されません。これは、Query Profile のデータ収集と処理がシステムに追加の負担をかける可能性があるためです。しかし、遅いクエリをキャプチャして分析する必要がある場合は、遅いクエリのみに対して Query Profile を有効にすることができます。これは、変数 `big_query_profile_threshold` を `0s` より大きい時間に設定することで実現できます。例えば、この変数を `30s` に設定すると、実行時間が 30 秒を超えるクエリのみが Query Profile をトリガーします。これにより、システムパフォーマンスを確保しつつ、遅いクエリを効果的に監視できます。
|
||||
|
||||
```SQL
|
||||
-- 30 秒
|
||||
SET global big_query_profile_threshold = '30s';
|
||||
|
||||
-- 500 ミリ秒
|
||||
SET global big_query_profile_threshold = '500ms';
|
||||
|
||||
-- 60 分
|
||||
SET global big_query_profile_threshold = '60m';
|
||||
```
|
||||
|
||||
### 実行時 Query Profile の有効化
|
||||
|
||||
一部のクエリは、秒から数時間にわたって実行されることがあります。多くの場合、クエリがまだ進行中であるか、システムがクエリ完了前にクラッシュしたかを判断するのは難しいです。この問題に対処するために、StarRocks は v3.1 以降で Runtime Query Profile 機能を導入しました。この機能により、クエリ実行中に固定時間間隔で Query Profile データを収集し、報告することができます。これにより、クエリの実行進捗と潜在的なボトルネックをリアルタイムで把握でき、クエリが終了するのを待たずに監視と最適化が可能になります。
|
||||
|
||||
Query Profile が有効になっている場合、この機能は自動的に有効化され、デフォルトの報告間隔は 10 秒です。この間隔は、変数 `runtime_profile_report_interval` を変更することで調整できます。
|
||||
|
||||
```SQL
|
||||
SET runtime_profile_report_interval = 30;
|
||||
```
|
||||
|
||||
Runtime Query Profile は、通常の Query Profile と同じ形式と内容を持っています。クラスター内で実行中のクエリのパフォーマンスメトリクスを理解するために、通常の Query Profile を分析するのと同様に Runtime Query Profile を分析できます。
|
||||
|
||||
### Query Profile の動作設定
|
||||
|
||||
| 設定タイプ | 設定項目 | 有効値 | デフォルト値 | 説明 |
|
||||
| -- | -- | -- | -- | -- |
|
||||
| セッション変数 | enable_profile | true/false | false | Query Profile を有効にするかどうか。`true` はこの機能を有効にすることを意味します。 |
|
||||
| セッション変数 | pipeline_profile_level | 1/2 | 1 | Query Profile のレベルを設定します。`1` は Query Profile のメトリクスをマージすることを示し、`2` は Query Profile の元の構造を保持することを示します。この項目を `2` に設定すると、すべての可視化分析ツールが適用されなくなるため、一般的にはこの値を変更することは推奨されません。 |
|
||||
| セッション変数 | runtime_profile_report_interval | 正の整数 | 10 | Runtime Query Profile の報告間隔。単位: 秒。 |
|
||||
| セッション変数 | big_query_profile_threshold | 文字列 | `0s` | 大規模クエリの実行時間がこの値を超える場合、そのクエリに対して Query Profile が自動的に有効になります。この項目を `0s` に設定すると、この機能は無効になります。その値は、単位が `ms`、`s`、`m` の整数で表すことができます。 |
|
||||
| FE 動的設定項目 | enable_statistics_collect_profile | true/false | false | 統計収集関連のクエリに対して Query Profile を有効にするかどうか。`true` はこの機能を有効にすることを意味します。 |
|
||||
| FE 動的設定項目 | profile_info_format | default/json | default | システムが出力する Profile のフォーマット。`default` に設定すると、Profile はデフォルトのフォーマットで出力される。`json` に設定すると、システムは JSON フォーマットで Profile を出力する。 |
|
||||
|
||||
### Web UI を通じて Query Profile を取得
|
||||
|
||||
以下の手順で Query Profile を取得します。
|
||||
|
||||
1. ブラウザで `http://<fe_ip>:<fe_http_port>` にアクセスします。
|
||||
2. 表示されたページで、上部のナビゲーションから **queries** をクリックします。
|
||||
3. **Finished Queries** リストで、分析したいクエリを選択し、**Profile** 列のリンクをクリックします。
|
||||
|
||||

|
||||
|
||||
選択した Query Profile の詳細ページにリダイレクトされます。
|
||||
|
||||

|
||||
|
||||
### get_query_profile を通じて Query Profile を取得
|
||||
|
||||
以下の例は、get_query_profile 関数を使用して Query Profile を取得する方法を示しています。
|
||||
|
||||
```Plain
|
||||
-- プロファイリング機能を有効にします。
|
||||
set enable_profile = true;
|
||||
-- シンプルなクエリを実行します。
|
||||
select 1;
|
||||
-- クエリの query_id を取得します。
|
||||
select last_query_id();
|
||||
+--------------------------------------+
|
||||
| last_query_id() |
|
||||
+--------------------------------------+
|
||||
| bd3335ce-8dde-11ee-92e4-3269eb8da7d1 |
|
||||
+--------------------------------------+
|
||||
-- クエリプロファイルを取得します。
|
||||
select get_query_profile('502f3c04-8f5c-11ee-a41f-b22a2c00f66b')\G
|
||||
```
|
||||
|
||||
## Query Profile の分析
|
||||
|
||||
Query Profile によって生成される生の内容には、多数のメトリクスが含まれている場合があります。これらのメトリクスの詳細な説明については、[Query Profile Structure and Detailed Metrics](./query_profile_details.md) を参照してください。
|
||||
|
||||
しかし、ほとんどのユーザーはこの生のテキストを直接分析するのが難しいと感じるかもしれません。この問題に対処するために、StarRocks は [Text-based Query Profile Visualized Analysis](./query_profile_text_based_analysis.md) メソッドを提供しています。この機能を使用して、複雑な Query Profile をより直感的に理解することができます。
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
label: 'クエリチューニング'
|
||||
position: 200
|
||||
collapsed: true
|
||||
link:
|
||||
type: generated-index
|
||||
title: 'クエリチューニングのベストプラクティス'
|
||||
description: 'StarRocks でクエリを分析、チューニング、最適化する方法を学びます。'
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 70
|
||||
---
|
||||
|
||||
# クエリヒント
|
||||
|
||||
クエリヒントは、クエリオプティマイザに対してクエリの実行方法を明示的に指示するための指示またはコメントです。現在、StarRocks は3種類のヒントをサポートしています: システム変数ヒント (`SET_VAR`)、ユーザー定義変数ヒント (`SET_USER_VARIABLE`)、および Join ヒントです。ヒントは単一のクエリ内でのみ効果を発揮します。
|
||||
|
||||
## システム変数ヒント
|
||||
|
||||
`SET_VAR` ヒントを使用して、SELECT および SUBMIT TASK 文で1つ以上の[システム変数](../../sql-reference/System_variable.md)を設定し、その後に文を実行できます。また、CREATE MATERIALIZED VIEW AS SELECT や CREATE VIEW AS SELECT などの他の文に含まれる SELECT 句でも `SET_VAR` ヒントを使用できます。ただし、CTE の SELECT 句で `SET_VAR` ヒントを使用した場合、文が正常に実行されても `SET_VAR` ヒントは効果を発揮しません。
|
||||
|
||||
[システム変数の一般的な使用法](../../sql-reference/System_variable.md)と比較して、`SET_VAR` ヒントはステートメントレベルで効果を発揮し、セッション全体には影響を与えません。
|
||||
|
||||
### 構文
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_VAR(key=value [, key = value]) */ ...
|
||||
SUBMIT [/*+ SET_VAR(key=value [, key = value]) */] TASK ...
|
||||
```
|
||||
|
||||
### 例
|
||||
|
||||
集計クエリの集計モードを指定するには、`SET_VAR` ヒントを使用して、集計クエリ内のシステム変数 `streaming_preaggregation_mode` と `new_planner_agg_stage` を設定します。
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_VAR (streaming_preaggregation_mode = 'force_streaming',new_planner_agg_stage = '2') */ SUM(sales_amount) AS total_sales_amount FROM sales_orders;
|
||||
```
|
||||
|
||||
SUBMIT TASK 文の実行タイムアウトを指定するには、`SET_VAR` ヒントを使用して、SUBMIT TASK 文内のシステム変数 `insert_timeout` を設定します。
|
||||
|
||||
```SQL
|
||||
SUBMIT /*+ SET_VAR(insert_timeout=3) */ TASK AS CREATE TABLE temp AS SELECT count(*) AS cnt FROM tbl1;
|
||||
```
|
||||
|
||||
マテリアライズドビューを作成する際のサブクエリ実行タイムアウトを指定するには、`SET_VAR` ヒントを使用して、SELECT 句内のシステム変数 `query_timeout` を設定します。
|
||||
|
||||
```SQL
|
||||
CREATE MATERIALIZED VIEW mv
|
||||
PARTITION BY dt
|
||||
DISTRIBUTED BY HASH(`key`)
|
||||
BUCKETS 10
|
||||
REFRESH ASYNC
|
||||
AS SELECT /*+ SET_VAR(query_timeout=500) */ * from dual;
|
||||
```
|
||||
|
||||
## ユーザー定義変数ヒント
|
||||
|
||||
`SET_USER_VARIABLE` ヒントを使用して、SELECT 文または INSERT 文で1つ以上の[ユーザー定義変数](../../sql-reference/user_defined_variables.md)を設定できます。他の文に SELECT 句が含まれている場合、その SELECT 句でも `SET_USER_VARIABLE` ヒントを使用できます。他の文は SELECT 文および INSERT 文であることができますが、CREATE MATERIALIZED VIEW AS SELECT 文および CREATE VIEW AS SELECT 文では使用できません。CTE の SELECT 句で `SET_USER_VARIABLE` ヒントを使用した場合、文が正常に実行されても `SET_USER_VARIABLE` ヒントは効果を発揮しません。v3.2.4 以降、StarRocks はユーザー定義変数ヒントをサポートしています。
|
||||
|
||||
[ユーザー定義変数の一般的な使用法](../../sql-reference/user_defined_variables.md)と比較して、`SET_USER_VARIABLE` ヒントはステートメントレベルで効果を発揮し、セッション全体には影響を与えません。
|
||||
|
||||
### 構文
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
INSERT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
```
|
||||
|
||||
### 例
|
||||
|
||||
次の SELECT 文はスカラーサブクエリ `select max(age) from users` と `select min(name) from users` を参照しているため、`SET_USER_VARIABLE` ヒントを使用してこれら2つのスカラーサブクエリをユーザー定義変数として設定し、その後クエリを実行できます。
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_USER_VARIABLE (@a = (select max(age) from users), @b = (select min(name) from users)) */ * FROM sales_orders where sales_orders.age = @a and sales_orders.name = @b;
|
||||
```
|
||||
|
||||
## Join ヒント
|
||||
|
||||
複数テーブルの Join クエリでは、オプティマイザは通常、最適な Join 実行方法を選択します。特別な場合には、Join ヒントを使用してオプティマイザに Join 実行方法を明示的に指示したり、Join Reorder を無効にすることができます。現在、Join ヒントは Shuffle Join、Broadcast Join、Bucket Shuffle Join、または Colocate Join を Join 実行方法として提案することをサポートしています。Join ヒントが使用されると、オプティマイザは Join Reorder を行いません。そのため、より小さいテーブルを右テーブルとして選択する必要があります。さらに、[Colocate Join](../../using_starrocks/Colocate_join.md) または Bucket Shuffle Join を Join 実行方法として提案する場合、結合されるテーブルのデータ分布がこれらの Join 実行方法の要件を満たしていることを確認してください。そうでない場合、提案された Join 実行方法は効果を発揮しません。
|
||||
|
||||
### 構文
|
||||
|
||||
```SQL
|
||||
... JOIN { [BROADCAST] | [SHUFFLE] | [BUCKET] | [COLOCATE] | [UNREORDER]} ...
|
||||
```
|
||||
|
||||
:::note
|
||||
Join ヒントは大文字小文字を区別しません。
|
||||
:::
|
||||
|
||||
### 例
|
||||
|
||||
- Shuffle Join
|
||||
|
||||
テーブル A と B の同じバケッティングキー値を持つデータ行を Join 操作が行われる前に同じマシンにシャッフルする必要がある場合、Join 実行方法を Shuffle Join としてヒントを与えることができます。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [SHUFFLE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Broadcast Join
|
||||
|
||||
テーブル A が大きなテーブルで、テーブル B が小さなテーブルの場合、Join 実行方法を Broadcast Join としてヒントを与えることができます。テーブル B のデータは、テーブル A のデータが存在するマシンに完全にブロードキャストされ、その後 Join 操作が行われます。Shuffle Join と比較して、Broadcast Join はテーブル A のデータをシャッフルするコストを節約します。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BROADCAST] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Bucket Shuffle Join
|
||||
|
||||
Join クエリの Join 等値結合式にテーブル A のバケッティングキーが含まれている場合、特にテーブル A と B の両方が大きなテーブルである場合、Join 実行方法を Bucket Shuffle Join としてヒントを与えることができます。テーブル B のデータは、テーブル A のデータ分布に従って、テーブル A のデータが存在するマシンにシャッフルされ、その後 Join 操作が行われます。Broadcast Join と比較して、Bucket Shuffle Join はデータ転送を大幅に削減します。なぜなら、テーブル B のデータはグローバルに一度だけシャッフルされるからです。Bucket Shuffle Join に参加するテーブルは、非パーティション化されているか、またはコロケートされている必要があります。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BUCKET] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Colocate Join
|
||||
|
||||
テーブル A と B がテーブル作成時に指定された同じ Colocation Group に属している場合、テーブル A と B の同じバケッティングキー値を持つデータ行は同じ BE ノードに分散されます。Join クエリの Join 等値結合式にテーブル A と B のバケッティングキーが含まれている場合、Join 実行方法を Colocate Join としてヒントを与えることができます。同じキー値を持つデータはローカルで直接結合され、ノード間のデータ伝送にかかる時間を削減し、クエリパフォーマンスを向上させます。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
### Join 実行方法の表示
|
||||
|
||||
`EXPLAIN` コマンドを使用して、実際の Join 実行方法を確認します。返された結果が Join ヒントと一致する場合、Join ヒントが効果的であることを意味します。
|
||||
|
||||
```SQL
|
||||
EXPLAIN select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
# クエリチューニングの紹介
|
||||
|
||||
クエリチューニングは、StarRocks において高いパフォーマンスと信頼性を実現するために不可欠です。このディレクトリでは、実用的なガイド、参考資料、実行可能なレシピを集め、SQL の記述から実行詳細の解釈に至るまで、あらゆる段階でクエリパフォーマンスを分析、診断、最適化するのに役立ちます。
|
||||
|
||||
StarRocks での効果的なクエリチューニングは、通常、トップダウンのプロセスに従います。
|
||||
|
||||
1. **問題の特定**
|
||||
- 遅いクエリ、高いリソース使用率、または予期しない結果を検出します。
|
||||
- StarRocks では、組み込みの監視ツール、クエリ履歴、監査ログを活用して、問題のあるクエリや異常なパターンを迅速に特定します。
|
||||
- 参照: ** [Query Tuning Recipes](./query_profile_tuning_recipes.md) ** で症状に基づく診断を行い、** [Query Profile Overview](./query_profile_overview.md) ** でクエリ履歴とプロファイルにアクセスします。
|
||||
|
||||
2. **実行情報の収集と分析**
|
||||
- `EXPLAIN` または `EXPLAIN ANALYZE` を使用してクエリプランを取得します。
|
||||
- Query Profile を有効にして、詳細な実行メトリクスを収集します。
|
||||
- 参照: ** [Query Plan Overview](./query_planning.md) ** でクエリプランの理解を深め、** [Explain Analyze & Text-Based Profile Analysis](./query_profile_text_based_analysis.md) ** でステップバイステップの分析を行い、** [Query Profile Overview](./query_profile_overview.md) ** でプロファイルの有効化と解釈を行います。
|
||||
|
||||
3. **根本原因の特定**
|
||||
- どのステージや Operator が最も時間やリソースを消費しているかを特定します。
|
||||
- よくある問題をチェックします: 非最適なジョイン順序、インデックスの欠如、データ分布の問題、または非効率な SQL パターン。
|
||||
- 参照: ** [Query Profile Metrics](./query_profile_operator_metrics.md) ** でメトリクスと Operator の用語集を確認し、** [Query Tuning Recipes](./query_profile_tuning_recipes.md) ** で根本原因の分析を行います。
|
||||
|
||||
4. **チューニング戦略の適用**
|
||||
- SQL リライト: SQL クエリをリライトまたは最適化します(例: フィルタを追加、SELECT * を避ける)。
|
||||
- スキーマチューニング: インデックスを追加、テーブルタイプを変更、パーティショニング、クラスタリング。
|
||||
- クエリプランチューニング: 必要に応じてヒントや変数を使用してオプティマイザをガイドします。
|
||||
- 実行チューニング: 特定のワークロードに対してセッション変数をチューニングします。
|
||||
- 参照: ** [Schema Tuning Recipes](./schema_tuning.md) ** でスキーマレベルの最適化を行い、** [Query Hint](./query_hint.md) ** でオプティマイザヒントを確認し、** [Query Tuning Recipes](./query_profile_tuning_recipes.md) ** でプランチューニングと実行チューニングを行います。
|
||||
|
||||
5. **検証と反復**
|
||||
- クエリを再実行し、変更前後のパフォーマンスを比較します。
|
||||
- 新しいクエリプランとプロファイルを確認し、改善を確認します。
|
||||
- さらなる最適化が必要な場合は、プロセスを繰り返します。
|
||||
|
||||
DBA、開発者、またはデータエンジニアであれ、これらのリソースは以下のことに役立ちます:
|
||||
- 遅いまたはリソース集約型のクエリを診断し、解決する
|
||||
- オプティマイザの選択と実行の詳細を理解する
|
||||
- ベストプラクティスと高度なチューニング戦略を適用する
|
||||
|
||||
概要から始め、必要に応じて参考資料に飛び込み、実際のパフォーマンスの課題を解決するためにレシピやヒントを活用してください。
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 20
|
||||
---
|
||||
|
||||
# クエリプラン
|
||||
|
||||
クエリパフォーマンスの最適化は、分析システムにおける一般的な課題です。クエリが遅いと、ユーザーエクスペリエンスやクラスタ全体のパフォーマンスに悪影響を及ぼす可能性があります。StarRocksでは、クエリプランとクエリプロファイルを理解し解釈することが、遅いクエリを診断し改善するための基盤となります。これらのツールは以下のことに役立ちます。
|
||||
- ボトルネックや高コストの操作を特定する
|
||||
- 最適でないジョイン戦略やインデックスの欠如を見つける
|
||||
- データがどのようにフィルタリング、集計、移動されるかを理解する
|
||||
- リソース使用のトラブルシューティングと最適化
|
||||
|
||||
**クエリプラン**は、StarRocks FE によって生成される詳細なロードマップで、SQL ステートメントがどのように実行されるかを説明します。クエリをスキャン、ジョイン、集計、ソートなどの一連の操作に分解し、それらを最も効率的に実行する方法を決定します。
|
||||
|
||||
StarRocks はクエリプランを確認するためのいくつかの方法を提供しています。
|
||||
|
||||
1. **EXPLAIN ステートメント**:
|
||||
`EXPLAIN` を使用して、クエリの論理または物理的な実行プランを表示します。出力を制御するオプションを追加できます。
|
||||
- `EXPLAIN LOGICAL <query>`: 簡略化されたプランを表示します。
|
||||
- `EXPLAIN <query>`: 基本的な物理プランを表示します。
|
||||
- `EXPLAIN VERBOSE <query>`: 詳細情報を含む物理プランを表示します。
|
||||
- `EXPLAIN COSTS <query>`: 各操作の推定コストを含み、統計の問題を診断するために使用されます。
|
||||
|
||||
2. **EXPLAIN ANALYZE**:
|
||||
`EXPLAIN ANALYZE <query>` を使用してクエリを実行し、実際の実行プランと実行時の統計情報を表示します。詳細は [Explain Anlayze](./query_profile_text_based_analysis.md) ドキュメントを参照してください。
|
||||
|
||||
例:
|
||||
```sql
|
||||
EXPLAIN ANALYZE SELECT * FROM sales_orders WHERE amount > 1000;
|
||||
```
|
||||
|
||||
3. **Query Profile**:
|
||||
クエリを実行した後、その詳細な実行プロファイルを表示できます。これには、タイミング、リソース使用量、オペレーター レベルの統計が含まれます。詳細情報のアクセスと解釈については [Query Profile](./query_profile_overview.md) ドキュメントを参照してください。
|
||||
- **SQL コマンド**: `SHOW PROFILELIST` および `ANALYZE PROFILE FOR <query_id>` を使用して、特定のクエリの実行プロファイルを取得できます。
|
||||
- **FE HTTP サービス**: StarRocks FE の Web UI で **Query** または **Profile** セクションに移動して、クエリの実行詳細を検索および確認できます。
|
||||
- **マネージドバージョン**: クラウドまたはマネージドデプロイメントでは、提供された Web コンソールまたはモニタリングダッシュボードを使用して、クエリプランとプロファイルを表示できます。多くの場合、視覚化やフィルタリングオプションが強化されています。
|
||||
|
||||
通常、クエリプランはクエリの計画と最適化に関連する問題を診断するために使用され、クエリプロファイルはクエリ実行中のパフォーマンス問題を特定するのに役立ちます。以下のセクションでは、クエリ実行の主要な概念を探り、クエリプランを分析する具体的な例を紹介します。
|
||||
|
||||
## クエリ実行フロー
|
||||
|
||||
StarRocks におけるクエリのライフサイクルは、主に3つのフェーズで構成されています。
|
||||
1. **計画**: クエリは解析、分析、最適化を経て、クエリプランの生成に至ります。
|
||||
2. **スケジューリング**: スケジューラとコーディネータがプランをすべての参加バックエンドノードに分配します。
|
||||
3. **実行**: プランはパイプライン実行エンジンを使用して実行されます。
|
||||
|
||||

|
||||
|
||||
**プラン構造**
|
||||
|
||||
StarRocks のプランは階層的です。
|
||||
- **フラグメント**: 最上位の作業スライスで、各フラグメントは異なるバックエンドノードで実行される複数の **FragmentInstances** を生成します。
|
||||
- **パイプライン**: インスタンス内で、パイプラインはオペレーターを連結し、複数の **PipelineDrivers** が同じパイプラインを別々の CPU コアで同時に実行します。
|
||||
- **オペレーター**: データを実際に処理するスキャン、ジョイン、集計などの基本的なステップです。
|
||||
|
||||

|
||||
|
||||
**パイプライン実行エンジン**
|
||||
|
||||
パイプラインエンジンは、クエリプランを並列かつ効率的に実行し、複雑なプランや大規模なデータ量を高パフォーマンスかつスケーラブルに処理します。
|
||||
|
||||

|
||||
|
||||
**メトリックマージ戦略**
|
||||
|
||||
デフォルトでは、StarRocks はプロファイルのボリュームを削減するために FragmentInstance と PipelineDriver レイヤーをマージし、簡略化された3層構造を生成します。
|
||||
- フラグメント
|
||||
- パイプライン
|
||||
- オペレーター
|
||||
|
||||
このマージ動作は、セッション変数 `pipeline_profile_level` を通じて制御できます。
|
||||
|
||||
## 例
|
||||
|
||||
### クエリプランとプロファイルの読み方
|
||||
|
||||
1. **構造を理解する**: クエリプランはフラグメントに分割され、それぞれが実行のステージを表します。下から上に読みます: まずスキャンノード、次にジョイン、集計、そして最終的に結果です。
|
||||
|
||||
2. **全体的な分析**:
|
||||
- 総実行時間、メモリ使用量、CPU/ウォールタイム比を確認します。
|
||||
- オペレーター時間でソートして遅いオペレーターを見つけます。
|
||||
- フィルターが可能な限りプッシュダウンされていることを確認します。
|
||||
- データの偏り(オペレーター時間や行数の不均一)を探します。
|
||||
- 高いメモリ使用量やディスクスピルを監視し、ジョイン順序を調整したり、ロールアップビューを使用したりします。
|
||||
- 必要に応じてマテリアライズドビューやクエリヒント(`BROADCAST`、`SHUFFLE`、`COLOCATE`)を使用して最適化します。
|
||||
|
||||
2. **スキャン操作**: `OlapScanNode` または類似のものを探します。どのテーブルがスキャンされ、どのフィルターが適用され、事前集計やマテリアライズドビューが使用されているかを確認します。
|
||||
|
||||
3. **ジョイン操作**: ジョインタイプ(`HASH JOIN`、`BROADCAST`、`SHUFFLE`、`COLOCATE`、`BUCKET SHUFFLE`)を特定します。ジョイン方法はパフォーマンスに影響します。
|
||||
- **Broadcast**: 小さなテーブルをすべてのノードに送信します。小さなテーブルに適しています。
|
||||
- **Shuffle**: 行をパーティション分割してシャッフルします。大きなテーブルに適しています。
|
||||
- **Colocate**: テーブルが同じ方法でパーティション分割されているため、ローカルジョインを可能にします。
|
||||
- **Bucket Shuffle**: ネットワークコストを削減するために、1つのテーブルのみをシャッフルします。
|
||||
|
||||
4. **集計とソート**: `AGGREGATE`、`TOP-N`、または `ORDER BY` を探します。これらは大規模または高カーディナリティのデータで高コストになる可能性があります。
|
||||
|
||||
5. **データ移動**: `EXCHANGE` ノードはフラグメントまたはノード間のデータ転送を示します。データ移動が多すぎるとパフォーマンスに悪影響を及ぼす可能性があります。
|
||||
|
||||
6. **述語プッシュダウン**: スキャン時に適用されるフィルターは、下流のデータを削減します。`PREDICATES` または `PushdownPredicates` を確認して、どのフィルターがプッシュダウンされているかを確認します。
|
||||
|
||||
### クエリプランの例
|
||||
|
||||
```sql
|
||||
EXPLAIN select count(*)
|
||||
from store_sales
|
||||
,household_demographics
|
||||
,time_dim
|
||||
, store
|
||||
where ss_sold_time_sk = time_dim.t_time_sk
|
||||
and ss_hdemo_sk = household_demographics.hd_demo_sk
|
||||
and ss_store_sk = s_store_sk
|
||||
and time_dim.t_hour = 8
|
||||
and time_dim.t_minute >= 30
|
||||
and household_demographics.hd_dep_count = 5
|
||||
and store.s_store_name = 'ese'
|
||||
order by count(*) limit 100;
|
||||
```
|
||||
|
||||
出力は、StarRocks がクエリをどのように実行するかを示す階層的なプランで、フラグメントとオペレーターに分かれています。以下はクエリプランフラグメントの簡略化された例です。
|
||||
|
||||
```
|
||||
PLAN FRAGMENT 1
|
||||
6:HASH JOIN (BROADCAST)
|
||||
|-- 4:HASH JOIN (BROADCAST)
|
||||
| |-- 2:HASH JOIN (BROADCAST)
|
||||
| | |-- 0:OlapScanNode (store_sales)
|
||||
| | |-- 1:OlapScanNode (time_dim)
|
||||
| |-- 3:OlapScanNode (household_demographics)
|
||||
|-- 5:OlapScanNode (store)
|
||||
```
|
||||
|
||||
- **OlapScanNode**: テーブルをスキャンし、フィルターや事前集計が適用される可能性があります。
|
||||
- **HASH JOIN (BROADCAST)**: 小さなテーブルをブロードキャストして2つのテーブルをジョインします。
|
||||
- **フラグメント**: 各フラグメントは異なるノードで並行して実行できます。
|
||||
|
||||
クエリ96のクエリプランは、0から4までの5つのフラグメントに分かれています。クエリプランは、下から上に一つずつ読むことができます。
|
||||
|
||||
フラグメント4は、`time_dim` テーブルをスキャンし、関連するクエリ条件(すなわち `time_dim.t_hour = 8 and time_dim.t_minute >= 30`)を事前に実行する役割を担っています。このステップは述語プッシュダウンとしても知られています。StarRocks は、集計テーブルに対して `PREAGGREGATION` を有効にするかどうかを決定します。前の図では、`time_dim` の事前集計は無効になっています。この場合、`time_dim` のすべてのディメンション列が読み取られ、テーブルに多くのディメンション列がある場合、パフォーマンスに悪影響を及ぼす可能性があります。`time_dim` テーブルがデータ分割に `range partition` を選択した場合、クエリプランでいくつかのパーティションがヒットし、無関係なパーティションは自動的にフィルタリングされます。マテリアライズドビューがある場合、StarRocks はクエリに基づいてマテリアライズドビューを自動的に選択します。マテリアライズドビューがない場合、クエリは自動的にベーステーブルにヒットします(たとえば、前の図の `rollup: time_dim`)。
|
||||
|
||||
スキャンが完了すると、フラグメント4が終了します。データは、前の図で EXCHANGE ID : 09 と示されるように、他のフラグメントに渡され、受信ノード9に送られます。
|
||||
|
||||
クエリ96のクエリプランでは、フラグメント2、3、4は似た機能を持っていますが、異なるテーブルをスキャンする役割を担っています。具体的には、クエリ内の `Order/Aggregation/Join` 操作はフラグメント1で実行されます。
|
||||
|
||||
フラグメント1は `BROADCAST` メソッドを使用して `Order/Aggregation/Join` 操作を実行します。つまり、小さなテーブルを大きなテーブルにブロードキャストします。両方のテーブルが大きい場合は、`SHUFFLE` メソッドを使用することをお勧めします。現在、StarRocks は `HASH JOIN` のみをサポートしています。`colocate` フィールドは、結合された2つのテーブルが同じ方法でパーティション分割およびバケット化されていることを示し、データを移動せずにローカルでジョイン操作を実行できることを示します。ジョイン操作が完了すると、上位レベルの `aggregation`、`order by`、および `top-n` 操作が実行されます。
|
||||
|
||||
特定の式を削除することにより(オペレーターのみを保持)、クエリプランはよりマクロ的なビューで提示できます。以下の図に示すように。
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,427 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 80
|
||||
keywords: ['profile', 'query']
|
||||
---
|
||||
|
||||
# Query Profile Metrics
|
||||
|
||||
> **StarRocks Query Profile** によって生成される生のメトリクスの権威あるリファレンスで、オペレーターごとにグループ化されています。
|
||||
> 用語集として使用してください。トラブルシューティングのガイダンスについては、**query_profile_tuning_recipes.md** にジャンプしてください。
|
||||
|
||||
### Summary Metrics
|
||||
|
||||
クエリ実行に関する基本情報:
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| Total | クエリによって消費された総時間。プランニング、実行、およびプロファイリングフェーズの期間を含みます。 |
|
||||
| Query State | クエリの状態。可能な状態には、Finished、Error、Running があります。 |
|
||||
| Query ID | クエリの一意の識別子。 |
|
||||
| Start Time | クエリが開始されたタイムスタンプ。 |
|
||||
| End Time | クエリが終了したタイムスタンプ。 |
|
||||
| Total | クエリの総期間。 |
|
||||
| Query Type | クエリのタイプ。 |
|
||||
| Query State | クエリの現在の状態。 |
|
||||
| StarRocks Version | 使用された StarRocks のバージョン。 |
|
||||
| User | クエリを実行したユーザー。 |
|
||||
| Default Db | クエリに使用されたデフォルトのデータベース。 |
|
||||
| Sql Statement | 実行された SQL ステートメント。 |
|
||||
| Variables | クエリに使用された重要な変数。 |
|
||||
| NonDefaultSessionVariables | クエリに使用された非デフォルトのセッション変数。 |
|
||||
| Collect Profile Time | プロファイルを収集するのにかかった時間。 |
|
||||
| IsProfileAsync | プロファイル収集が非同期であったかどうかを示します。 |
|
||||
|
||||
### Planner Metrics
|
||||
|
||||
プランナーの包括的な概要を提供します。通常、プランナーに費やされる総時間が10ms未満であれば、問題はありません。
|
||||
|
||||
特定のシナリオでは、プランナーがより多くの時間を必要とする場合があります:
|
||||
1. 複雑なクエリは、最適な実行プランを確保するために、解析と最適化に追加の時間を必要とする場合があります。
|
||||
2. 多数のマテリアライズドビューが存在する場合、クエリの書き換えに必要な時間が増加する可能性があります。
|
||||
3. 複数の同時クエリがシステムリソースを使い果たし、クエリキューが使用される場合、`Pending` 時間が延長される可能性があります。
|
||||
4. 外部テーブルを含むクエリは、外部メタデータサーバーとの通信に追加の時間を要する可能性があります。
|
||||
|
||||
Example:
|
||||
```
|
||||
- -- Parser[1] 0
|
||||
- -- Total[1] 3ms
|
||||
- -- Analyzer[1] 0
|
||||
- -- Lock[1] 0
|
||||
- -- AnalyzeDatabase[1] 0
|
||||
- -- AnalyzeTemporaryTable[1] 0
|
||||
- -- AnalyzeTable[1] 0
|
||||
- -- Transformer[1] 0
|
||||
- -- Optimizer[1] 1ms
|
||||
- -- MVPreprocess[1] 0
|
||||
- -- MVTextRewrite[1] 0
|
||||
- -- RuleBaseOptimize[1] 0
|
||||
- -- CostBaseOptimize[1] 0
|
||||
- -- PhysicalRewrite[1] 0
|
||||
- -- DynamicRewrite[1] 0
|
||||
- -- PlanValidate[1] 0
|
||||
- -- InputDependenciesChecker[1] 0
|
||||
- -- TypeChecker[1] 0
|
||||
- -- CTEUniqueChecker[1] 0
|
||||
- -- ColumnReuseChecker[1] 0
|
||||
- -- ExecPlanBuild[1] 0
|
||||
- -- Pending[1] 0
|
||||
- -- Prepare[1] 0
|
||||
- -- Deploy[1] 2ms
|
||||
- -- DeployLockInternalTime[1] 2ms
|
||||
- -- DeploySerializeConcurrencyTime[2] 0
|
||||
- -- DeployStageByStageTime[6] 0
|
||||
- -- DeployWaitTime[6] 1ms
|
||||
- -- DeployAsyncSendTime[2] 0
|
||||
- DeployDataSize: 10916
|
||||
Reason:
|
||||
```
|
||||
|
||||
### Execution Overview Metrics
|
||||
|
||||
高レベルの実行統計:
|
||||
|
||||
| Metric | Description | Rule of Thumb |
|
||||
|--------|-------------|---------------|
|
||||
| FrontendProfileMergeTime | FE 側のプロファイル処理時間 | < 10ms 正常 |
|
||||
| QueryAllocatedMemoryUsage | ノード全体で割り当てられたメモリの合計 | |
|
||||
| QueryDeallocatedMemoryUsage | ノード全体で解放されたメモリの合計 | |
|
||||
| QueryPeakMemoryUsagePerNode | ノードごとの最大ピークメモリ | < 80% 容量正常 |
|
||||
| QuerySumMemoryUsage | ノード全体でのピークメモリの合計 | |
|
||||
| QueryExecutionWallTime | 実行のウォールタイム | |
|
||||
| QueryCumulativeCpuTime | ノード全体での CPU 時間の合計 | `walltime * totalCpuCores` と比較 |
|
||||
| QueryCumulativeOperatorTime | オペレーター実行時間の合計 | オペレーター時間の割合の分母 |
|
||||
| QueryCumulativeNetworkTime | Exchange ノードのネットワーク時間の合計 | |
|
||||
| QueryCumulativeScanTime | Scan ノードの IO 時間の合計 | |
|
||||
| QueryPeakScheduleTime | 最大パイプラインスケジュール時間 | 単純なクエリでは < 1s 正常 |
|
||||
| QuerySpillBytes | ディスクにスピルされたデータ | < 1GB 正常 |
|
||||
|
||||
### Fragment Metrics
|
||||
|
||||
フラグメントレベルの実行詳細:
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| InstanceNum | FragmentInstances の数 |
|
||||
| InstanceIds | すべての FragmentInstances の ID |
|
||||
| BackendNum | 参加している BEs の数 |
|
||||
| BackendAddresses | BE のアドレス |
|
||||
| FragmentInstancePrepareTime | フラグメント準備フェーズの期間 |
|
||||
| InstanceAllocatedMemoryUsage | インスタンスに割り当てられたメモリの合計 |
|
||||
| InstanceDeallocatedMemoryUsage | インスタンスで解放されたメモリの合計 |
|
||||
| InstancePeakMemoryUsage | インスタンス全体でのピークメモリ |
|
||||
|
||||
### Pipeline Metrics
|
||||
|
||||
パイプラインの実行詳細と関係:
|
||||
|
||||

|
||||
|
||||
主要な関係:
|
||||
- DriverTotalTime = ActiveTime + PendingTime + ScheduleTime
|
||||
- ActiveTime = ∑ OperatorTotalTime + OverheadTime
|
||||
- PendingTime = InputEmptyTime + OutputFullTime + PreconditionBlockTime + PendingFinishTime
|
||||
- InputEmptyTime = FirstInputEmptyTime + FollowupInputEmptyTime
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| DegreeOfParallelism | パイプライン実行の並行性の度合い。 |
|
||||
| TotalDegreeOfParallelism | 並行性の度合いの合計。同じパイプラインが複数のマシンで実行される可能性があるため、この項目はすべての値を集計します。 |
|
||||
| DriverPrepareTime | 準備フェーズにかかった時間。このメトリクスは DriverTotalTime に含まれません。 |
|
||||
| DriverTotalTime | 準備フェーズに費やされた時間を除くパイプラインの総実行時間。 |
|
||||
| ActiveTime | 各オペレーターの実行時間や、has_output、need_input などのメソッドを呼び出す際のフレームワーク全体のオーバーヘッドを含むパイプラインの実行時間。 |
|
||||
| PendingTime | さまざまな理由でスケジュールされることを妨げられたパイプラインの時間。 |
|
||||
| InputEmptyTime | 入力キューが空であるためにブロックされたパイプラインの時間。 |
|
||||
| FirstInputEmptyTime | 入力キューが空であるために最初にブロックされたパイプラインの時間。最初のブロック時間は、主にパイプラインの依存関係によって引き起こされるため、別途計算されます。 |
|
||||
| FollowupInputEmptyTime | 入力キューが空であるためにその後ブロックされたパイプラインの時間。 |
|
||||
| OutputFullTime | 出力キューが満杯であるためにブロックされたパイプラインの時間。 |
|
||||
| PreconditionBlockTime | 依存関係が満たされていないためにブロックされたパイプラインの時間。 |
|
||||
| PendingFinishTime | 非同期タスクの終了を待つためにブロックされたパイプラインの時間。 |
|
||||
| ScheduleTime | 準備キューに入ってから実行のためにスケジュールされるまでのパイプラインのスケジュール時間。 |
|
||||
| BlockByInputEmpty | InputEmpty のためにパイプラインがブロックされた回数。 |
|
||||
| BlockByOutputFull | OutputFull のためにパイプラインがブロックされた回数。 |
|
||||
| BlockByPrecondition | 未満の前提条件のためにパイプラインがブロックされた回数。 |
|
||||
|
||||
### Operator Metrics
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| PrepareTime | 準備に費やされた時間。 |
|
||||
| OperatorTotalTime | オペレーターによって消費された総時間。次の式を満たします: OperatorTotalTime = PullTotalTime + PushTotalTime + SetFinishingTime + SetFinishedTime + CloseTime。準備に費やされた時間は含まれません。 |
|
||||
| PullTotalTime | オペレーターが push_chunk を実行するのに費やす総時間。 |
|
||||
| PushTotalTime | オペレーターが pull_chunk を実行するのに費やす総時間。 |
|
||||
| SetFinishingTime | オペレーターが set_finishing を実行するのに費やす総時間。 |
|
||||
| SetFinishedTime | オペレーターが set_finished を実行するのに費やす総時間。 |
|
||||
| PushRowNum | オペレーターの入力行の累積数。 |
|
||||
| PullRowNum | オペレーターの出力行の累積数。 |
|
||||
| JoinRuntimeFilterEvaluate | ジョインランタイムフィルターが評価された回数。 |
|
||||
| JoinRuntimeFilterHashTime | ジョインランタイムフィルターのハッシュを計算するのに費やされた時間。 |
|
||||
| JoinRuntimeFilterInputRows | ジョインランタイムフィルターの入力行数。 |
|
||||
| JoinRuntimeFilterOutputRows | ジョインランタイムフィルターの出力行数。 |
|
||||
| JoinRuntimeFilterTime | ジョインランタイムフィルターに費やされた時間。 |
|
||||
|
||||
### Scan Operator
|
||||
|
||||
#### OLAP Scan Operator
|
||||
|
||||
OLAP_SCAN オペレーターは、StarRocks 内部テーブルからデータを読み取る役割を担っています。
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| Table | テーブル名。 |
|
||||
| Rollup | マテリアライズドビュー名。マテリアライズドビューがヒットしない場合、テーブル名と同じです。 |
|
||||
| SharedScan | enable_shared_scan セッション変数が有効かどうか。 |
|
||||
| TabletCount | タブレットの数。 |
|
||||
| MorselsCount | モーセルの数。これは基本的な IO 実行単位です。 |
|
||||
| PushdownPredicates | プッシュダウン述語の数。 |
|
||||
| Predicates | 述語式。 |
|
||||
| BytesRead | 読み取られたデータのサイズ。 |
|
||||
| CompressedBytesRead | ディスクから読み取られた圧縮データのサイズ。 |
|
||||
| UncompressedBytesRead | ディスクから読み取られた非圧縮データのサイズ。 |
|
||||
| RowsRead | 読み取られた行数(述語フィルタリング後)。 |
|
||||
| RawRowsRead | 読み取られた生の行数(述語フィルタリング前)。 |
|
||||
| ReadPagesNum | 読み取られたページ数。 |
|
||||
| CachedPagesNum | キャッシュされたページ数。 |
|
||||
| ChunkBufferCapacity | チャンクバッファの容量。 |
|
||||
| DefaultChunkBufferCapacity | チャンクバッファのデフォルト容量。 |
|
||||
| PeakChunkBufferMemoryUsage | チャンクバッファのピークメモリ使用量。 |
|
||||
| PeakChunkBufferSize | チャンクバッファのピークサイズ。 |
|
||||
| PrepareChunkSourceTime | チャンクソースの準備に費やされた時間。 |
|
||||
| ScanTime | 累積スキャン時間。スキャン操作は非同期 I/O スレッドプールで完了します。 |
|
||||
| IOTaskExecTime | IO タスクの実行時間。 |
|
||||
| IOTaskWaitTime | IO タスクのスケジュール実行までの成功した提出からの待機時間。 |
|
||||
| SubmitTaskCount | IO タスクが提出された回数。 |
|
||||
| SubmitTaskTime | タスク提出に費やされた時間。 |
|
||||
| PeakIOTasks | IO タスクのピーク数。 |
|
||||
| PeakScanTaskQueueSize | IO タスクキューのピークサイズ。 |
|
||||
|
||||
#### Connector Scan Operator
|
||||
|
||||
OLAP_SCAN オペレーターに似ていますが、Iceberg/Hive/Hudi/Detal などの外部テーブルをスキャンするために使用されます。
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| DataSourceType | データソースタイプ。HiveDataSource、ESDataSource などが含まれます。 |
|
||||
| Table | テーブル名。 |
|
||||
| TabletCount | タブレットの数。 |
|
||||
| MorselsCount | モーセルの数。 |
|
||||
| Predicates | 述語式。 |
|
||||
| PredicatesPartition | パーティションに適用される述語式。 |
|
||||
| SharedScan | `enable_shared_scan` セッション変数が有効かどうか。 |
|
||||
| ChunkBufferCapacity | チャンクバッファの容量。 |
|
||||
| DefaultChunkBufferCapacity | チャンクバッファのデフォルト容量。 |
|
||||
| PeakChunkBufferMemoryUsage | チャンクバッファのピークメモリ使用量。 |
|
||||
| PeakChunkBufferSize | チャンクバッファのピークサイズ。 |
|
||||
| PrepareChunkSourceTime | チャンクソースの準備にかかった時間。 |
|
||||
| ScanTime | スキャンの累積時間。スキャン操作は非同期 I/O スレッドプールで完了します。 |
|
||||
| IOTaskExecTime | I/O タスクの実行時間。 |
|
||||
| IOTaskWaitTime | IO タスクのスケジュール実行までの成功した提出からの待機時間。 |
|
||||
| SubmitTaskCount | IO タスクが提出された回数。 |
|
||||
| SubmitTaskTime | タスク提出にかかった時間。 |
|
||||
| PeakIOTasks | IO タスクのピーク数。 |
|
||||
| PeakScanTaskQueueSize | IO タスクキューのピークサイズ。 |
|
||||
|
||||
### Exchange Operator
|
||||
|
||||
Exchange Operator は BE ノード間でデータを送信する役割を担っています。いくつかの種類の交換操作があります: GATHER/BROADCAST/SHUFFLE。
|
||||
|
||||
Exchange Operator がクエリのボトルネックになる可能性のある典型的なシナリオ:
|
||||
1. Broadcast Join: これは小さなテーブルに適した方法です。しかし、例外的な場合にオプティマイザーが最適でないクエリプランを選択すると、ネットワーク帯域幅が大幅に増加する可能性があります。
|
||||
2. Shuffle Aggregation/Join: 大きなテーブルをシャッフルすると、ネットワーク帯域幅が大幅に増加する可能性があります。
|
||||
|
||||
#### Exchange Sink Operator
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| ChannelNum | チャネルの数。通常、チャネルの数は受信者の数と等しいです。 |
|
||||
| DestFragments | 目的地の FragmentInstance ID のリスト。 |
|
||||
| DestID | 目的地のノード ID。 |
|
||||
| PartType | データ分配モード。UNPARTITIONED、RANDOM、HASH_PARTITIONED、BUCKET_SHUFFLE_HASH_PARTITIONED などが含まれます。 |
|
||||
| SerializeChunkTime | チャンクをシリアライズするのにかかった時間。 |
|
||||
| SerializedBytes | シリアライズされたデータのサイズ。 |
|
||||
| ShuffleChunkAppendCounter | PartType が HASH_PARTITIONED または BUCKET_SHUFFLE_HASH_PARTITIONED の場合のチャンク追加操作の回数。 |
|
||||
| ShuffleChunkAppendTime | PartType が HASH_PARTITIONED または BUCKET_SHUFFLE_HASH_PARTITIONED の場合のチャンク追加操作にかかった時間。 |
|
||||
| ShuffleHashTime | PartType が HASH_PARTITIONED または BUCKET_SHUFFLE_HASH_PARTITIONED の場合のハッシュ計算にかかった時間。 |
|
||||
| RequestSent | 送信されたデータパケットの数。 |
|
||||
| RequestUnsent | 送信されなかったデータパケットの数。このメトリクスはショートサーキットロジックがある場合にゼロ以外になります。それ以外の場合はゼロです。 |
|
||||
| BytesSent | 送信されたデータのサイズ。 |
|
||||
| BytesUnsent | 送信されなかったデータのサイズ。このメトリクスはショートサーキットロジックがある場合にゼロ以外になります。それ以外の場合はゼロです。 |
|
||||
| BytesPassThrough | 目的地のノードが現在のノードである場合、データはネットワークを介して送信されず、パススルーデータと呼ばれます。このメトリクスはそのようなパススルーデータのサイズを示します。パススルーは `enable_exchange_pass_through` によって制御されます。 |
|
||||
| PassThroughBufferPeakMemoryUsage | パススルーバッファのピークメモリ使用量。 |
|
||||
| CompressTime | 圧縮時間。 |
|
||||
| CompressedBytes | 圧縮されたデータのサイズ。 |
|
||||
| OverallThroughput | スループットレート。 |
|
||||
| NetworkTime | データパケットの送信にかかった時間(受信後の処理時間を除く)。 |
|
||||
| NetworkBandwidth | 推定ネットワーク帯域幅。 |
|
||||
| WaitTime | 送信者キューが満杯のための待機時間。 |
|
||||
| OverallTime | 送信プロセス全体の総時間、つまり最初のデータパケットの送信から最後のデータパケットの正しい受信の確認まで。 |
|
||||
| RpcAvgTime | RPC の平均時間。 |
|
||||
| RpcCount | RPC の総数。 |
|
||||
|
||||
#### Exchange Source Operator
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| RequestReceived | 受信したデータパケットのサイズ。 |
|
||||
| BytesReceived | 受信したデータのサイズ。 |
|
||||
| DecompressChunkTime | チャンクを解凍するのにかかった時間。 |
|
||||
| DeserializeChunkTime | チャンクをデシリアライズするのにかかった時間。 |
|
||||
| ClosureBlockCount | ブロックされたクロージャの数。 |
|
||||
| ClosureBlockTime | クロージャのブロックされた時間。 |
|
||||
| ReceiverProcessTotalTime | 受信側の処理にかかった総時間。 |
|
||||
| WaitLockTime | ロック待機時間。 |
|
||||
|
||||
### Aggregate Operator
|
||||
|
||||
**Metrics List**
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `GroupingKeys` | `GROUP BY` カラム。 |
|
||||
| `AggregateFunctions` | 集計関数の計算にかかった時間。 |
|
||||
| `AggComputeTime` | AggregateFunctions + Group By の時間。 |
|
||||
| `ChunkBufferPeakMem` | チャンクバッファのピークメモリ使用量。 |
|
||||
| `ChunkBufferPeakSize` | チャンクバッファのピークサイズ。 |
|
||||
| `ExprComputeTime` | 式の計算にかかった時間。 |
|
||||
| `ExprReleaseTime` | 式の解放にかかった時間。 |
|
||||
| `GetResultsTime` | 集計結果を抽出するのにかかった時間。 |
|
||||
| `HashTableSize` | ハッシュテーブルのサイズ。 |
|
||||
| `HashTableMemoryUsage` | ハッシュテーブルのメモリサイズ。 |
|
||||
| `InputRowCount` | 入力行数。 |
|
||||
| `PassThroughRowCount` | 自動モードで、低集計後にストリーミングモードに劣化した場合のストリーミングモードで処理されたデータ行数。 |
|
||||
| `ResultAggAppendTime` | 集計結果カラムを追加するのにかかった時間。 |
|
||||
| `ResultGroupByAppendTime` | Group By カラムを追加するのにかかった時間。 |
|
||||
| `ResultIteratorTime` | ハッシュテーブルを反復するのにかかった時間。 |
|
||||
| `StreamingTime` | ストリーミングモードでの処理時間。 |
|
||||
|
||||
### Join Operator
|
||||
|
||||
**Metrics List**
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `DistributionMode` | 分配タイプ。BROADCAST、PARTITIONED、COLOCATE などが含まれます。 |
|
||||
| `JoinPredicates` | ジョイン述語。 |
|
||||
| `JoinType` | ジョインタイプ。 |
|
||||
| `BuildBuckets` | ハッシュテーブルのバケット数。 |
|
||||
| `BuildKeysPerBucket` | ハッシュテーブルのバケットごとのキー数。 |
|
||||
| `BuildConjunctEvaluateTime` | ビルドフェーズ中の結合評価にかかった時間。 |
|
||||
| `BuildHashTableTime` | ハッシュテーブルの構築にかかった時間。 |
|
||||
| `ProbeConjunctEvaluateTime` | プローブフェーズ中の結合評価にかかった時間。 |
|
||||
| `SearchHashTableTimer` | ハッシュテーブルを検索するのにかかった時間。 |
|
||||
| `CopyRightTableChunkTime` | 右テーブルからチャンクをコピーするのにかかった時間。 |
|
||||
| `OutputBuildColumnTime` | ビルド側のカラムを出力するのにかかった時間。 |
|
||||
| `OutputProbeColumnTime` | プローブ側のカラムを出力するのにかかった時間。 |
|
||||
| `HashTableMemoryUsage` | ハッシュテーブルのメモリ使用量。 |
|
||||
| `RuntimeFilterBuildTime` | ランタイムフィルターの構築にかかった時間。 |
|
||||
| `RuntimeFilterNum` | ランタイムフィルターの数。 |
|
||||
|
||||
### Window Function Operator
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `ProcessMode` | 実行モード。Materializing と Streaming の2つの部分を含みます。さらに、Cumulative、RemovableCumulative、ByDefinition も含まれます。 |
|
||||
| `ComputeTime` | ウィンドウ関数の計算にかかった時間。 |
|
||||
| `PartitionKeys` | パーティションカラム。 |
|
||||
| `AggregateFunctions` | 集計関数。 |
|
||||
| `ColumnResizeTime` | カラムのリサイズにかかった時間。 |
|
||||
| `PartitionSearchTime` | パーティション境界を検索するのにかかった時間。 |
|
||||
| `PeerGroupSearchTime` | ピアグループ境界を検索するのにかかった時間。ウィンドウタイプが `RANGE` の場合にのみ意味があります。 |
|
||||
| `PeakBufferedRows` | バッファ内のピーク行数。 |
|
||||
| `RemoveUnusedRowsCount` | 未使用のバッファが削除された回数。 |
|
||||
| `RemoveUnusedTotalRows` | 未使用のバッファから削除された行の総数。 |
|
||||
|
||||
### Sort Operator
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `SortKeys` | ソートキー。 |
|
||||
| `SortType` | クエリ結果のソート方法: フルソートまたはトップ N 結果のソート。 |
|
||||
| `MaxBufferedBytes` | バッファされたデータのピークサイズ。 |
|
||||
| `MaxBufferedRows` | バッファされた行のピーク数。 |
|
||||
| `NumSortedRuns` | ソートされたランの数。 |
|
||||
| `BuildingTime` | ソート中に内部データ構造を維持するのにかかった時間。 |
|
||||
| `MergingTime` | ソート中にソートされたランをマージするのにかかった時間。 |
|
||||
| `SortingTime` | ソートにかかった時間。 |
|
||||
| `OutputTime` | 出力ソートシーケンスを構築するのにかかった時間。 |
|
||||
|
||||
### Merge Operator
|
||||
|
||||
| Metric | Description | Level |
|
||||
|--------|-------------|-------|
|
||||
| `Limit` | リミット。 | Primary |
|
||||
| `Offset` | オフセット。 | Primary |
|
||||
| `StreamingBatchSize` | ストリーミングモードでマージが実行される場合のマージ操作ごとに処理されるデータのサイズ | Primary |
|
||||
| `LateMaterializationMaxBufferChunkNum` | 後期実体化が有効な場合のバッファ内の最大チャンク数。 | Primary |
|
||||
| `OverallStageCount` | すべてのステージの総実行回数。 | Primary |
|
||||
| `OverallStageTime` | 各ステージの総実行時間。 | Primary |
|
||||
| `1-InitStageCount` | Init ステージの実行回数。 | Secondary |
|
||||
| `2-PrepareStageCount` | Prepare ステージの実行回数。 | Secondary |
|
||||
| `3-ProcessStageCount` | Process ステージの実行回数。 | Secondary |
|
||||
| `4-SplitChunkStageCount` | SplitChunk ステージの実行回数。 | Secondary |
|
||||
| `5-FetchChunkStageCount` | FetchChunk ステージの実行回数。 | Secondary |
|
||||
| `6-PendingStageCount` | Pending ステージの実行回数。 | Secondary |
|
||||
| `7-FinishedStageCount` | Finished ステージの実行回数。 | Secondary |
|
||||
| `1-InitStageTime` | Init ステージの実行時間。 | Secondary |
|
||||
| `2-PrepareStageTime` | Prepare ステージの実行時間。 | Secondary |
|
||||
| `3-ProcessStageTime` | Process ステージの実行時間。 | Secondary |
|
||||
| `4-SplitChunkStageTime` | Split ステージにかかった時間。 | Secondary |
|
||||
| `5-FetchChunkStageTime` | Fetch ステージにかかった時間。 | Secondary |
|
||||
| `6-PendingStageTime` | Pending ステージにかかった時間。 | Secondary |
|
||||
| `7-FinishedStageTime` | Finished ステージにかかった時間。 | Secondary |
|
||||
| `LateMaterializationGenerateOrdinalTime` | 後期実体化中に序数カラムを生成するのにかかった時間。 | Tertiary |
|
||||
| `SortedRunProviderTime` | Process ステージ中にプロバイダーからデータを取得するのにかかった時間。 | Tertiary |
|
||||
|
||||
### TableFunction Operator
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `TableFunctionExecTime` | テーブル関数の計算時間。 |
|
||||
| `TableFunctionExecCount` | テーブル関数の実行回数。 |
|
||||
|
||||
### Project Operator
|
||||
|
||||
Project Operator は `SELECT <expr>` を実行する役割を担っています。クエリに高価な式が含まれている場合、このオペレーターはかなりの時間を要することがあります。
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `ExprComputeTime` | 式の計算時間。 |
|
||||
| `CommonSubExprComputeTime` | 共通部分式の計算時間。 |
|
||||
|
||||
### LocalExchange Operator
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| Type | Local Exchange のタイプ。`Passthrough`、`Partition`、`Broadcast` が含まれます。 |
|
||||
| `ShuffleNum` | シャッフルの数。このメトリクスは `Type` が `Partition` の場合にのみ有効です。 |
|
||||
| `LocalExchangePeakMemoryUsage` | ピークメモリ使用量。 |
|
||||
| `LocalExchangePeakBufferSize` | バッファのピークサイズ。 |
|
||||
| `LocalExchangePeakBufferMemoryUsage` | バッファのピークメモリ使用量。 |
|
||||
| `LocalExchangePeakBufferChunkNum` | バッファ内のピークチャンク数。 |
|
||||
| `LocalExchangePeakBufferRowNum` | バッファ内のピーク行数。 |
|
||||
| `LocalExchangePeakBufferBytes` | バッファ内のデータのピークサイズ。 |
|
||||
| `LocalExchangePeakBufferChunkSize` | バッファ内のチャンクのピークサイズ。 |
|
||||
| `LocalExchangePeakBufferChunkRowNum` | バッファ内のチャンクごとのピーク行数。 |
|
||||
| `LocalExchangePeakBufferChunkBytes` | バッファ内のチャンクごとのデータのピークサイズ。 |
|
||||
|
||||
### OlapTableSink Operator
|
||||
|
||||
OlapTableSink Operator は `INSERT INTO <table>` 操作を実行する役割を担っています。
|
||||
|
||||
:::tip
|
||||
- `OlapTableSink` の `PushChunkNum` メトリクスの最大値と最小値の差が大きい場合、上流オペレーターでのデータスキューを示しており、ロードパフォーマンスのボトルネックになる可能性があります。
|
||||
- `RpcClientSideTime` は `RpcServerSideTime` にネットワーク伝送時間と RPC フレームワーク処理時間を加えたものです。`RpcClientSideTime` と `RpcServerSideTime` の間に大きな差がある場合、圧縮を有効にして伝送時間を短縮することを検討してください。
|
||||
:::
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `IndexNum` | 目的地のテーブルに作成された同期マテリアライズドビューの数。 |
|
||||
| `ReplicatedStorage` | シングルリーダーレプリケーションが有効かどうか。 |
|
||||
| `TxnID` | ロードトランザクションの ID。 |
|
||||
| `RowsRead` | 上流オペレーターから読み取られた行数。 |
|
||||
| `RowsFiltered` | データ品質が不十分なためにフィルタリングされた行数。 |
|
||||
| `RowsReturned` | 目的地のテーブルに書き込まれた行数。 |
|
||||
| `RpcClientSideTime` | クライアント側で記録されたロードの総 RPC 時間消費。 |
|
||||
| `RpcServerSideTime` | サーバー側で記録されたロードの総 RPC 時間消費。 |
|
||||
| `PrepareDataTime` | データ準備フェーズの総時間消費。データ形式の変換とデータ品質チェックを含みます。 |
|
||||
| `SendDataTime` | データ送信のローカル時間消費。データのシリアライズと圧縮、および送信者キューへのタスクの提出時間を含みます。 |
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 30
|
||||
keywords: ['profile', 'query']
|
||||
---
|
||||
|
||||
# Query Profile 概要
|
||||
|
||||
## はじめに
|
||||
|
||||
Query Profile は、クエリに関与するすべての作業ノードの実行情報を記録し、クエリパフォーマンスに影響を与えるボトルネックを迅速に特定するのに役立ちます。これは、StarRocks におけるクエリパフォーマンスの診断と調整のための強力なツールです。
|
||||
|
||||
> v3.3.0 以降、StarRocks は INSERT INTO FILES() および Broker Load を使用したデータロードのための Query Profile を提供することをサポートしています。関連するメトリクスの詳細については、 [OlapTableSink Operator](./query_profile_operator_metrics.md#olaptablesink-operator) を参照してください。
|
||||
|
||||
## Query Profile の有効化方法
|
||||
|
||||
### Query Profile の有効化
|
||||
|
||||
Query Profile を有効にするには、変数 `enable_profile` を `true` に設定します。
|
||||
|
||||
```SQL
|
||||
SET enable_profile = true;
|
||||
SET GLOBAL enable_profile = true;
|
||||
```
|
||||
|
||||
### スロークエリのための Query Profile
|
||||
|
||||
長期間にわたって Query Profile をグローバルに有効にすることは、追加のシステム負荷を課す可能性があるため、本番環境では推奨されません。スロークエリのみをキャプチャして分析するには、変数 `big_query_profile_threshold` を `0s` より大きい時間に設定します。例えば、`30s` に設定すると、30 秒を超えるクエリのみが Query Profile をトリガーします。
|
||||
|
||||
```SQL
|
||||
-- 30 秒
|
||||
SET global big_query_profile_threshold = '30s';
|
||||
|
||||
-- 500 ミリ秒
|
||||
SET global big_query_profile_threshold = '500ms';
|
||||
|
||||
-- 60 分
|
||||
SET global big_query_profile_threshold = '60m';
|
||||
```
|
||||
|
||||
### 実行時 Query Profile
|
||||
|
||||
長時間実行されるクエリでは、完了前に進捗や問題を特定するのが難しい場合があります。実行時 Query Profile 機能 (v3.1+) は、実行中に固定間隔で Query Profile データを収集し、クエリの進捗やボトルネックに関するリアルタイムの洞察を提供します。
|
||||
|
||||
Query Profile が有効になっている場合、実行時 Query Profile はデフォルトで 10 秒の報告間隔で自動的に有効化されます。`runtime_profile_report_interval` で間隔を調整できます。
|
||||
|
||||
```SQL
|
||||
SET runtime_profile_report_interval = 30;
|
||||
```
|
||||
|
||||
### 設定
|
||||
|
||||
| 設定項目 | タイプ | 有効な値 | デフォルト | 説明 |
|
||||
|-----------------------------------|--------------|-----------------|---------|-------------------------------------------------------------------------------------------|
|
||||
| enable_profile | セッション変数 | true/false | false | Query Profile を有効化 |
|
||||
| pipeline_profile_level | セッション変数 | 1/2 | 1 | 1: メトリクスをマージ; 2: 元の構造を保持 (可視化ツールを無効化) |
|
||||
| runtime_profile_report_interval | セッション変数 | 正の整数 | 10 | 実行時 Query Profile の報告間隔 (秒) |
|
||||
| big_query_profile_threshold | セッション変数 | 文字列 | 0s | この期間を超えるクエリに対して Query Profile を有効化 (例: '30s', '500ms', '60m') |
|
||||
| enable_statistics_collect_profile | FE ダイナミック | true/false | false | 統計収集関連のクエリに対する Query Profile を有効化 |
|
||||
|
||||
## Query Profile の取得方法
|
||||
|
||||
### Web UI 経由
|
||||
|
||||
1. ブラウザで `http://<fe_ip>:<fe_http_port>` にアクセスします。
|
||||
2. 上部ナビゲーションで **queries** をクリックします。
|
||||
3. **Finished Queries** リストで、分析したいクエリを選択し、**Profile** 列のリンクをクリックします。
|
||||
|
||||

|
||||
|
||||
選択した Query Profile の詳細ページにリダイレクトされます。
|
||||
|
||||

|
||||
|
||||
### SQL 関数 (`get_query_profile`) 経由
|
||||
|
||||
ワークフローの例:
|
||||
- `last_query_id()`: セッションで最も最近実行されたクエリの ID を返します。最後のクエリのプロファイルを迅速に取得するのに便利です。
|
||||
- `show profilelist;`: 最近のクエリとその ID およびステータスを一覧表示します。プロファイル分析に必要な `query_id` を見つけるのに使用します。
|
||||
- `get_query_profile('<query_id>')`: 指定されたクエリの詳細な実行プロファイルを返します。クエリがどのように実行され、どこで時間やリソースが費やされたかを分析するのに使用します。
|
||||
|
||||
```sql
|
||||
-- プロファイリング機能を有効にします。
|
||||
set enable_profile = true;
|
||||
-- シンプルなクエリを実行します。
|
||||
select 1;
|
||||
-- クエリの query_id を取得します。
|
||||
select last_query_id();
|
||||
+--------------------------------------+
|
||||
| last_query_id() |
|
||||
+--------------------------------------+
|
||||
| bd3335ce-8dde-11ee-92e4-3269eb8da7d1 |
|
||||
+--------------------------------------+
|
||||
-- プロファイルのリストを取得します。
|
||||
show profilelist;
|
||||
-- クエリプロファイルを取得します。
|
||||
select get_query_profile('502f3c04-8f5c-11ee-a41f-b22a2c00f66b')\G
|
||||
```
|
||||
|
||||
### マネージドバージョンで
|
||||
|
||||
StarRocks Managed (Enterprise) 環境では、Web コンソールのクエリ履歴から直接クエリプロファイルにアクセスできます。マネージド UI は、各クエリの実行プロファイルを直感的に視覚化し、手動の SQL コマンドなしでパフォーマンスを分析し、ボトルネックを特定するのを容易にします。
|
||||
|
||||
## Query Profile の解釈
|
||||
|
||||
### Explain Analyze
|
||||
|
||||
ほとんどのユーザーは、生のテキストを直接分析するのが難しいかもしれません。StarRocks は、より直感的に理解できる [Text-based Query Profile Visualized Analysis](./query_profile_text_based_analysis.md) 方法を提供しています。
|
||||
|
||||
### マネージドバージョン
|
||||
|
||||
StarRocks Enterprise Edition (EE) では、マネージドバージョンがクエリプロファイルのためのビジュアライゼーションツールを内蔵しています。このツールは、複雑なクエリ実行の詳細を生のテキスト出力と比較してはるかに簡単に解釈できるインタラクティブなグラフィカルインターフェースを提供します。
|
||||
|
||||
**ビジュアライゼーションツールの主な機能:**
|
||||
- **オペレーター単位の内訳:** 各オペレーターのメトリクス (時間、行、メモリ) が明確に表示されたツリーまたはグラフとして実行計画を表示します。
|
||||
- **ボトルネックのハイライト:** カラーコード化されたインジケーターを通じて、遅いまたはリソース集約的なオペレーターを迅速に特定します。
|
||||
- **ドリルダウン機能:** 任意のオペレーターをクリックして、入力/出力行、CPU 時間、メモリ使用量などの詳細な統計を確認します。
|
||||
|
||||
**使用方法:**
|
||||
1. StarRocks Managed Web コンソールを開きます。
|
||||
2. **Query** または **Query History** セクションに移動します。
|
||||
3. クエリを選択し、**Profile** または **Visualize** ボタンをクリックします。
|
||||
4. ビジュアライズされたプロファイルを探索して、パフォーマンスを分析し、最適化の機会を特定します。
|
||||
|
||||
このビジュアライゼーションツールは、Managed/Enterprise Edition に限定されており、複雑なワークロードのトラブルシューティングとパフォーマンスチューニングを加速するように設計されています。
|
||||
|
|
@ -1,14 +1,15 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 60
|
||||
---
|
||||
|
||||
# テキストベースのクエリのプロファイルの可視化分析
|
||||
# Explain Analyze
|
||||
|
||||
このトピックでは、MySQL クライアントを使用してテキストベースの Query Profile を取得し、分析する方法を紹介します。
|
||||
このドキュメントでは、StarRocks でテキストベースの Query Profile を取得し、分析する方法を説明します。これにより、クエリパフォーマンスを理解し、SQL クエリを最適化する方法を見つける手助けをします。
|
||||
|
||||
## ANALYZE PROFILE を使用して既存のクエリのプロファイルを分析する
|
||||
|
||||
クラスター内の既存の(履歴または実行中の)クエリのテキストベースのプロファイルを分析するには、まず [SHOW PROFILELIST](../sql-reference/sql-statements/cluster-management/plan_profile/SHOW_PROFILELIST.md) ステートメントを使用してクエリの概要を取得する必要があります。このコマンドは、正常に終了したクエリ、エラーで失敗したクエリ、および(10 秒以上実行中でまだ終了していない)クエリをすべてリストします。このステートメントを通じて、後続の分析のための対応する Query ID を取得できます。構文は次のとおりです。
|
||||
クラスター内の既存の(履歴または実行中の)クエリのテキストベースのプロファイルを分析するには、まず [SHOW PROFILELIST](../../sql-reference/sql-statements/cluster-management/plan_profile/SHOW_PROFILELIST.md) ステートメントを使用してクエリの概要を取得する必要があります。このコマンドは、正常に終了したクエリ、エラーで失敗したクエリ、およびまだ実行中のクエリ(10 秒以上経過しても終了していないもの)を一覧表示します。このステートメントを通じて、後続の分析のための対応する Query ID を取得できます。構文は次のとおりです。
|
||||
|
||||
```SQL
|
||||
SHOW PROFILELIST [LIMIT <num>];
|
||||
|
|
@ -35,59 +36,59 @@ SHOW PROFILELIST LIMIT 5;
|
|||
+--------------------------------------+---------------------+-------+----------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
Query ID を取得したら、[ANALYZE PROFILE](../sql-reference/sql-statements/cluster-management/plan_profile/ANALYZE_PROFILE.md) ステートメントを使用して Query Profile の分析を進めることができます。構文は次のとおりです。
|
||||
Query ID を取得したら、[ANALYZE PROFILE](../../sql-reference/sql-statements/cluster-management/plan_profile/ANALYZE_PROFILE.md) ステートメントを使用して Query Profile の分析を進めることができます。構文は次のとおりです。
|
||||
|
||||
```SQL
|
||||
ANALYZE PROFILE FROM '<Query_ID>' [, <Node_ID> [, ...] ]
|
||||
```
|
||||
|
||||
- `Query_ID`: `SHOW PROFILELIST` ステートメントから取得したクエリに対応する ID。
|
||||
- `Node_ID`: プロファイルノード ID。ID が指定されたノードについては、StarRocks はそのノードの詳細なメトリック情報を返します。ID が指定されていないノードについては、StarRocks は概要情報のみを返します。
|
||||
- `Node_ID`: プロファイルノード ID。ID が指定されたノードについては、StarRocks はそのノードの詳細なメトリック情報を返します。ID が指定されていないノードについては、StarRocks は要約情報のみを返します。
|
||||
|
||||
プロファイルには次のセクションが含まれます。
|
||||
|
||||
- Summary: プロファイルの概要情報。
|
||||
- Summary: プロファイルの要約情報。
|
||||
- QueryID
|
||||
- バージョン情報
|
||||
- クエリの状態(`Finished`、`Error`、`Running` を含む)
|
||||
- クエリの総時間
|
||||
- 総クエリ時間
|
||||
- メモリ使用量
|
||||
- CPU 使用率が最も高いトップ 10 ノード
|
||||
- メモリ使用率が最も高いトップ 10 ノード
|
||||
- デフォルト値とは異なる値を持つセッション変数
|
||||
- デフォルト値と異なる値を持つセッション変数
|
||||
- Fragments: 各フラグメント内の各ノードのメトリクスを表示。
|
||||
- 各ノードの時間、メモリ使用量、コスト推定情報、出力行数。
|
||||
- 時間使用率が 30% を超えるノードは赤で強調表示。
|
||||
- 時間使用率が 15% を超え、30% 未満のノードはピンクで強調表示。
|
||||
- 各ノードの時間、メモリ使用量、コスト見積もり情報、および出力行。
|
||||
- 時間使用率が 30% を超えるノードは赤で強調表示されます。
|
||||
- 時間使用率が 15% を超え、30% 未満のノードはピンクで強調表示されます。
|
||||
|
||||
例 1: ノード ID を指定せずに Query Profile をクエリ。
|
||||
|
||||

|
||||

|
||||
|
||||
例 2: ノード ID を `0` と指定して Query Profile をクエリ。StarRocks はノード ID `0` のすべての詳細なメトリクスを返し、問題の特定を容易にするために高使用率のメトリクスを強調表示します。
|
||||
例 2: Query Profile をクエリし、ノード ID を `0` と指定。StarRocks はノード ID `0` のすべての詳細なメトリクスを返し、問題の特定を容易にするために高使用率のメトリクスを強調表示します。
|
||||
|
||||

|
||||

|
||||
|
||||
さらに、上記の方法は、実行中のクエリのために生成されたプロファイルである Runtime Query Profile の表示と分析もサポートしています。Query Profile 機能が有効になっている場合、この方法を使用して 10 秒以上実行中のクエリのプロファイルを取得できます。
|
||||
さらに、上記の方法は、実行中のクエリに対して生成されたプロファイルである Runtime Query Profile の表示と分析もサポートしています。Query Profile 機能が有効になっている場合、この方法を使用して 10 秒以上実行中のクエリのプロファイルを取得できます。
|
||||
|
||||
完了したクエリのものと比較して、実行中のクエリのテキストベースの Query Profile には次の情報が含まれます。
|
||||
|
||||
- オペレーターの状態:
|
||||
- ⏳: オペレーターが開始されていません。これらのオペレーターは依存関係のために実行が開始されていない可能性があります。
|
||||
- 🚀: 実行中のオペレーター。
|
||||
- ✅: 実行が完了したオペレーター。
|
||||
- Operator の状態:
|
||||
- ⏳: 開始されていない Operator。これらの Operator は依存関係のために実行を開始していない可能性があります。
|
||||
- 🚀: 実行中の Operator。
|
||||
- ✅: 実行を完了した Operator。
|
||||
|
||||
- 全体の進捗: `実行が完了したオペレーターの数 / オペレーターの総数` に基づいて計算されます。データ行の詳細情報が不足しているため、この値は若干歪む可能性があります。
|
||||
- 全体の進捗状況: `実行を完了した Operator の数 / 総 Operator 数` に基づいて計算されます。データ行の詳細情報が不足しているため、この値は若干歪む可能性があります。
|
||||
|
||||
- オペレーターの進捗: `処理された行数 / 行の総数` に基づいて計算されます。行の総数を計算できない場合、進捗は `?` と表示されます。
|
||||
- Operator の進捗状況: `処理された行数 / 総行数` に基づいて計算されます。総行数が計算できない場合、進捗は `?` と表示されます。
|
||||
|
||||
例:
|
||||
|
||||

|
||||

|
||||
|
||||
## EXPLAIN ANALYZE を使用してプロファイル分析のためのクエリをシミュレートする
|
||||
|
||||
StarRocks は [EXPLAIN ANALYZE](../sql-reference/sql-statements/cluster-management/plan_profile/EXPLAIN_ANALYZE.md) ステートメントを提供しており、クエリのプロファイルを直接シミュレートして分析することができます。構文は次のとおりです。
|
||||
StarRocks は [EXPLAIN ANALYZE](../../sql-reference/sql-statements/cluster-management/plan_profile/EXPLAIN_ANALYZE.md) ステートメントを提供しており、クエリのプロファイルを直接シミュレートして分析することができます。構文は次のとおりです。
|
||||
|
||||
```SQL
|
||||
EXPLAIN ANALYZE <sql_statement>
|
||||
|
|
@ -95,19 +96,19 @@ EXPLAIN ANALYZE <sql_statement>
|
|||
|
||||
`EXPLAIN ANALYZE` を実行すると、StarRocks はデフォルトで現在のセッションに対して Query Profile 機能を有効にします。
|
||||
|
||||
現在、`EXPLAIN ANALYZE` は 2 種類の SQL ステートメントをサポートしています: SELECT ステートメントと INSERT INTO ステートメント。StarRocks のデフォルトカタログ内の内部テーブルに対する INSERT INTO ステートメントの Query Profile のシミュレーションと分析のみが可能です。INSERT INTO ステートメントの Query Profile をシミュレーションおよび分析する際、実際のデータはロードされません。デフォルトで、インポートトランザクションは中止され、分析中にデータに意図しない変更が加えられないようにします。
|
||||
現在、`EXPLAIN ANALYZE` は 2 種類の SQL ステートメントをサポートしています: SELECT ステートメントと INSERT INTO ステートメント。StarRocks のデフォルトカタログ内の内部テーブルに対してのみ、INSERT INTO ステートメントの Query Profile をシミュレートして分析できます。INSERT INTO ステートメントの Query Profile をシミュレートして分析する際には、実際のデータはロードされません。デフォルトでは、分析中にデータに意図しない変更が加えられないように、インポートトランザクションは中止されます。
|
||||
|
||||
例 1: SELECT ステートメントをシミュレートして分析。クエリ結果は破棄されます。
|
||||
|
||||

|
||||

|
||||
|
||||
例 2: INSERT INTO ステートメントをシミュレートして分析。ロードトランザクションは中止されます。
|
||||
|
||||

|
||||

|
||||
|
||||
## 制限事項
|
||||
|
||||
- `EXPLAIN ANALYZE INSERT INTO` ステートメントはデフォルトカタログ内のテーブルに対してのみサポートされています。
|
||||
- より良い視覚効果を得るために、出力テキストには色付け、ハイライト、その他の機能を提供するために ANSI 文字が含まれています。MyCLI クライアントの使用を推奨します。ANSI 機能をサポートしていないクライアント(MySQL クライアントなど)では、表示が若干乱れることがありますが、通常は使用に影響しません。例えば:
|
||||
|
||||

|
||||

|
||||
|
|
@ -0,0 +1,193 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 40
|
||||
keywords: ['profile', 'query']
|
||||
---
|
||||
|
||||
# クエリチューニングレシピ
|
||||
|
||||
> 実践的なプレイブック: **症状 → 根本原因 → 実証済みの修正**。
|
||||
> プロファイルを開いて問題のあるメトリックを見つけたが、「_次に何をすべきか?_」という問いに答える必要があるときに使用します。
|
||||
|
||||
---
|
||||
|
||||
## 1 · 迅速な診断ワークフロー
|
||||
|
||||
1. **実行概要をざっと見る**
|
||||
`QueryPeakMemoryUsagePerNode > 80 %` または `QuerySpillBytes > 1 GB` の場合、メモリとスピルのレシピに直接進みます。
|
||||
|
||||
2. **最も遅いパイプライン / オペレーターを見つける**
|
||||
⟶ *Query Profile UI* で **Sort by OperatorTotalTime %** をクリックします。
|
||||
最も負荷の高いオペレーターが次に読むべきレシピブロックを教えてくれます(Scan, Join, Aggregate など)。
|
||||
|
||||
3. **ボトルネックのサブタイプを確認する**
|
||||
各レシピはその*シグネチャ*メトリックパターンから始まります。修正を試みる前にそれらを一致させます。
|
||||
|
||||
---
|
||||
|
||||
## 2 · オペレーター別レシピ
|
||||
|
||||
### 2.1 OLAP / コネクタースキャン [[metrics]](./query_profile_operator_metrics.md#scan-operator)
|
||||
|
||||
Scan Operator 内のさまざまなメトリックをよりよく理解するために、以下の図はこれらのメトリックとストレージ構造との関連を示しています。
|
||||
|
||||

|
||||
|
||||
ディスクからデータを取得し、述語を適用するために、ストレージエンジンはいくつかの技術を利用します:
|
||||
1. **データストレージ**: エンコードおよび圧縮されたデータは、さまざまなインデックスと共にセグメントに分けられてディスクに保存されます。
|
||||
2. **インデックスフィルタリング**: エンジンは、BitmapIndex、BloomfilterIndex、ZonemapIndex、ShortKeyIndex、NGramIndex などのインデックスを活用して不要なデータをスキップします。
|
||||
3. **プッシュダウン述語**: `a > 1` のような単純な述語は、特定の列で評価されるようにプッシュダウンされます。
|
||||
4. **後期実体化**: 必要な列とフィルタリングされた行のみがディスクから取得されます。
|
||||
5. **非プッシュダウン述語**: プッシュダウンできない述語は評価されます。
|
||||
6. **プロジェクション式**: `SELECT a + 1` のような式が計算されます。
|
||||
|
||||
Scan Operator は、IO タスクを実行するための追加のスレッドプールを利用します。したがって、このノードの時間メトリックの関係は以下に示されています。
|
||||
|
||||

|
||||
|
||||
#### 一般的なパフォーマンスのボトルネック
|
||||
|
||||
**コールドまたは遅いストレージ** – `BytesRead`、`ScanTime`、または `IOTaskExecTime` が支配的で、ディスク I/O が 80‑100 % の範囲にある場合、スキャンはコールドまたは過小プロビジョニングされたストレージにヒットしています。ホットデータを NVMe/SSD に移動し、ストレージキャッシュを有効にするか、S3/HDFS をスキャンしている場合は `remote_cache_capacity` を増やします。
|
||||
|
||||
**フィルタープッシュダウンの欠如** – `PushdownPredicates` が 0 に近いままで `ExprFilterRows` が高い場合、述語がストレージ層に到達していません。単純な比較として書き直す(`%LIKE%` や広範な `OR` チェーンを避ける)か、ゾーンマップ/Bloom インデックスやマテリアライズドビューを追加してプッシュダウンできるようにします。
|
||||
|
||||
**スレッドプールの枯渇** – 高い `IOTaskWaitTime` と低い `PeakIOTasks` は、I/O スレッドプールが飽和していることを示します。BE の `max_io_threads` を増やすか、キャッシュを拡大してより多くのタスクを同時に実行できるようにします。
|
||||
|
||||
**タブレット間のデータスキュー** – 最大と最小の `OperatorTotalTime` の間に大きなギャップがある場合、一部のタブレットが他よりも多くの作業をしています。高いカーディナリティのキーで再バケット化するか、バケット数を増やして負荷を分散します。
|
||||
|
||||
**Rowset/segment の断片化** – `RowsetsReadCount`/`SegmentsReadCount` が急増し、長い `SegmentInitTime` がある場合、多くの小さな rowset が存在します。手動でのコンパクションをトリガーし、小さなロードをバッチ処理してセグメントを事前にマージします。
|
||||
|
||||
**累積されたソフトデリート** – 大きな `DeleteFilterRows` は、ソフトデリートの使用が多いことを示します。BE コンパクションを実行してトゥームストーンを削除し、削除ビットマップを統合します。
|
||||
|
||||
### 2.2 集計 [[metrics]](./query_profile_operator_metrics.md#aggregate-operator)
|
||||
|
||||

|
||||
Aggregate Operator は、集計関数、`GROUP BY`、および `DISTINCT` の実行を担当します。
|
||||
|
||||
**集計アルゴリズムの多様な形式**
|
||||
|
||||
| 形式 | プランナーが選択する条件 | 内部データ構造 | 特徴 / 注意点 |
|
||||
|------|----------------------------|-------------------------|-----------------------|
|
||||
| ハッシュ集計 | キーがメモリに収まる; カーディナリティが極端でない | SIMD プロービングを備えたコンパクトなハッシュテーブル | デフォルトパス、適度なキー数に最適 |
|
||||
| ソート集計 | 入力が GROUP BY キーで既に順序付けされている | 単純な行比較 + 実行状態 | ハッシュテーブルコストがゼロ、プロービングが重いスキューで通常 2-3 倍速い |
|
||||
| スピル可能な集計 (3.2+) | ハッシュテーブルがメモリ制限を超える | ディスクスピルパーティションを持つハイブリッドハッシュ/マージ | OOM を防ぎ、パイプラインの並行性を維持 |
|
||||
|
||||
**多段階分散集計**
|
||||
|
||||
StarRocks では、集計は分散方式で実装されており、クエリパターンとオプティマイザの決定に応じて多段階になることがあります。
|
||||
|
||||
```
|
||||
┌─────────┐ ┌──────────┐ ┌────────────┐ ┌────────────┐
|
||||
│ Stage 0 │ local │ Stage 1 │ shard/ │ Stage 2 │ gather/│ Stage 3 │ final
|
||||
│ Partial │───► │ Update │ hash │ Merge │ shard │ Finalize │ output
|
||||
└─────────┘ └──────────┘ └────────────┘ └────────────┘
|
||||
```
|
||||
|
||||
| ステージ | 使用される条件 | 実行内容 |
|
||||
|--------|------------|--------------|
|
||||
| ワンステージ | `DISTRIBUTED BY` が `GROUP BY` のサブセットで、パーティションがコロケートされている | 部分集計が即座に最終結果になります。 |
|
||||
| ツーステージ (ローカル + グローバル) | 一般的な分散 `GROUP BY` | 各 BE 内の Stage 0 が重複を適応的に圧縮し、Stage 1 が `GROUP BY` に基づいてデータをシャッフルしてからグローバル集計を実行します。 |
|
||||
| スリーステージ (ローカル + シャッフル + ファイナル) | 重い `DISTINCT` と高カーディナリティの `GROUP BY` | 上記のように Stage 0; Stage 1 が `GROUP BY` によってシャッフルし、`GROUP BY` と `DISTINCT` で集計; Stage 2 が部分状態を `GROUP BY` としてマージします。 |
|
||||
| フォーステージ (ローカル + 部分 + 中間 + ファイナル) | 重い `DISTINCT` と低カーディナリティの `GROUP BY` | 単一ポイントのボトルネックを避けるために `GROUP BY` と `DISTINCT` によってシャッフルする追加のステージを導入します。 |
|
||||
|
||||
#### 一般的なパフォーマンスのボトルネック
|
||||
|
||||
**高カーディナリティの GROUP BY** – `HashTableSize` または `HashTableMemoryUsage` がメモリ制限に向かって膨らむ場合、グループ化キーが広すぎるか、非常に異なるものです。ソートされたストリーミング集計 (`enable_streaming_preaggregation = true`) を有効にし、ロールアップマテリアライズドビューを作成するか、広い文字列キーを `INT` にキャストします。
|
||||
|
||||
**シャッフルスキュー** – フラグメント間で `HashTableSize` または `InputRowCount` に大きな差がある場合、不均衡なシャッフルを示します。キーにソルト列を追加するか、`DISTINCT [skew]` ヒントを使用して行を均等に分配します。
|
||||
|
||||
**状態が重い集計関数** – `AggregateFunctions` が実行時間を支配し、関数に `HLL_`、`BITMAP_`、または `COUNT(DISTINCT)` が含まれる場合、巨大な状態オブジェクトが移動されています。取り込み中に HLL/ビットマップスケッチを事前に計算するか、近似バリアントに切り替えます。
|
||||
|
||||
**部分集計の劣化** – 大きな `InputRowCount` と控えめな `AggComputeTime`、および上流の EXCHANGE での大規模な `BytesSent` は、事前集計がバイパスされたことを意味します。`SET streaming_preaggregation_mode = "force_preaggregation"` で強制的にオンに戻します。
|
||||
|
||||
**高価なキー式** – `ExprComputeTime` が `AggComputeTime` に匹敵する場合、GROUP BY キーが行ごとに計算されています。これらの式をサブクエリで実体化するか、生成列に昇格させます。
|
||||
|
||||
### 2.3 ジョイン [[metrics]](./query_profile_operator_metrics.md#join-operator)
|
||||
|
||||

|
||||
|
||||
Join Operator は、明示的なジョインまたは暗黙のジョインを実装する責任があります。
|
||||
|
||||
実行中、ジョインオペレーターはパイプラインエンジン内で並行して実行される Build (ハッシュテーブル構築) フェーズと Probe フェーズに分割されます。ベクトルチャンク (最大 4096 行) は SIMD でバッチハッシュされ、消費されたキーは実行時フィルター (Bloom または IN フィルター) を生成し、プローブ入力を早期に削減するために上流のスキャンにプッシュバックされます。
|
||||
|
||||
**ジョイン戦略**
|
||||
|
||||
StarRocks は、ベクトル化され、パイプラインに適したハッシュジョインコアに依存しており、コストベースオプティマイザがプラン時に評価する 4 つの物理戦略に組み込むことができます。
|
||||
|
||||
| 戦略 | オプティマイザが選択する条件 | 高速化の要因 |
|
||||
|----------|-----------------------------|---------------------|
|
||||
| Colocate Join | 両方のテーブルが同じコロケーショングループに属している (同一のバケットキー、バケット数、レプリカレイアウト)。  | ネットワークシャッフルなし: 各 BE はローカルバケットのみをジョインします。 |
|
||||
| Bucket-Shuffle Join | ジョインテーブルの一方がジョインキーと同じバケットキーを持っている | ジョインテーブルの一方のみをシャッフルする必要があり、ネットワークコストを削減できます。 |
|
||||
| Broadcast Join | ビルド側が非常に小さい (行/バイトのしきい値または明示的なヒント)。  | 小さなテーブルがすべてのプローブノードに複製され、大きなテーブルのシャッフルを回避します。 |
|
||||
| Shuffle (Hash) Join | 一般的なケース、キーが一致しない。 | 各行をジョインキーでハッシュ分割し、プローブを BE 間で均等に分散します。 |
|
||||
|
||||
#### 一般的なパフォーマンスのボトルネック
|
||||
|
||||
**ビルド側のサイズ超過** – `BuildHashTableTime` と `HashTableMemoryUsage` のスパイクは、ビルド側がメモリを超えていることを示します。プローブ/ビルドテーブルを入れ替え、ビルドテーブルを事前フィルタリングするか、ハッシュスピリングを有効にします。
|
||||
|
||||
**キャッシュに優しくないプローブ** – `SearchHashTableTime` が支配的な場合、プローブ側がキャッシュ効率が悪いです。プローブ行をジョインキーでソートし、実行時フィルターを有効にします。
|
||||
|
||||
**シャッフルスキュー** – 単一のフラグメントの `ProbeRows` が他のすべてを圧倒する場合、データがスキューしています。より高いカーディナリティのキーに切り替えるか、`key || mod(id, 16)` のようなソルトを追加します。
|
||||
|
||||
**意図しないブロードキャスト** – ジョインタイプ **BROADCAST** で巨大な `BytesSent` は、小さいと思っていたテーブルが実際にはそうでないことを示します。`broadcast_row_limit` を下げるか、`SHUFFLE` ヒントでシャッフルを強制します。
|
||||
|
||||
**実行時フィルターの欠如** – 小さな `JoinRuntimeFilterEvaluate` とフルテーブルスキャンは、実行時フィルターが伝播しなかったことを示します。ジョインを純粋な等式として書き直し、列タイプが一致していることを確認します。
|
||||
|
||||
**非等式フォールバック** – オペレータータイプが `CROSS` または `NESTLOOP` の場合、不等式または関数がハッシュジョインを妨げています。真の等式述語を追加するか、より大きなテーブルを事前にフィルタリングします。
|
||||
|
||||
### 2.4 Exchange (ネットワーク) [[metrics]](./query_profile_operator_metrics.md#exchange-operator)
|
||||
|
||||
**サイズ超過のシャッフルまたはブロードキャスト** – `NetworkTime` が 30 % を超え、`BytesSent` が大きい場合、クエリは過剰なデータを送信しています。ジョイン戦略を再評価するか、Exchange Compaction (`pipeline_enable_exchange_compaction`) を有効にします。
|
||||
|
||||
**レシーバーのバックログ** – 送信者キューが常に満杯である場合、シンクでの高い `WaitTime` はレシーバーが追いつけないことを示します。レシーバースレッドプール (`brpc_num_threads`) を増やし、NIC の帯域幅と QoS 設定を確認します。
|
||||
|
||||
### 2.5 ソート / マージ / ウィンドウ
|
||||
|
||||
さまざまなメトリックを理解しやすくするために、マージは以下の状態メカニズムとして表現できます。
|
||||
|
||||
```plaintext
|
||||
┌────────── PENDING ◄──────────┐
|
||||
│ │
|
||||
│ │
|
||||
├──────────────◄───────────────┤
|
||||
│ │
|
||||
▼ │
|
||||
INIT ──► PREPARE ──► SPLIT_CHUNK ──► FETCH_CHUNK ──► FINISHED
|
||||
▲
|
||||
|
|
||||
| one traverse from leaf to root
|
||||
|
|
||||
▼
|
||||
PROCESS
|
||||
```
|
||||
|
||||
**ソートスピリング** – `MaxBufferedBytes` が約 2 GB を超えるか `SpillBytes` がゼロでない場合、ソートフェーズがディスクにスピルしています。`LIMIT` を追加し、上流で事前集計するか、マシンに十分なメモリがある場合は `sort_spill_threshold` を上げます。
|
||||
|
||||
**マージの飢餓状態** – 高い `PendingStageTime` は、マージが上流のチャンクを待っていることを示します。最初にプロデューサーオペレーターを最適化するか、パイプラインバッファを拡大します。
|
||||
|
||||
**広いウィンドウパーティション** – ウィンドウオペレーター内の巨大な `PeakBufferedRows` は非常に広いパーティションまたはフレーム制限のない ORDER BY を示します。より細かくパーティション化し、`RANGE BETWEEN` 境界を追加するか、中間集計を実体化します。
|
||||
|
||||
---
|
||||
|
||||
## 3 · メモリ & スピル チートシート
|
||||
|
||||
| 閾値 | 監視対象 | 実践的なアクション |
|
||||
| --- | --- | --- |
|
||||
| **80 %** の BE メモリ | `QueryPeakMemoryUsagePerNode` | セッションの `exec_mem_limit` を下げるか、BE RAM を追加します。 |
|
||||
| スピル検出 (`SpillBytes` > 0) | `QuerySpillBytes`, オペレーターごとの `SpillBlocks` | メモリ制限を増やす; SR 3.2+ にアップグレードしてハイブリッドハッシュ/マージスピルを使用します。 |
|
||||
|
||||
---
|
||||
|
||||
## 4 · ポストモーテムのテンプレート
|
||||
|
||||
```text
|
||||
1. 症状
|
||||
– 遅いステージ: 集計 (OperatorTotalTime 68 %)
|
||||
– 警告: HashTableMemoryUsage 9 GB (> exec_mem_limit)
|
||||
2. 根本原因
|
||||
– GROUP BY 高カーディナリティ UUID
|
||||
3. 適用された修正
|
||||
– ソートされたストリーミング集計 + ロールアップ MV を追加
|
||||
4. 結果
|
||||
– クエリ実行時間が 95 秒から 8 秒に短縮; メモリピーク 0.7 GB
|
||||
```
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 50
|
||||
---
|
||||
|
||||
# スキーマチューニングレシピ
|
||||
|
||||
このドキュメントは、StarRocks における効果的なスキーマ設計と基礎的なテーブル選択を通じて、クエリパフォーマンスを最適化するための実用的なヒントとベストプラクティスを提供します。異なるテーブルタイプ、キー、分散戦略がクエリ実行にどのように影響するかを理解することで、速度とリソース効率の両方を大幅に向上させることができます。これらのガイドラインを使用して、スキーマ設計、テーブルタイプの選択、StarRocks 環境のチューニングにおいて情報に基づいた意思決定を行い、高性能な分析を実現してください。
|
||||
|
||||
## テーブルタイプの選択
|
||||
|
||||
StarRocks は、重複キーテーブル、集計テーブル、ユニークキーテーブル、主キーテーブルの4つのテーブルタイプをサポートしています。これらはすべて KEY によってソートされます。
|
||||
|
||||
- `AGGREGATE KEY`: 同じ AGGREGATE KEY を持つレコードが StarRocks にロードされると、古いレコードと新しいレコードが集計されます。現在、集計テーブルは以下の集計関数をサポートしています: SUM, MIN, MAX, REPLACE。集計テーブルはデータを事前に集計し、ビジネスステートメントや多次元分析を容易にします。
|
||||
- `DUPLICATE KEY`: 重複キーテーブルにはソートキーを指定するだけで済みます。同じ DUPLICATE KEY を持つレコードは同時に存在します。事前にデータを集計しない分析に適しています。
|
||||
- `UNIQUE KEY`: 同じ UNIQUE KEY を持つレコードが StarRocks にロードされると、新しいレコードが古いレコードを上書きします。ユニークキーテーブルは REPLACE 関数を持つ集計テーブルに似ています。どちらも定期的な更新を伴う分析に適しています。
|
||||
- `PRIMARY KEY`: 主キーテーブルはレコードの一意性を保証し、リアルタイムの更新を可能にします。
|
||||
|
||||
```sql
|
||||
CREATE TABLE site_visit
|
||||
(
|
||||
siteid INT,
|
||||
city SMALLINT,
|
||||
username VARCHAR(32),
|
||||
pv BIGINT SUM DEFAULT '0'
|
||||
)
|
||||
AGGREGATE KEY(siteid, city, username)
|
||||
DISTRIBUTED BY HASH(siteid);
|
||||
|
||||
CREATE TABLE session_data
|
||||
(
|
||||
visitorid SMALLINT,
|
||||
sessionid BIGINT,
|
||||
visittime DATETIME,
|
||||
city CHAR(20),
|
||||
province CHAR(20),
|
||||
ip varchar(32),
|
||||
browser CHAR(20),
|
||||
url VARCHAR(1024)
|
||||
)
|
||||
DUPLICATE KEY(visitorid, sessionid)
|
||||
DISTRIBUTED BY HASH(sessionid, visitorid);
|
||||
|
||||
CREATE TABLE sales_order
|
||||
(
|
||||
orderid BIGINT,
|
||||
status TINYINT,
|
||||
username VARCHAR(32),
|
||||
amount BIGINT DEFAULT '0'
|
||||
)
|
||||
UNIQUE KEY(orderid)
|
||||
DISTRIBUTED BY HASH(orderid);
|
||||
|
||||
CREATE TABLE sales_order
|
||||
(
|
||||
orderid BIGINT,
|
||||
status TINYINT,
|
||||
username VARCHAR(32),
|
||||
amount BIGINT DEFAULT '0'
|
||||
)
|
||||
PRIMARY KEY(orderid)
|
||||
DISTRIBUTED BY HASH(orderid);
|
||||
```
|
||||
|
||||
## コロケートテーブル
|
||||
|
||||
クエリを高速化するために、同じ分散を持つテーブルは共通のバケッティングカラムを使用できます。この場合、`join` 操作中にデータがクラスター間で転送されることなく、ローカルでジョインできます。
|
||||
|
||||
```sql
|
||||
CREATE TABLE colocate_table
|
||||
(
|
||||
visitorid SMALLINT,
|
||||
sessionid BIGINT,
|
||||
visittime DATETIME,
|
||||
city CHAR(20),
|
||||
province CHAR(20),
|
||||
ip varchar(32),
|
||||
browser CHAR(20),
|
||||
url VARCHAR(1024)
|
||||
)
|
||||
DUPLICATE KEY(visitorid, sessionid)
|
||||
DISTRIBUTED BY HASH(sessionid, visitorid)
|
||||
PROPERTIES(
|
||||
"colocate_with" = "group1"
|
||||
);
|
||||
```
|
||||
|
||||
コロケートジョインとレプリカ管理の詳細については、 [Colocate join](../../using_starrocks/Colocate_join.md) を参照してください。
|
||||
|
||||
## フラットテーブルとスタースキーマ
|
||||
|
||||
StarRocks はスタースキーマをサポートしており、フラットテーブルよりも柔軟にモデリングできます。モデリング中にフラットテーブルを置き換えるビューを作成し、複数のテーブルからデータをクエリしてクエリを高速化できます。
|
||||
|
||||
フラットテーブルには以下の欠点があります:
|
||||
|
||||
- フラットテーブルは通常、多数のディメンションを含むため、ディメンションの更新コストが高い。ディメンションが更新されるたびに、テーブル全体を更新する必要があります。更新頻度が増すと状況は悪化します。
|
||||
- フラットテーブルは追加の開発作業、ストレージスペース、データバックフィリング操作を必要とするため、メンテナンスコストが高い。
|
||||
- フラットテーブルには多くのフィールドがあり、集計テーブルにはさらに多くのキー フィールドが含まれる可能性があるため、データ取り込みコストが高い。データロード中に、より多くのフィールドをソートする必要があり、データロードが長引きます。
|
||||
|
||||
クエリの同時実行性や低レイテンシーに対する要求が高い場合は、フラットテーブルを使用することもできます。
|
||||
|
||||
## パーティションとバケット
|
||||
|
||||
StarRocks は2レベルのパーティショニングをサポートしています。第1レベルは RANGE パーティションで、第2レベルは HASH バケットです。
|
||||
|
||||
- RANGE パーティション: RANGE パーティションはデータを異なる間隔に分割するために使用されます(元のテーブルを複数のサブテーブルに分割することと理解できます)。ほとんどのユーザーは時間でパーティションを設定することを選択し、次の利点があります:
|
||||
|
||||
- ホットデータとコールドデータを区別しやすい
|
||||
- StarRocks の階層型ストレージ (SSD + SATA) を活用できる
|
||||
- パーティションによるデータ削除が高速
|
||||
|
||||
- HASH バケット: ハッシュ値に基づいてデータを異なるバケットに分割します。
|
||||
|
||||
- データの偏りを避けるために、識別度の高い列をバケッティングに使用することをお勧めします。
|
||||
- データの復旧を容易にするために、各バケット内の圧縮データのサイズを 100 MB から 1 GB の間に保つことをお勧めします。テーブルを作成するかパーティションを追加する際に、適切なバケット数を設定することをお勧めします。
|
||||
- ランダムバケット法は推奨されません。テーブルを作成する際には、HASH バケッティングカラムを明示的に指定する必要があります。
|
||||
|
||||
## スパースインデックスとブルームフィルターインデックス
|
||||
|
||||
StarRocks はデータを順序付けて保存し、1024 行の粒度でスパースインデックスを構築します。
|
||||
|
||||
StarRocks はスキーマ内の固定長プレフィックス(現在は 36 バイト)をスパースインデックスとして選択します。
|
||||
|
||||
テーブルを作成する際には、一般的なフィルターフィールドをスキーマ宣言の先頭に配置することをお勧めします。識別度とクエリ頻度が最も高いフィールドを最初に配置する必要があります。
|
||||
|
||||
VARCHAR フィールドはスパースインデックスの最後に配置する必要があります。インデックスは VARCHAR フィールドから切り捨てられるためです。VARCHAR フィールドが最初に現れると、インデックスは 36 バイト未満になる可能性があります。
|
||||
|
||||
上記の `site_visit` テーブルを例にとります。このテーブルには 4 つの列があります: `siteid, city, username, pv`。ソートキーには `siteid, city, username` の 3 つの列が含まれ、それぞれ 4, 2, 32 バイトを占めます。したがって、プレフィックスインデックス(スパースインデックス)は `siteid + city + username` の最初の 30 バイトになります。
|
||||
|
||||
スパースインデックスに加えて、StarRocks はブルームフィルターインデックスも提供しており、識別度の高い列をフィルタリングするのに効果的です。VARCHAR フィールドを他のフィールドの前に配置したい場合は、ブルームフィルターインデックスを作成できます。
|
||||
|
||||
## インバーテッドインデックス
|
||||
|
||||
StarRocks はビットマップインデックス技術を採用しており、重複キーテーブルのすべての列と集計テーブルおよびユニークキーテーブルのキー列に適用できるインバーテッドインデックスをサポートしています。ビットマップインデックスは、性別、都市、州などの小さな値範囲を持つ列に適しています。範囲が拡大するにつれて、ビットマップインデックスも並行して拡大します。
|
||||
|
||||
## マテリアライズドビュー(ロールアップ)
|
||||
|
||||
ロールアップは、元のテーブル(ベーステーブル)のマテリアライズドインデックスです。ロールアップを作成する際には、ベーステーブルの一部の列のみをスキーマとして選択でき、スキーマ内のフィールドの順序はベーステーブルとは異なる場合があります。以下はロールアップの使用例です:
|
||||
|
||||
- ベーステーブルのデータ集約が高くない場合、ベーステーブルには識別度の高いフィールドが含まれているためです。この場合、一部の列を選択してロールアップを作成することを検討できます。上記の `site_visit` テーブルを例にとります:
|
||||
|
||||
```sql
|
||||
site_visit(siteid, city, username, pv)
|
||||
```
|
||||
|
||||
`siteid` はデータ集約が不十分になる可能性があります。都市ごとに PV を頻繁に計算する必要がある場合は、`city` と `pv` のみを含むロールアップを作成できます。
|
||||
|
||||
```sql
|
||||
ALTER TABLE site_visit ADD ROLLUP rollup_city(city, pv);
|
||||
```
|
||||
|
||||
- ベーステーブルのプレフィックスインデックスがヒットしない場合、ベーステーブルの構築方法がすべてのクエリパターンをカバーできないためです。この場合、列の順序を調整するためにロールアップを作成することを検討できます。上記の `session_data` テーブルを例にとります:
|
||||
|
||||
```sql
|
||||
session_data(visitorid, sessionid, visittime, city, province, ip, browser, url)
|
||||
```
|
||||
|
||||
`visitorid` に加えて `browser` と `province` で訪問を分析する必要がある場合は、別のロールアップを作成できます:
|
||||
|
||||
```sql
|
||||
ALTER TABLE session_data
|
||||
ADD ROLLUP rollup_browser(browser,province,ip,url)
|
||||
DUPLICATE KEY(browser,province);
|
||||
```
|
||||
|
||||
## スキーマ変更
|
||||
|
||||
StarRocks では、スキーマを変更する方法が3つあります:ソート済みスキーマ変更、直接スキーマ変更、リンクスキーマ変更。
|
||||
|
||||
- ソート済みスキーマ変更: 列のソートを変更し、データを再配置します。たとえば、ソート済みスキーマで列を削除するとデータが再配置されます。
|
||||
|
||||
`ALTER TABLE site_visit DROP COLUMN city;`
|
||||
|
||||
- 直接スキーマ変更: データを再配置せずに変換します。たとえば、列の型を変更したり、スパースインデックスに列を追加したりします。
|
||||
|
||||
`ALTER TABLE site_visit MODIFY COLUMN username varchar(64);`
|
||||
|
||||
- リンクスキーマ変更: データを変換せずに変更を完了します。たとえば、列を追加します。
|
||||
|
||||
`ALTER TABLE site_visit ADD COLUMN click bigint SUM default '0';`
|
||||
|
||||
テーブルを作成する際には、スキーマ変更を加速するために適切なスキーマを選択することをお勧めします。
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
---
|
||||
|
||||
#
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
<DocCardList />
|
||||
|
|
@ -22,7 +22,7 @@ get_query_profile(x)
|
|||
|
||||
## 戻り値
|
||||
|
||||
クエリプロファイルには以下のフィールドが含まれます。クエリプロファイルの詳細については、[Query Profile](../../../administration/query_profile_overview.md) を参照してください。
|
||||
クエリプロファイルには以下のフィールドが含まれます。クエリプロファイルの詳細については、[Query Profile](../../../best_practices/query_tuning/query_profile_overview.md) を参照してください。
|
||||
|
||||
```SQL
|
||||
Query:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ displayed_sidebar: docs
|
|||
|
||||
## 説明
|
||||
|
||||
特定のクエリプロファイルをフラグメントごとに分析し、ツリー構造で表示します。クエリプロファイルの詳細については、[Query Profile Overview](../../../../administration/query_profile_overview.md) を参照してください。
|
||||
特定のクエリプロファイルをフラグメントごとに分析し、ツリー構造で表示します。クエリプロファイルの詳細については、[Query Profile Overview](../../../../best_practices/query_tuning/query_profile_overview.md) を参照してください。
|
||||
|
||||
この機能は v3.1 以降でサポートされています。
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ displayed_sidebar: docs
|
|||
|
||||
## 説明
|
||||
|
||||
クエリステートメントの論理または物理実行プランを表示します。クエリプランの分析方法については、[Plan analysis](../../../../administration/Query_planning.md#plan-analysis)を参照してください。
|
||||
クエリステートメントの論理または物理実行プランを表示します。クエリプランの分析方法については、[Plan analysis](../../../../best_practices/query_tuning/query_planning.md#plan-analysis)を参照してください。
|
||||
|
||||
:::tip
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ displayed_sidebar: docs
|
|||
|
||||
## 説明
|
||||
|
||||
指定された SQL ステートメントを実行し、そのステートメントの Query Profile を表示します。Query Profile についての詳細は、[Query Profile Overview](../../../../administration/query_profile_overview.md) を参照してください。
|
||||
指定された SQL ステートメントを実行し、そのステートメントの Query Profile を表示します。Query Profile についての詳細は、[Query Profile Overview](../../../../best_practices/query_tuning/query_profile_overview.md) を参照してください。
|
||||
|
||||
この機能は v3.1 以降でサポートされています。
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ displayed_sidebar: docs
|
|||
|
||||
## 説明
|
||||
|
||||
StarRocks クラスターにキャッシュされている query profile レコードを一覧表示します。query profile についての詳細は、[Query Profile Overview](../../../../administration/query_profile_overview.md) を参照してください。
|
||||
StarRocks クラスターにキャッシュされている query profile レコードを一覧表示します。query profile についての詳細は、[Query Profile Overview](../../../../best_practices/query_tuning/query_profile_overview.md) を参照してください。
|
||||
|
||||
この機能は v3.1 以降でサポートされています。
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ SELECT select_expr[, select_expr ...]
|
|||
> - v3.1以降、各同期マテリアライズドビューはベーステーブルの各列に対して複数の集計関数をサポートできます。例: `select b, sum(a), min(a) from table group by b`のようなクエリステートメント。
|
||||
> - v3.1以降、同期マテリアライズドビューはSELECTおよび集計関数の複雑な式をサポートします。例: `select b, sum(a + 1) as sum_a1, min(cast (a as bigint)) as min_a from table group by b`や`select abs(b) as col1, a + 1 as col2, cast(a as bigint) as col3 from table`のようなクエリステートメント。同期マテリアライズドビューで使用される複雑な式には次の制限があります:
|
||||
> - 各複雑な式にはエイリアスが必要で、ベーステーブルのすべての同期マテリアライズドビュー間で異なる複雑な式には異なるエイリアスを割り当てる必要があります。例: `select b, sum(a + 1) as sum_a from table group by b`と`select b, sum(a) as sum_a from table group by b`のようなクエリステートメントは、同じベーステーブルに対して同期マテリアライズドビューを作成するために使用できません。複雑な式に異なるエイリアスを設定できます。
|
||||
> - 複雑な式で作成された同期マテリアライズドビューによってクエリが書き換えられているかどうかを確認するには、`EXPLAIN <sql_statement>`を実行します。詳細については、[クエリ分析](../../../administration/Query_planning.md)を参照してください。
|
||||
> - 複雑な式で作成された同期マテリアライズドビューによってクエリが書き換えられているかどうかを確認するには、`EXPLAIN <sql_statement>`を実行します。詳細については、[クエリ分析](../../../best_practices/query_tuning/query_planning.md)を参照してください。
|
||||
|
||||
- WHERE (オプション)
|
||||
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ DROP INDEX lo_orderdate_index ON lineorder_partial;
|
|||
|
||||
### ビットマップインデックスがクエリを高速化するかどうかを確認する
|
||||
|
||||
クエリプロファイルの`BitmapIndexFilterRows`フィールドを確認します。プロファイルの表示方法については、[クエリ分析](../../administration/Query_planning.md)を参照してください。
|
||||
クエリプロファイルの`BitmapIndexFilterRows`フィールドを確認します。プロファイルの表示方法については、[クエリ分析](../../best_practices/query_tuning/query_planning.md)を参照してください。
|
||||
|
||||
## ビットマップインデックスのパフォーマンステスト
|
||||
|
||||
|
|
|
|||
|
|
@ -114,4 +114,4 @@ v3.0以降、主キーテーブルのソートキーは変更可能です。そ
|
|||
|
||||
## プレフィックスインデックスがクエリを加速するかどうかを確認する方法
|
||||
|
||||
クエリを実行した後、プレフィックスインデックスが効果を発揮したかどうかを確認し、`ShortKeyFilterRows`などの詳細なメトリクスからそのフィルタリング効果を確認できます。[Query Profile](../../administration/query_profile_overview.md)のスキャンノードで確認できます。
|
||||
クエリを実行した後、プレフィックスインデックスが効果を発揮したかどうかを確認し、`ShortKeyFilterRows`などの詳細なメトリクスからそのフィルタリング効果を確認できます。[Query Profile](../../best_practices/query_tuning/query_profile_overview.md)のスキャンノードで確認できます。
|
||||
|
|
@ -56,7 +56,7 @@ SELECT flat_json_meta(<json_column>)
|
|||
FROM <table_name>[_META_];
|
||||
```
|
||||
|
||||
実行されたクエリが Flat JSON 最適化の恩恵を受けているかどうかを [Query Profile](../administration/query_profile_overview.md) を通じて以下のメトリクスを観察することで確認できます:
|
||||
実行されたクエリが Flat JSON 最適化の恩恵を受けているかどうかを [Query Profile](../best_practices/query_tuning/query_profile_overview.md) を通じて以下のメトリクスを観察することで確認できます:
|
||||
- `PushdownAccessPaths`: ストレージにプッシュダウンされたサブフィールドパスの数。
|
||||
- `AccessPathHits`: Flat JSON サブフィールドがヒットした回数と、特定の JSON ヒットに関する詳細情報。
|
||||
- `AccessPathUnhits`: Flat JSON サブフィールドがヒットしなかった回数と、特定の JSON ヒットしなかった情報。
|
||||
|
|
@ -134,7 +134,7 @@ FROM <table_name>[_META_];
|
|||
SELECT get_json_string(k2,'\$.Bool') FROM t1 WHERE k2->'arr' = '[10,20,30]';
|
||||
```
|
||||
|
||||
7. [Query Profile](../administration/query_profile_overview.md) で Flat JSON 関連のメトリクスを表示します。
|
||||
7. [Query Profile](../best_practices/query_tuning/query_profile_overview.md) で Flat JSON 関連のメトリクスを表示します。
|
||||
```yaml
|
||||
PushdownAccessPaths: 2
|
||||
- Table: t1
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ ExecTime | 2.583 s
|
|||
- `QueryMemCost`: クエリの総メモリコスト。
|
||||
- 個々のオペレーターに関する他のメトリクス、例えばジョインオペレーターや集計オペレーター。
|
||||
|
||||
クエリプロファイルの確認方法や他のメトリクスの理解についての詳細は、[Analyze query profile](../../administration/query_profile_overview.md)を参照してください。
|
||||
クエリプロファイルの確認方法や他のメトリクスの理解についての詳細は、[Analyze query profile](../../best_practices/query_tuning/query_profile_overview.md)を参照してください。
|
||||
|
||||
### 非同期マテリアライズドビューによるクエリの書き換えを確認
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ where empid < 5;
|
|||
|
||||
## ベストプラクティス
|
||||
|
||||
実際のビジネスシナリオでは、監査ログや大規模クエリログを分析することで、実行レイテンシーが高くリソース消費が多いクエリを特定できます。さらに、[query profiles](../../../administration/query_profile_overview.md) を使用して、クエリが遅い特定の段階を特定できます。以下のセクションでは、マテリアライズドビューを使用してデータレイククエリパフォーマンスを向上させる方法と例を提供します。
|
||||
実際のビジネスシナリオでは、監査ログや大規模クエリログを分析することで、実行レイテンシーが高くリソース消費が多いクエリを特定できます。さらに、[query profiles](../../../best_practices/query_tuning/query_profile_overview.md) を使用して、クエリが遅い特定の段階を特定できます。以下のセクションでは、マテリアライズドビューを使用してデータレイククエリパフォーマンスを向上させる方法と例を提供します。
|
||||
|
||||
### ケース1: データレイクでのジョイン計算の加速
|
||||
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 747 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 414 KiB |
|
After Width: | Height: | Size: 647 KiB |
|
|
@ -1,482 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
---
|
||||
|
||||
# 分析查询
|
||||
|
||||
本文介绍如何分析 StarRocks 中的查询。
|
||||
|
||||
为优化 StarRocks 集群性能,管理员需要定期针对慢查询进行分析并优化,以免慢查询影响整个集群的服务能力,进而影响用户体验。
|
||||
|
||||
您可以在 **fe/log/fe.audit.log** 中看到所有查询和慢查询信息,每个查询对应一个 QueryID。您可以在日志或者页面中查找到查询对应的 Query Plan 和 Profile。Query Plan 是 FE 通过解析 SQL 生成的执行计划,而 Profile 是 BE 执行查询后的结果,包含了每一步的耗时和数据处理量等数据。
|
||||
|
||||
同时,StarRocks 还支持对慢查询中的 SQL 语句进行归类,并为各类 SQL 语句计算出 SQL 指纹。
|
||||
|
||||
## 查看分析 Query Plan
|
||||
|
||||
SQL 语句在 StarRocks 中的生命周期可以分为查询解析(Query Parsing)、规划(Query Plan)、执行(Query Execution)三个阶段。通常对于 StarRocks 而言,查询解析不会成为查询性能的瓶颈,因为分析型需求的 QPS 普遍不高。
|
||||
|
||||
决定 StarRocks 中查询性能的关键就在于查询规划(Query Plan)和查询执行(Query Execution),二者的关系可以描述为 Query Plan 负责组织算子(Join/Order/Aggregation)之间的关系,Query Execution 负责执行具体算子。
|
||||
|
||||
Query Plan 可以为数据库管理者提供一个宏观的视角,从而获取查询执行的相关信息。优秀的 Query Plan 很大程度上决定了查询的性能,所以数据库管理者需要频繁查看 Query Plan,以确保其是否生成得当。本章以 TPC-DS 的 query96.sql 为例,展示如何查看StarRocks的Query Plan。
|
||||
|
||||
以下示例以 TPC-DS 的 query96.sql 为例,展示如何查看分析 StarRocks 的 Query Plan。
|
||||
|
||||
```SQL
|
||||
-- query96.sql
|
||||
select count(*)
|
||||
from store_sales,
|
||||
household_demographics,
|
||||
time_dim,
|
||||
store
|
||||
where ss_sold_time_sk = time_dim.t_time_sk
|
||||
and ss_hdemo_sk = household_demographics.hd_demo_sk
|
||||
and ss_store_sk = s_store_sk
|
||||
and time_dim.t_hour = 8
|
||||
and time_dim.t_minute >= 30
|
||||
and household_demographics.hd_dep_count = 5
|
||||
and store.s_store_name = 'ese'
|
||||
order by count(*) limit 100;
|
||||
```
|
||||
|
||||
### 查看 Query Plan
|
||||
|
||||
Query Plan 可以分为逻辑执行计划(Logical Query Plan),和物理执行计划(Physical Query Plan),本章节所讲述的 Query Plan 默认指代的都是逻辑执行计划。
|
||||
|
||||
通过 [EXPLAIN](../sql-reference/sql-statements/cluster-management/plan_profile/EXPLAIN.md) 命令查看 Query Plan。
|
||||
|
||||
```sql
|
||||
EXPLAIN sql_statement;
|
||||
```
|
||||
|
||||
TPC-DS query96.sql 对应的 Query Plan 展示如下:
|
||||
|
||||
```plain text
|
||||
mysql> EXPLAIN select count(*)
|
||||
from store_sales,
|
||||
household_demographics,
|
||||
time_dim,
|
||||
store
|
||||
where ss_sold_time_sk = time_dim.t_time_sk
|
||||
and ss_hdemo_sk = household_demographics.hd_demo_sk
|
||||
and ss_store_sk = s_store_sk
|
||||
and time_dim.t_hour = 8
|
||||
and time_dim.t_minute >= 30
|
||||
and household_demographics.hd_dep_count = 5
|
||||
and store.s_store_name = 'ese'
|
||||
order by count(*) limit 100;
|
||||
|
||||
+------------------------------------------------------------------------------+
|
||||
| Explain String |
|
||||
+------------------------------------------------------------------------------+
|
||||
| PLAN FRAGMENT 0 |
|
||||
| OUTPUT EXPRS:<slot 11> |
|
||||
| PARTITION: UNPARTITIONED |
|
||||
| RESULT SINK |
|
||||
| 12:MERGING-EXCHANGE |
|
||||
| limit: 100 |
|
||||
| tuple ids: 5 |
|
||||
| |
|
||||
| PLAN FRAGMENT 1 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 12 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 8:TOP-N |
|
||||
| | order by: <slot 11> ASC |
|
||||
| | offset: 0 |
|
||||
| | limit: 100 |
|
||||
| | tuple ids: 5 |
|
||||
| | |
|
||||
| 7:AGGREGATE (update finalize) |
|
||||
| | output: count(*) |
|
||||
| | group by: |
|
||||
| | tuple ids: 4 |
|
||||
| | |
|
||||
| 6:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: left hash join node can not do colocate |
|
||||
| | equal join conjunct: `ss_store_sk` = `s_store_sk` |
|
||||
| | tuple ids: 0 2 1 3 |
|
||||
| | |
|
||||
| |----11:EXCHANGE |
|
||||
| | tuple ids: 3 |
|
||||
| | |
|
||||
| 4:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: left hash join node can not do colocate |
|
||||
| | equal join conjunct: `ss_hdemo_sk`=`household_demographics`.`hd_demo_sk`|
|
||||
| | tuple ids: 0 2 1 |
|
||||
| | |
|
||||
| |----10:EXCHANGE |
|
||||
| | tuple ids: 1 |
|
||||
| | |
|
||||
| 2:HASH JOIN |
|
||||
| | join op: INNER JOIN (BROADCAST) |
|
||||
| | hash predicates: |
|
||||
| | colocate: false, reason: table not in same group |
|
||||
| | equal join conjunct: `ss_sold_time_sk` = `time_dim`.`t_time_sk` |
|
||||
| | tuple ids: 0 2 |
|
||||
| | |
|
||||
| |----9:EXCHANGE |
|
||||
| | tuple ids: 2 |
|
||||
| | |
|
||||
| 0:OlapScanNode |
|
||||
| TABLE: store_sales |
|
||||
| PREAGGREGATION: OFF. Reason: `ss_sold_time_sk` is value column |
|
||||
| partitions=1/1 |
|
||||
| rollup: store_sales |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 0 |
|
||||
| |
|
||||
| PLAN FRAGMENT 2 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 11 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 5:OlapScanNode |
|
||||
| TABLE: store |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `store`.`s_store_name` = 'ese' |
|
||||
| partitions=1/1 |
|
||||
| rollup: store |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 3 |
|
||||
| |
|
||||
| PLAN FRAGMENT 3 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 10 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 3:OlapScanNode |
|
||||
| TABLE: household_demographics |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `household_demographics`.`hd_dep_count` = 5 |
|
||||
| partitions=1/1 |
|
||||
| rollup: household_demographics |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 1 |
|
||||
| |
|
||||
| PLAN FRAGMENT 4 |
|
||||
| OUTPUT EXPRS: |
|
||||
| PARTITION: RANDOM |
|
||||
| STREAM DATA SINK |
|
||||
| EXCHANGE ID: 09 |
|
||||
| UNPARTITIONED |
|
||||
| |
|
||||
| 1:OlapScanNode |
|
||||
| TABLE: time_dim |
|
||||
| PREAGGREGATION: OFF. Reason: null |
|
||||
| PREDICATES: `time_dim`.`t_hour` = 8, `time_dim`.`t_minute` >= 30 |
|
||||
| partitions=1/1 |
|
||||
| rollup: time_dim |
|
||||
| tabletRatio=0/0 |
|
||||
| tabletList= |
|
||||
| cardinality=-1 |
|
||||
| avgRowSize=0.0 |
|
||||
| numNodes=0 |
|
||||
| tuple ids: 2 |
|
||||
+------------------------------------------------------------------------------+
|
||||
128 rows in set (0.02 sec)
|
||||
```
|
||||
|
||||
### 分析 Query Plan
|
||||
|
||||
分析 Query Plan 将涉及以下概念。
|
||||
|
||||
|名称|解释|
|
||||
|---|---|
|
||||
|avgRowSize|扫描数据行的平均大小。|
|
||||
|cardinality|扫描表的数据总行数。|
|
||||
|colocate|表是否采用了 Colocate 形式。|
|
||||
|numNodes|扫描涉及的节点数。|
|
||||
|rollup|物化视图。|
|
||||
|preaggregation|预聚合。|
|
||||
|predicates|谓词,也就是查询过滤条件。|
|
||||
|partitions|分区。|
|
||||
|table|表。|
|
||||
|
||||
query96.sql 的 Query Plan 分为 5 个 Plan Fragment,编号从 0 至 4。您可以通过从下至上的方式查看 Query Plan。
|
||||
|
||||
以上示例中,最底部的 Plan Fragment 为 Fragment 4,它负责扫描 `time_dim` 表,并提前执行相关查询条件 `time_dim.t_hour = 8 and time_dim.t_minute >= 30`,即谓词下推。对于聚合表,StarRocks 会根据不同查询选择是否开启预聚合 PREAGGREGATION。以上示例中 `time_dim` 表的预聚合为关闭状态,此状态之下 StarRocks 会读取 `time_dim` 的全部维度列,如果当前表包含大量维度列,这可能会成为影响性能的一个关键因素。如果 `time_dim` 表被设置为根据 Range Partition 进行数据划分,Query Plan 中的 `partitions` 会表征查询命中的分区,无关分区被自动过滤,从而有效减少扫描数据量。如果当前表有物化视图,StarRocks 会根据查询去自动选择物化视图,如果没有物化视图,那么查询自动命中 base table,也就是以上示例中展示的 `rollup: time_dim`。您暂时无需关注其他字段。
|
||||
|
||||
当 `time_dim` 表数据扫描完成之后,Fragment 4 的执行过程也就随之结束,此时它将扫描得到的数据传递给其他 Fragment。以上示例中的 `EXCHANGE ID : 09` 表征了数据传递给了标号为 `9` 的接收节点。
|
||||
|
||||
对于 query96.sql 的 Query Plan 而言,Fragment 2,3,4功能类似,只是负责扫描的表不同。而查询中的 Order/Aggregation/Join 算子,都在 Fragment 1 中进行。
|
||||
|
||||
Fragment 1 集成了三个 Join 算子的执行,采用默认的 BROADCAST 方式进行执行,也就是小表向大表广播的方式进行。如果两个 Join 的表都是大表,建议采用 SHUFFLE 的方式进行。目前 StarRocks 只支持 HASH JOIN,也就是采用哈希算法进行 Join。以上示例中的 `colocate` 字段用来表述两张 Join 表采用同样的分区/分桶方式。如果分区/分桶方式相同,Join 的过程可以直接在本地执行,不用进行数据的移动。Join 执行完成之后,Fragment 1 就会执行上层的 Aggregation、Order by 和 TOP-N 算子。
|
||||
|
||||
抛开具体的表达式不谈,下图从宏观的角度展示了 query96.sql 的 Query Plan。
|
||||
|
||||

|
||||
|
||||
## 查看分析 Profile
|
||||
|
||||
在分析 Query Plan 后,您可以分析 BE 的执行结果 Profile 了解集群性能。关于如何查看并分析查询的 Profile,请参考[Query Profile 概述](./query_profile_overview.md)。
|
||||
|
||||
以下示例以 TPCH 的 Q4 查询为例。
|
||||
|
||||
```sql
|
||||
-- TPCH Q4
|
||||
select o_orderpriority, count(*) as order_count
|
||||
from orders
|
||||
where
|
||||
o_orderdate >= date '1993-07-01'
|
||||
and o_orderdate < date '1993-07-01' + interval '3' month
|
||||
and exists (
|
||||
select * from lineitem
|
||||
where l_orderkey = o_orderkey and l_commitdate < l_receiptdate
|
||||
)
|
||||
group by o_orderpriority
|
||||
order by o_orderpriority;
|
||||
```
|
||||
|
||||
以上查询包含了相关子查询,即 group by,order by 和 count 查询。其中 `order` 是订单表,`lineitem` 是货品明细表,这两张表均为数据量较大的的事实表。这个查询的含义是按照订单的优先级分组,统计每个分组的订单数量,同时有两个过滤条件:
|
||||
|
||||
* 订单创建时间处于 `1993 年 7 月` 至 `1993 年 10 月` 之间。
|
||||
* 订单对应的产品的提交日期 `l_commitdate` 小于收货日期 `l_receiptadate`。
|
||||
|
||||
通过分析对应 Profile,可以看到该查询执行了 3.106s。其中 `Active` 字段表示当前节点(包含其所有子节点)的执行时间。当前节点有两个子节点,即两个 Scan Node,二者分别扫描了 5,730,776 条和 379,364,474 条数据,并进行了一次 Shuffle Join,完成后输出 5,257,429 条数据,然后经过两层聚合,最后通过一个 Sort Node 后输出结果,其中 Exchange Node 是数据交换节点,在当前示例中进行了两次 Shuffle。
|
||||
|
||||
通常情况下,分析 Profile 的核心即找到执行时间最长的性能瓶颈所在的节点。您可以按照自上而下的方式依次查看。
|
||||
|
||||
在当前示例中,Hash Join Node 占了主要时间。
|
||||
|
||||
```plain text
|
||||
HASH_JOIN_NODE (id=2):(Active: 3s85ms, % non-child: 34.59%)
|
||||
- AvgInputProbeChunkSize: 3.653K (3653)
|
||||
- AvgOutputChunkSize: 3.57K (3570)
|
||||
- BuildBuckets: 67.108864M (67108864)
|
||||
- BuildRows: 31.611425M (31611425)
|
||||
- BuildTime: 3s56ms
|
||||
- 1-FetchRightTableTime: 2s14ms
|
||||
- 2-CopyRightTableChunkTime: 0ns
|
||||
- 3-BuildHashTableTime: 1s19ms
|
||||
- 4-BuildPushDownExprTime: 0ns
|
||||
- PeakMemoryUsage: 376.59 MB
|
||||
- ProbeRows: 478.599K (478599)
|
||||
- ProbeTime: 28.820ms
|
||||
- 1-FetchLeftTableTimer: 369.315us
|
||||
- 2-SearchHashTableTimer: 19.252ms
|
||||
- 3-OutputBuildColumnTimer: 893.29us
|
||||
- 4-OutputProbeColumnTimer: 7.612ms
|
||||
- 5-OutputTupleColumnTimer: 34.593us
|
||||
- PushDownExprNum: 0
|
||||
- RowsReturned: 439.16K (439160)
|
||||
- RowsReturnedRate: 142.323K /sec
|
||||
```
|
||||
|
||||
在当前示例中的信息可以看出,Hash Join 的执行时间主要分成两部分,也就是 `BuildTime` 和 `ProbeTime`,`BuildTime` 是扫描右表并构建 Hash 表的过程,`ProbeTime` 是获取左表并搜索 Hash 表进行匹配并输出的过程。可以看出在当前节点的 `BuildTime` 中,`FetchRightTableTime` 和 `BuildHashTableTime` 占据了较大部分。对比先前扫描行数数据,可以发现当前查询的左表和右表的顺序并不理想,应该将左表设置为大表,如此右表构建 Hash 表的效果更好。除此之外,当前两表均为事实表,数据量较大,您也可以考虑采用 Colocate Join 来避免数据 Shuffle,同时减少 Join 的数据量。您可以参考 [Colocate Join](../using_starrocks/Colocate_join.md) 建立 Colocation 关系,改写 SQL 如下:
|
||||
|
||||
```sql
|
||||
with t1 as (
|
||||
select l_orderkey from lineitem
|
||||
where l_commitdate < l_receiptdate
|
||||
) select o_orderpriority, count(*)as order_count from t1 right semi join orders_co on l_orderkey = o_orderkey
|
||||
where o_orderdate >= date '1993-07-01'
|
||||
and o_orderdate < date '1993-07-01' + interval '3' month
|
||||
group by o_orderpriority
|
||||
order by o_orderpriority;
|
||||
```
|
||||
|
||||
新的 SQL 执行时间从 3.106s 降低至 1.042s。两张大表没有了 Exchange 节点,直接通过 Colocate Join 进行 Join。除此之外,调换左右表顺序后,整体性能大幅提升,新的 Join Node 信息如下:
|
||||
|
||||
```sql
|
||||
HASH_JOIN_NODE (id=2):(Active: 996.337ms, % non-child: 52.05%)
|
||||
- AvgInputProbeChunkSize: 2.588K (2588)
|
||||
- AvgOutputChunkSize: 35
|
||||
- BuildBuckets: 1.048576M (1048576)
|
||||
- BuildRows: 478.171K (478171)
|
||||
- BuildTime: 187.794ms
|
||||
- 1-FetchRightTableTime: 175.810ms
|
||||
- 2-CopyRightTableChunkTime: 5.942ms
|
||||
- 3-BuildHashTableTime: 5.811ms
|
||||
- 4-BuildPushDownExprTime: 0ns
|
||||
- PeakMemoryUsage: 22.38 MB
|
||||
- ProbeRows: 31.609786M (31609786)
|
||||
- ProbeTime: 807.406ms
|
||||
- 1-FetchLeftTableTimer: 282.257ms
|
||||
- 2-SearchHashTableTimer: 457.235ms
|
||||
- 3-OutputBuildColumnTimer: 26.135ms
|
||||
- 4-OutputProbeColumnTimer: 16.138ms
|
||||
- 5-OutputTupleColumnTimer: 1.127ms
|
||||
- PushDownExprNum: 0
|
||||
- RowsReturned: 438.502K (438502)
|
||||
- RowsReturnedRate: 440.114K /sec
|
||||
```
|
||||
|
||||
## Query hint
|
||||
|
||||
Query hint 是一种指令或注释,显式地向查询优化器建议如何执行查询。目前 StarRocks 支持三种 hint:系统变量 hint (`SET_VAR`),用户自定义变量 hint (`SET_USER_VARIABLE`) 和 Join hint。Hint 仅在单个查询范围内生效。
|
||||
|
||||
### 系统变量 hint
|
||||
|
||||
在 SELECT、SUBMIT TASK 语句中使用 `SET_VAR` hint 设置一个或多个[系统变量](../sql-reference/System_variable.md) ,然后执行该语句。其他语句中如果包含 SELECT 子句(如 CREATE MATERIALIZED VIEW AS SELECT,CREATE VIEW AS SELECT),则您也可以在该 SELECT 子句中使用 `SET_VAR` hint。注意如果在 CTE 中的 SELECT 子句中使用 `SET_VAR` hint 设置系统变量,即使语句执行成功,但是该 `SET_VAR` hint 不会生效。
|
||||
|
||||
相比于[系统变量的一般用法](../sql-reference/System_variable.md)是会话级别生效的,`SET_VAR` hint 是语句级别生效,不会影响整个会话。
|
||||
|
||||
#### 语法
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_VAR(key=value [, key = value]) */ ...
|
||||
SUBMIT [/*+ SET_VAR(key=value [, key = value]) */] TASK ...
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
如果需要指定聚合查询的聚合方式,可以在聚合查询中使用 `SET_VAR` hint 设置系统变量 `streaming_preaggregation_mode` 和 `new_planner_agg_stage`。
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_VAR (streaming_preaggregation_mode = 'force_streaming',new_planner_agg_stage = '2') */ SUM(sales_amount) AS total_sales_amount FROM sales_orders;
|
||||
```
|
||||
|
||||
如果需要指定 SUBMIT TASK 语句执行超时时间,可以在 SUBMIT TASK 语句中使用 `SET_VAR` hint 设置系统变量 `insert_timeout`。
|
||||
|
||||
```SQL
|
||||
SUBMIT /*+ SET_VAR(insert_timeout=3) */ TASK
|
||||
AS CREATE TABLE temp AS SELECT count(*) AS cnt FROM tbl1;
|
||||
```
|
||||
|
||||
如果需要指定创建物化视图的子查询执行超时时间,可以在 SELECT 子句中使用 `SET_VAR` hint 设置系统变量 `query_timeout`。
|
||||
|
||||
```SQL
|
||||
CREATE MATERIALIZED VIEW mv
|
||||
PARTITION BY dt
|
||||
DISTRIBUTED BY HASH(`key`)
|
||||
BUCKETS 10
|
||||
REFRESH ASYNC
|
||||
AS SELECT /*+ SET_VAR(query_timeout=500) */ * from dual;
|
||||
```
|
||||
|
||||
### 用户自定义变量 hint
|
||||
|
||||
在 SELECT 或者 INSERT 语句中使用 `SET_USER_VARIABLE` hint 设置一个或多个[用户自定义变量](../sql-reference/user_defined_variables.md) ,然后执行该语句。如果其他语句中包含 SELECT 子句(如 SELECT 语句和 INSERT 语句,不包括 CREATE MATERIALIZED VIEW AS SELECT,CREATE VIEW AS SELECT),则您也可以在该 SELECT 子句中使用 `SET_USER_VARIABLE` hint。注意如果在 CTE 中的 SELECT 子句中使用 `SET_USER_VARIABLE` hint 设置系统变量,即使语句执行成功,但是该 `SET_USER_VARIABLE` hint 不会生效。自 3.2.4 起,StarRocks 支持用户自定义变量 hint。
|
||||
|
||||
相比于[用户自定义变量的一般用法](../sql-reference/user_defined_variables.md)是会话级别生效的,`SET_USER_VARIABLE` hint 是语句级别生效,不会影响整个会话。
|
||||
|
||||
#### 语法
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
INSERT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
||||
如下 SELECT 语句中引用了标量子查询 `select max(age) from users` 和 `select min(name) from users`,则您可以使用 `SET_USER_VARIABLE` hint,将这两个标量子查询设置为用户自定义变量,然后执行查询。
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_USER_VARIABLE (@a = (select max(age) from users), @b = (select min(name) from users)) */ * FROM sales_orders where sales_orders.age = @a and sales_orders.name = @b;
|
||||
```
|
||||
|
||||
### Join hint
|
||||
|
||||
针对多表关联查询,优化器一般会主动选择最优的 Join 执行方式。在特殊情况下,您也可以使用 Join hint 显式地向优化器建议 Join 执行方式、以及禁用 Join Reorder。目前 Join hint 支持的 Join 执行方式有 Shuffle Join、Broadcast Join、Bucket Shuffle Join 和 Colocate Join。
|
||||
|
||||
当您使用 Join hint 建议 Join 的执行方式后,优化器不会进行 Join Reorder,因此您需要确保右表为较小的表。并且当您所建议的 Join 执行方式为 [Colocate Join](../using_starrocks/Colocate_join.md) 或者 Bucket Shuffle Join 时,您需要确保表的数据分布情况满足这两种 Join 执行方式的要求,否则所建议的 Join 执行方式不生效。
|
||||
|
||||
#### 语法
|
||||
|
||||
```SQL
|
||||
... JOIN { [BROADCAST] | [SHUFFLE] | [BUCKET] | [COLOCATE] | [UNREORDER]} ...
|
||||
```
|
||||
|
||||
> **说明**
|
||||
>
|
||||
> 使用 Join hint 时大小写不敏感。
|
||||
|
||||
#### 示例
|
||||
|
||||
* Shuffle Join
|
||||
|
||||
如果需要将表 A、B 中分桶键取值相同的数据行 Shuffle 到相同机器上,再进行 Join 操作,则您可以设置 Join hint 为 Shuffle Join。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [SHUFFLE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
* Broadcast Join
|
||||
|
||||
如果表 A 是个大表,表 B 是个小表,则您可以设置 Join hint 为 Broadcast Join。表 B 的数据全量广播到表 A 数据所在的机器上,再进行 Join 操作。Broadcast Join 相比较于 Shuffle Join,节省了 Shuffle 表 A 数据的开销。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BROADCAST] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
* Bucket Shuffle Join
|
||||
|
||||
如果关联查询中 Join 等值表达式命中表 A 的分桶键 ,尤其是在表 A 和表 B 均是大表的情况下,您可以设置 Join hint 为 Bucket Shuffle Join。表 B 数据会按照表 A 数据的分布方式,Shuffle 到表 A 数据所在机器上,再进行 Join 操作。Bucket Shuffle Join 是在 Broadcast Join 的基础上进一步优化,Shuffle B 表的数据量全局只有一份,比 Broadcast Join 少传输了很多倍数据量。
|
||||
参与 Bucket Shuffle Join 的表必须是非分区表或者 Colocate Join 表。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BUCKET] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
* Colocate Join
|
||||
|
||||
如果建表时指定表 A 和 B 属于同一个 Colocation Group,则表 A 和表 B 分桶键取值相同的数据行一定分布在相同 BE 节点上。当关联查询中 Join 等值表达式命中表 A 和 B 的分桶键,则您可以设置 Join hint 为 Colocate Join。 具有相同键值的数据直接在本地 Join,减少数据在节点间的传输耗时,从而提高查询性能。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
#### 查看实际的 Join 执行方式
|
||||
|
||||
通过 `EXPLAIN` 命令来查看 Join hint 是否生效。如果返回结果所显示的 Join 执行方式符合 Join hint,则表示 Join hint 生效。
|
||||
|
||||
```SQL
|
||||
EXPLAIN select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 查看 SQL 指纹
|
||||
|
||||
StarRocks 支持规范化慢查询中 SQL 语句,归类并计算各个类型 SQL 语句的 MD5 哈希值。
|
||||
|
||||
您可以在 **fe.audit.log.slow_query** 中查看慢查询相关信息,其中 MD5 哈希值对应字段为 `Digest`。
|
||||
|
||||
```plain text
|
||||
2021-12-27 15:13:39,108 [slow_query] |Client=172.26.xx.xxx:54956|User=root|Db=default_cluster:test|State=EOF|Time=2469|ScanBytes=0|ScanRows=0|ReturnRows=6|StmtId=3|QueryId=824d8dc0-66e4-11ec-9fdc-00163e04d4c2|IsQuery=true|feIp=172.26.92.195|Stmt=select count(*) from test_basic group by id_bigint|Digest=51390da6b57461f571f0712d527320f4
|
||||
```
|
||||
|
||||
SQL 语句规范化仅保留重要的语法结构,对 SQL 语句进行以下操作:
|
||||
|
||||
* 保留对象标识符,如数据库和表的名称。
|
||||
* 转换常量为 `?`。
|
||||
* 删除注释并调整空格。
|
||||
|
||||
以下两个 SQL 语句,规范化后属于同一类SQL。
|
||||
|
||||
```sql
|
||||
SELECT * FROM orders WHERE customer_id=10 AND quantity>20
|
||||
|
||||
SELECT * FROM orders WHERE customer_id = 20 AND quantity > 100
|
||||
```
|
||||
|
||||
以下为规范化后 SQL 类型。
|
||||
|
||||
```sql
|
||||
SELECT * FROM orders WHERE customer_id=? AND quantity>?
|
||||
```
|
||||
|
|
@ -92,7 +92,7 @@ SHOW PARTITIONS FROM starrocks_audit_db__.starrocks_audit_tbl__;
|
|||
- `user`:集群用户名。该用户必须具有对应表的 INSERT 权限。
|
||||
- `password`:集群用户密码。
|
||||
- `secret_key`:用于加密密码的 Key(字符串,长度不得超过 16 个字节)。如果该参数为空,则表示不对 **plugin.conf** 中的密码进行加解密,您只需在 `password` 处直接配置明文密码。如果该参数不为空,表示需要通过该 Key 对密码进行加解密,您需要在 `password` 处配置加密后的字符串。加密后的密码可在 StarRocks 中通过 `AES_ENCRYPT` 函数生成:`SELECT TO_BASE64(AES_ENCRYPT('password','secret_key'));`。
|
||||
- `enable_compute_all_query_digest`:是否对所有查询都生成 Hash SQL 指纹(StarRocks 默认只为慢查询开启 SQL 指纹)。需注意插件中的指纹计算方法与 FE 内部的方法不一致,FE 会对 SQL 语句[规范化处理](../Query_planning.md#%E6%9F%A5%E7%9C%8B-sql-%E6%8C%87%E7%BA%B9),而插件不会,且如果开启该参数,指纹计算会额外占用集群内的计算资源。
|
||||
- `enable_compute_all_query_digest`:是否对所有查询都生成 Hash SQL 指纹(StarRocks 默认只为慢查询开启 SQL 指纹)。需注意插件中的指纹计算方法与 FE 内部的方法不一致,FE 会对 SQL 语句[规范化处理](../../best_practices/query_tuning/query_planning.md#%E6%9F%A5%E7%9C%8B-sql-%E6%8C%87%E7%BA%B9),而插件不会,且如果开启该参数,指纹计算会额外占用集群内的计算资源。
|
||||
- `filter`:审计信息入库的过滤条件。该参数基于 Stream Load 中的 [WHERE 参数](../../sql-reference/sql-statements/loading_unloading/STREAM_LOAD.md#opt_properties) 实现,即 `-H "where: <condition>"`,默认值为空字符串。示例:`filter=isQuery=1 and clientIp like '127.0.0.1%' and user='root'`。
|
||||
|
||||
4. 重新打包以上文件。
|
||||
|
|
|
|||
|
|
@ -1,100 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
---
|
||||
|
||||
# Query Profile 概述
|
||||
|
||||
本文介绍如何查看并分析 Query Profile。Query Profile 记录了查询中涉及的所有工作节点的执行信息。您可以通过 Query Profile 快速识别影响 StarRocks 集群查询性能的瓶颈。
|
||||
|
||||
自 v3.3.0 起,StarRocks 支持为 INSERT INTO FILES() 和 Broker Load 导入方式提供 Query Profile。相关指标详情,请参考 [OlapTableSink Operator](./query_profile_details.md#olaptablesink-operator)。
|
||||
|
||||
## 启用 Query Profile
|
||||
|
||||
您可以通过将变量 `enable_profile` 设置为 `true` 以启用 Query Profile:
|
||||
|
||||
```SQL
|
||||
SET enable_profile = true;
|
||||
```
|
||||
|
||||
### 针对慢查询开启 Query Profile
|
||||
|
||||
在生产环境中,通常不推荐全面启用 Query Profile 功能。这是因为 Query Profile 的数据采集和处理过程可能会为系统带来额外的负担。然而,如果需要捕捉到耗时的慢查询,就需要巧妙地使用这一功能。为此,您可以选择只对慢查询启用 Query Profile。这可以通过设置变量 `big_query_profile_threshold` 为一个大于 `0s` 的时间来实现。例如,若将此变量设置为 `30s`,意味着只有那些执行时间超过 30 秒的查询会启用 Query Profile 功能。这样既保证了系统性能,又能有效监控到慢查询。
|
||||
|
||||
```SQL
|
||||
-- 30 seconds
|
||||
SET global big_query_profile_threshold = '30s';
|
||||
|
||||
-- 500 milliseconds
|
||||
SET global big_query_profile_threshold = '500ms';
|
||||
|
||||
-- 60 minutes
|
||||
SET global big_query_profile_threshold = '60m';
|
||||
```
|
||||
|
||||
### 启用 Runtime Query Profile
|
||||
|
||||
某些查询可能需要耗费较长时间执行,从数十秒到数小时不等。在查询完成之前,经常无法判断查询是否还在进行或是系统已经死机。为解决这个问题,StarRocks 在 v3.1 及以上版本中引入了 Runtime Query Profile 功能。此功能允许 StarRocks 在查询执行过程中,按固定时间间隔收集并上报 Query Profile 数据。这使您能够实时了解查询的执行进度和潜在的瓶颈点,而不必等到查询完全结束。通过这种方式,您可以更有效地监控和优化查询过程。
|
||||
|
||||
当 Query Profile 启用时,该功能会自动启用,默认的上报时间间隔为 10 秒。您可以通过修改变量 `runtime_profile_report_interval` 来调整对应的时间间隔:
|
||||
|
||||
```SQL
|
||||
SET runtime_profile_report_interval = 30;
|
||||
```
|
||||
|
||||
Runtime Query Profile 与普通 Query Profile 格式和内容均相同。您可以像分析常规 Query Profile 一样分析 Runtime Query Profile,以此了解集群内正在运行的查询的性能指标。
|
||||
|
||||
### 配置 Query Profile 行为
|
||||
|
||||
| 配置方式 | 配置项 | 可选值 | 默认值 | 含义 |
|
||||
| -- | -- | -- | -- | -- |
|
||||
| Session 变量 | enable_profile | true/false | false |是否启用 Query Profile 功能。`true` 表示启用。 |
|
||||
| Session 变量 | pipeline_profile_level | 1/2 | 1 | 设置 Query Profile 的级别。`1` 表示会对 Profile 进行合并展示;`2` 表示保留原始的 Profile,如果选用这一级别,那么所有可视化的分析工具将不再起作用,因此通常不建议修改该参数。 |
|
||||
| Session 变量 | runtime_profile_report_interval | 正整数 | 10 | 设置 Runtime Query Profile 上报的时间间隔,单位秒。 |
|
||||
| Session 变量 | big_query_profile_threshold | 字符串 | `0s` | 设置长查询自动开启 Query Profile 的阈值,`0s` 表示关闭该功能。整数结合时间单位表示启用,可以用单位包括:`ms`、`s`、`m`。 |
|
||||
| FE 动态配置项 | enable_statistics_collect_profile | true/false | false | 是否启用统计信息采集相关查询的 Query Profile。`true` 表示启用。 |
|
||||
| FE 动态配置项 | profile_info_format | default/json | default | 系统输出 Profile 的格式。设置为 `default` 时,Profile 为默认格式。设置为 `json` 时,系统输出 JSON 格式 Profile。 |
|
||||
|
||||
## 获取 Query Profile
|
||||
|
||||
### 通过 Web 页面获取
|
||||
|
||||
以下步骤获取 Query Profile:
|
||||
|
||||
1. 在浏览器中访问 `http://<fe_ip>:<fe_http_port>`。
|
||||
2. 在显示的页面上,单击顶部导航中的 **queries**。
|
||||
3. 在 **Finished Queries** 列表中,选择您要分析的查询并单击 **Profile** 列中的链接。
|
||||
|
||||

|
||||
|
||||
页面将跳转至相应 Query Profile。
|
||||
|
||||

|
||||
|
||||
### 通过 get_query_profile 函数获取
|
||||
|
||||
以下示例展示了如何获取 Query Profile:
|
||||
|
||||
```
|
||||
-- Enable the profiling feature.
|
||||
set enable_profile = true;
|
||||
|
||||
-- Run a simple query.
|
||||
select 1;
|
||||
|
||||
-- Get the query_id of the query.
|
||||
select last_query_id();
|
||||
+--------------------------------------+
|
||||
| last_query_id() |
|
||||
+--------------------------------------+
|
||||
| bd3335ce-8dde-11ee-92e4-3269eb8da7d1 |
|
||||
+--------------------------------------+
|
||||
|
||||
-- Obtain the query profile.
|
||||
select get_query_profile('502f3c04-8f5c-11ee-a41f-b22a2c00f66b')\G
|
||||
```
|
||||
|
||||
## 分析 Query Profile
|
||||
|
||||
Query Profile 生成的原始文本内容非常庞大,包含了众多指标。如需详细了解这些指标,请参阅[Query Profile 结构与详细指标](./query_profile_details.md)。
|
||||
|
||||
然而,对于非开发者的普通用户来说,直接分析这些原始文本可能并非易事。为了解决这一问题,StarRocks 提供了 [文本可视化 Query Profile](./query_profile_text_based_analysis.md) 的分析方式。您可以通过该功能更直观地理解复杂 Query Profile 的含义。
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
---
|
||||
|
||||
# 文本可视化 Query Profile
|
||||
|
||||
本文介绍了如何通过 MySQL 客户端获取并分析 Query Profile。
|
||||
|
||||
## 使用 ANALYZE PROFILE 分析已有查询
|
||||
|
||||
首先,您需要通过 SHOW PROFILELIST 语句来获取查询的概要信息,该命令会列出所有正常结束、异常结束,以及仍在运行(运行 10 秒以上且仍未结束)的查询。通过这个语句,您可以获取到对应的 Query ID,方便进行后续的 Query Profile 分析。语法如下:
|
||||
|
||||
```SQL
|
||||
SHOW PROFILELIST [LIMIT <num>];
|
||||
```
|
||||
|
||||
示例如下:
|
||||
|
||||
```SQL
|
||||
SHOW PROFILELIST;
|
||||
SHOW PROFILELIST LIMIT 5;
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
```
|
||||
+--------------------------------------+---------------------+-------+----------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
| QueryId | StartTime | Time | State | Statement |
|
||||
+--------------------------------------+---------------------+-------+----------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
| a40456b2-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:18 | 21ms | Finished | SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES\n WHERE ROUTINE_TYPE="FUNCTION" AND ROUTINE_SCHEMA = "None" |
|
||||
| a3fc4060-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:17 | 39ms | Finished | select TABLE_NAME, COLUMN_NAME from information_schema.columns\n where table_schema = 'Non ... |
|
||||
| a3f7d38d-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:17 | 15ms | Finished | select connection_id() |
|
||||
| a3efbd3b-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:17 | 16ms | Finished | select connection_id() |
|
||||
| a26ec286-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:15 | 269ms | Error | EXPLAIN ANALYZE SELECT c_nation, s_nation, year(lo_orderdate) AS year , SUM(lo_revenue) AS revenue FROM lineorder_flat WHER ... |
|
||||
+--------------------------------------+---------------------+-------+----------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
在取得 Query ID 后,您可以通过 ANALYZE PROFILE 语句对 Query Profile 进行下一步的分析,其语法如下:
|
||||
|
||||
```SQL
|
||||
ANALYZE PROFILE FROM '<Query_ID>' [, <Node_ID> [, ...] ]
|
||||
```
|
||||
|
||||
- `Query_ID`:查询对应的 ID。您可以通过 SHOW PROFILELIST 语句获取。
|
||||
- `Node_ID`:Profile 节点 ID。对于指定了 ID 的节点,StarRocks 会输出该节点的所有指标信息。对于未指定 ID 的节点,StarRocks 仅输出该节点的概要信息。
|
||||
|
||||
其输出内容包含如下几个部分:
|
||||
|
||||
- Summary:Profile 概要信息。
|
||||
- QueryID
|
||||
- 版本信息
|
||||
- 查询状态,包括:`Finished`、`Error` 以及 `Running`。
|
||||
- 查询总耗时。
|
||||
- 内存使用情况
|
||||
- CPU 使用占比最高的 10 个节点。
|
||||
- 内存使用占比最高的 10 个节点。
|
||||
- 与默认值不同的 Session Variable。
|
||||
- Fragments:以 Fragment 为单位,依次展示每个 Fragment 中各个节点的指标。
|
||||
- 每个节点的耗时、内存占用、Cost 估算信息,输出行数等。
|
||||
- 当节点的耗时占比超过 30%,该节点会用红色加粗标出。
|
||||
- 当节点的耗时占比超过 15% 且小于 30%,该节点会用粉红色加粗标出。
|
||||
|
||||
示例一:查询 Query Profile,不指定节点 ID。
|
||||
|
||||

|
||||
|
||||
示例二:查询 Query Profile,并指定节点 ID 为 `0`。StarRocks 会返回 Node ID 为 `0` 的节点的所有详细指标,并且高亮显示使用占比较高的指标,便于定位问题。
|
||||
|
||||

|
||||
|
||||
此外,以上方法也支持 Runtime Query Profile 的展示分析。对于开启了 Query Profile 功能,且运行超过 10 秒仍未结束的查询,您可以通过该方法获取 Profile。
|
||||
|
||||
相对于已结束的查询,正在运行的查询的文本可视化 Query Profile 包含以下信息:
|
||||
|
||||
- 算子状态:
|
||||
|
||||
- ⏳:未启动的算子。这些算子可能由于依赖关系而尚未开始执行。
|
||||
- 🚀:运行中的算子。
|
||||
- ✅:已结束执行的算子。
|
||||
|
||||
- 整体进度展示:根据 `已结束执行的算子数量/所有算子数量` 计算得到。由于没有考虑到行数信息,这个进度可能有点失真。
|
||||
- 算子进度展示:根据 `已经处理的行数/总行数` 计算得到,若无法计算总行数,则该进度显示为 `?`。
|
||||
|
||||
示例:
|
||||
|
||||

|
||||
|
||||
|
||||
## 使用 EXPLAIN ANALYZE 语句模拟分析查询
|
||||
|
||||
StarRocks 提供了 EXPLAIN ANALYZE 语句,方便您对查询直接进行模拟并分析其 Profile,语法如下:
|
||||
|
||||
```SQL
|
||||
EXPLAIN ANALYZE <sql_statement>
|
||||
```
|
||||
|
||||
执行 EXPLAIN ANALYZE 时,StarRocks 默认会为当前会话开启 Query Profile 功能。
|
||||
|
||||
目前,EXPLAIN ANALYZE 支持两种类型的 SQL 语句:查询(SELECT)语句和 INSERT INTO 语句。您只能在 StarRocks 内表上模拟 INSERT INTO 语句并分析其 Query Profile。请注意,当您模拟并分析 INSERT INTO 语句的 Query Profile 时,实际上不会导入任何数据。默认情况下,导入事务会被中止,以确保在分析过程中不会对数据进行意外更改。
|
||||
|
||||
示例一:模拟分析 SELECT 语句,查询返回结果会被丢弃。
|
||||
|
||||

|
||||
|
||||
|
||||
示例二:模拟分析 INSERT INTO 语句。完成后,导入事务会被中止,数据不会被实际导入。
|
||||
|
||||

|
||||
|
||||
## 限制
|
||||
|
||||
- EXPLAIN ANALYZE INSERT INTO 语句仅支持内表。
|
||||
- 为了获得更好的视觉效果,输出文本中包含了 ANSI 字符,以提供颜色、高亮等功能。推荐使用 MyCLI 客户端。对于不兼容 ANSI 功能的客户端,比如 MySQL 客户端,可能会出现右侧边界未对齐的现象,但并不影响使用。例如:
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,7 @@
|
|||
label: '查询调优'
|
||||
position: 200
|
||||
collapsed: true
|
||||
link:
|
||||
type: generated-index
|
||||
title: '查询调优最佳实践'
|
||||
description: '学习如何在 StarRocks 中分析、调优和优化查询。'
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 70
|
||||
---
|
||||
|
||||
# 查询提示
|
||||
|
||||
查询提示是指示或注释,用于明确建议查询优化器如何执行查询。目前,StarRocks 支持三种类型的提示:系统变量提示 (`SET_VAR`)、用户自定义变量提示 (`SET_USER_VARIABLE`) 和 Join 提示。提示仅在单个查询中生效。
|
||||
|
||||
## 系统变量提示
|
||||
|
||||
您可以在 SELECT 和 SUBMIT TASK 语句中使用 `SET_VAR` 提示来设置一个或多个[系统变量](../../sql-reference/System_variable.md),然后执行这些语句。您还可以在其他语句中包含的 SELECT 子句中使用 `SET_VAR` 提示,例如 CREATE MATERIALIZED VIEW AS SELECT 和 CREATE VIEW AS SELECT。请注意,如果在 CTE 的 SELECT 子句中使用 `SET_VAR` 提示,即使语句成功执行,`SET_VAR` 提示也不会生效。
|
||||
|
||||
与[系统变量的一般用法](../../sql-reference/System_variable.md)相比,`SET_VAR` 提示在语句级别生效,不会影响整个会话。
|
||||
|
||||
### 语法
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_VAR(key=value [, key = value]) */ ...
|
||||
SUBMIT [/*+ SET_VAR(key=value [, key = value]) */] TASK ...
|
||||
```
|
||||
|
||||
### 示例
|
||||
|
||||
要为聚合查询指定聚合模式,可以在聚合查询中使用 `SET_VAR` 提示设置系统变量 `streaming_preaggregation_mode` 和 `new_planner_agg_stage`。
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_VAR (streaming_preaggregation_mode = 'force_streaming',new_planner_agg_stage = '2') */ SUM(sales_amount) AS total_sales_amount FROM sales_orders;
|
||||
```
|
||||
|
||||
要为 SUBMIT TASK 语句指定执行超时,可以在 SUBMIT TASK 语句中使用 `SET_VAR` 提示设置系统变量 `insert_timeout`。
|
||||
|
||||
```SQL
|
||||
SUBMIT /*+ SET_VAR(insert_timeout=3) */ TASK AS CREATE TABLE temp AS SELECT count(*) AS cnt FROM tbl1;
|
||||
```
|
||||
|
||||
要为创建物化视图指定子查询执行超时,可以在 SELECT 子句中使用 `SET_VAR` 提示设置系统变量 `query_timeout`。
|
||||
|
||||
```SQL
|
||||
CREATE MATERIALIZED VIEW mv
|
||||
PARTITION BY dt
|
||||
DISTRIBUTED BY HASH(`key`)
|
||||
BUCKETS 10
|
||||
REFRESH ASYNC
|
||||
AS SELECT /*+ SET_VAR(query_timeout=500) */ * from dual;
|
||||
```
|
||||
|
||||
## 用户自定义变量提示
|
||||
|
||||
您可以在 SELECT 语句或 INSERT 语句中使用 `SET_USER_VARIABLE` 提示来设置一个或多个[用户自定义变量](../../sql-reference/user_defined_variables.md)。如果其他语句包含 SELECT 子句,您也可以在该 SELECT 子句中使用 `SET_USER_VARIABLE` 提示。其他语句可以是 SELECT 语句和 INSERT 语句,但不能是 CREATE MATERIALIZED VIEW AS SELECT 语句和 CREATE VIEW AS SELECT 语句。请注意,如果在 CTE 的 SELECT 子句中使用 `SET_USER_VARIABLE` 提示,即使语句成功执行,`SET_USER_VARIABLE` 提示也不会生效。从 v3.2.4 开始,StarRocks 支持用户自定义变量提示。
|
||||
|
||||
与[用户自定义变量的一般用法](../../sql-reference/user_defined_variables.md)相比,`SET_USER_VARIABLE` 提示在语句级别生效,不会影响整个会话。
|
||||
|
||||
### 语法
|
||||
|
||||
```SQL
|
||||
[...] SELECT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
INSERT /*+ SET_USER_VARIABLE(@var_name = expr [, @var_name = expr]) */ ...
|
||||
```
|
||||
|
||||
### 示例
|
||||
|
||||
以下 SELECT 语句引用了标量子查询 `select max(age) from users` 和 `select min(name) from users`,因此您可以使用 `SET_USER_VARIABLE` 提示将这两个标量子查询设置为用户自定义变量,然后运行查询。
|
||||
|
||||
```SQL
|
||||
SELECT /*+ SET_USER_VARIABLE (@a = (select max(age) from users), @b = (select min(name) from users)) */ * FROM sales_orders where sales_orders.age = @a and sales_orders.name = @b;
|
||||
```
|
||||
|
||||
## Join 提示
|
||||
|
||||
对于多表 Join 查询,优化器通常会选择最佳的 Join 执行方法。在特殊情况下,您可以使用 Join 提示明确建议优化器使用的 Join 执行方法或禁用 Join Reorder。目前,Join 提示支持建议 Shuffle Join、Broadcast Join、Bucket Shuffle Join 或 Colocate Join 作为 Join 执行方法。当使用 Join 提示时,优化器不会执行 Join Reorder。因此,您需要选择较小的表作为右表。此外,当建议使用 [Colocate Join](../../using_starrocks/Colocate_join.md) 或 Bucket Shuffle Join 作为 Join 执行方法时,请确保连接表的数据分布符合这些 Join 执行方法的要求。否则,建议的 Join 执行方法无法生效。
|
||||
|
||||
### 语法
|
||||
|
||||
```SQL
|
||||
... JOIN { [BROADCAST] | [SHUFFLE] | [BUCKET] | [COLOCATE] | [UNREORDER]} ...
|
||||
```
|
||||
|
||||
:::note
|
||||
Join 提示不区分大小写。
|
||||
:::
|
||||
|
||||
### 示例
|
||||
|
||||
- Shuffle Join
|
||||
|
||||
如果需要在执行 Join 操作之前将具有相同分桶键值的数据行从表 A 和表 B 洗牌到同一台机器上,可以将 Join 执行方法提示为 Shuffle Join。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [SHUFFLE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Broadcast Join
|
||||
|
||||
如果表 A 是一个大表,表 B 是一个小表,可以将 Join 执行方法提示为 Broadcast Join。表 B 的数据完全广播到表 A 所在的机器上,然后执行 Join 操作。与 Shuffle Join 相比,Broadcast Join 节省了洗牌表 A 数据的成本。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BROADCAST] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Bucket Shuffle Join
|
||||
|
||||
如果 Join 查询中的等值连接表达式包含表 A 的分桶键,尤其是当表 A 和表 B 都是大表时,可以将 Join 执行方法提示为 Bucket Shuffle Join。表 B 的数据根据表 A 的数据分布洗牌到表 A 所在的机器上,然后执行 Join 操作。与 Broadcast Join 相比,Bucket Shuffle Join 显著减少了数据传输,因为表 B 的数据只需全局洗牌一次。参与 Bucket Shuffle Join 的表必须是非分区的或同置的。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [BUCKET] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
- Colocate Join
|
||||
|
||||
如果表 A 和表 B 属于在创建表时指定的同一 Colocation Group,具有相同分桶键值的数据行从表 A 和表 B 分布在同一 BE 节点上。当 Join 查询中的等值连接表达式包含表 A 和表 B 的分桶键时,可以将 Join 执行方法提示为 Colocate Join。具有相同键值的数据直接在本地连接,减少了节点之间的数据传输时间,提高了查询性能。
|
||||
|
||||
```SQL
|
||||
select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||
### 查看 Join 执行方法
|
||||
|
||||
使用 `EXPLAIN` 命令查看实际的 Join 执行方法。如果返回的结果显示 Join 执行方法与 Join 提示匹配,则表示 Join 提示有效。
|
||||
|
||||
```SQL
|
||||
EXPLAIN select k1 from t1 join [COLOCATE] t2 on t1.k1 = t2.k2 group by t2.k2;
|
||||
```
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
# 查询调优简介
|
||||
|
||||
查询调优对于在 StarRocks 中实现高性能和高可靠性至关重要。本目录汇集了实用指南、参考资料和可操作的方案,帮助您在每个阶段分析、诊断和优化查询性能——从编写 SQL 到解释执行细节。
|
||||
|
||||
在 StarRocks 中,有效的查询调优通常遵循自上而下的过程:
|
||||
|
||||
1. **识别问题**
|
||||
- 检测慢查询、高资源使用或意外结果。
|
||||
- 在 StarRocks 中,利用内置的监控工具、查询历史和审计日志快速识别问题查询或异常模式。
|
||||
- 参见:**[查询调优方案](./query_profile_tuning_recipes.md)** 进行症状驱动的诊断,和 **[查询概况概览](./query_profile_overview.md)** 访问查询历史和概况。
|
||||
|
||||
2. **收集和分析执行信息**
|
||||
- 使用 `EXPLAIN` 或 `EXPLAIN ANALYZE` 获取查询计划。
|
||||
- 启用并查看 Query Profile 以收集详细的执行指标。
|
||||
- 参见:**[查询计划概览](./query_planning.md)** 理解查询计划,**[Explain Analyze & 基于文本的概况分析](./query_profile_text_based_analysis.md)** 进行逐步分析,以及 **[查询概况概览](./query_profile_overview.md)** 启用和解释概况。
|
||||
|
||||
3. **定位根本原因**
|
||||
- 确定哪个阶段或 Operator 消耗了最多的时间或资源。
|
||||
- 检查常见问题:次优的连接顺序、缺失的索引、数据分布问题或低效的 SQL 模式。
|
||||
- 参见:**[查询概况指标](./query_profile_operator_metrics.md)** 获取指标和 Operator 的词汇表,以及 **[查询调优方案](./query_profile_tuning_recipes.md)** 进行根本原因分析。
|
||||
|
||||
4. **应用调优策略**
|
||||
- SQL 重写:重写或优化 SQL 查询(例如,添加过滤器,避免使用 SELECT *)。
|
||||
- 模型调优:添加索引、更改表模型、分区、聚簇。
|
||||
- 查询计划调优:如有必要,使用提示或变量引导优化器。
|
||||
- 执行调优:针对特定工作负载调整会话变量。
|
||||
- 参见:**[模型调优方案](./schema_tuning.md)** 进行模型级别优化,**[查询提示](./query_hint.md)** 获取优化器提示,以及 **[查询调优方案](./query_profile_tuning_recipes.md)** 进行计划调优和执行调优。
|
||||
|
||||
5. **验证和迭代**
|
||||
- 重新运行查询并比较更改前后的性能。
|
||||
- 查看新的查询计划和概况以确保改进。
|
||||
- 根据需要重复该过程以进一步优化。
|
||||
|
||||
无论您是 DBA、开发人员还是数据工程师,这些资源将帮助您:
|
||||
- 诊断和解决慢速或资源密集型查询
|
||||
- 理解优化器选择和执行细节
|
||||
- 应用最佳实践和高级调优策略
|
||||
|
||||
从概览开始,根据需要深入参考资料,并使用方案和技巧解决 StarRocks 中的实际性能挑战。
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 20
|
||||
---
|
||||
|
||||
# 查询计划
|
||||
|
||||
优化查询性能是分析系统中的一个常见挑战。慢查询会影响用户体验和整个集群的性能。在StarRocks中,理解和解释查询计划和查询分析是诊断和改进慢查询的基础。这些工具可以帮助你:
|
||||
- 识别瓶颈和昂贵的操作
|
||||
- 发现次优的连接策略或缺失的索引
|
||||
- 理解数据是如何被过滤、聚合和移动的
|
||||
- 排查和优化资源使用
|
||||
|
||||
**查询计划** 是由StarRocks FE生成的详细路线图,描述了你的SQL语句将如何执行。它将查询分解为一系列操作,如扫描、连接、聚合和排序,并确定执行这些操作的最有效方式。
|
||||
|
||||
StarRocks提供了几种查看查询计划的方法:
|
||||
|
||||
1. **EXPLAIN 语句**:
|
||||
使用 `EXPLAIN` 显示查询的逻辑或物理执行计划。你可以添加选项来控制输出:
|
||||
- `EXPLAIN LOGICAL <query>`: 显示简化的计划。
|
||||
- `EXPLAIN <query>`: 显示基本的物理计划。
|
||||
- `EXPLAIN VERBOSE <query>`: 显示带有详细信息的物理计划。
|
||||
- `EXPLAIN COSTS <query>`: 包含每个操作的估计成本,用于诊断统计问题。
|
||||
|
||||
2. **EXPLAIN ANALYZE**:
|
||||
使用 `EXPLAIN ANALYZE <query>` 执行查询并显示实际执行计划以及真实的运行时统计信息。详情请参阅 [Explain Analyze](./query_profile_text_based_analysis.md) 文档。
|
||||
|
||||
示例:
|
||||
```sql
|
||||
EXPLAIN ANALYZE SELECT * FROM sales_orders WHERE amount > 1000;
|
||||
```
|
||||
|
||||
3. **Query Profile**:
|
||||
在运行查询后,你可以查看其详细的执行分析,包括时间、资源使用和操作级别的统计信息。请参阅 [Query Profile](./query_profile_overview.md) 文档,了解如何访问和解释这些信息。
|
||||
- **SQL命令**: `SHOW PROFILELIST` 和 `ANALYZE PROFILE FOR <query_id>`: 可用于检索特定查询的执行分析。
|
||||
- **FE HTTP 服务**: 通过StarRocks FE的Web UI访问查询分析,导航到 **Query** 或 **Profile** 部分,在那里你可以搜索和检查查询执行细节。
|
||||
- **托管版本**: 在云或托管部署中,使用提供的Web控制台或监控仪表板查看查询计划和分析,通常具有增强的可视化和过滤选项。
|
||||
|
||||
通常,查询计划用于诊断与查询计划和优化相关的问题,而查询分析有助于识别查询执行期间的性能问题。在接下来的部分中,我们将探讨查询执行的关键概念,并通过一个具体的示例来分析查询计划。
|
||||
|
||||
## 查询执行流程
|
||||
|
||||
在StarRocks中,查询的生命周期由三个主要阶段组成:
|
||||
1. **规划**: 查询经过解析、分析和优化,最终生成查询计划。
|
||||
2. **调度**: 调度器和协调器将计划分发给所有参与的后端节点。
|
||||
3. **执行**: 使用管道执行引擎执行计划。
|
||||
|
||||

|
||||
|
||||
**计划结构**
|
||||
|
||||
StarRocks计划是分层的:
|
||||
- **Fragment**: 顶层工作片段;每个Fragment在不同的后端节点上生成多个 **FragmentInstances**。
|
||||
- **Pipeline**: 在一个实例中,管道将操作符串联在一起;多个 **PipelineDrivers** 在不同的CPU核心上并发运行相同的管道。
|
||||
- **Operator**: 原子步骤——扫描、连接、聚合——实际处理数据。
|
||||
|
||||

|
||||
|
||||
**管道执行引擎**
|
||||
|
||||
管道引擎以并行和高效的方式执行查询计划,处理复杂的计划和大数据量,以实现高性能和可扩展性。
|
||||
|
||||

|
||||
|
||||
**指标合并策略**
|
||||
|
||||
默认情况下,StarRocks合并FragmentInstance和PipelineDriver层以减少分析体积,形成简化的三层结构:
|
||||
- Fragment
|
||||
- Pipeline
|
||||
- Operator
|
||||
|
||||
你可以通过会话变量 `pipeline_profile_level` 控制这种合并行为。
|
||||
|
||||
## 示例
|
||||
|
||||
### 如何阅读查询计划和分析
|
||||
|
||||
1. **理解结构**: 查询计划分为多个片段,每个片段代表一个执行阶段。从下往上阅读:首先是扫描节点,然后是连接、聚合,最后是结果。
|
||||
|
||||
2. **整体分析**:
|
||||
- 检查总运行时间、内存使用和CPU/墙时间比率。
|
||||
- 通过按操作符时间排序找到慢操作符。
|
||||
- 确保过滤器尽可能下推。
|
||||
- 查找数据倾斜(不均匀的操作符时间或行数)。
|
||||
- 监控高内存或磁盘溢出;如有必要,调整连接顺序或使用汇总视图。
|
||||
- 根据需要使用物化视图和查询提示(`BROADCAST`、`SHUFFLE`、`COLOCATE`)进行优化。
|
||||
|
||||
2. **扫描操作**: 查找 `OlapScanNode` 或类似节点。注意扫描了哪些表,应用了哪些过滤器,以及是否使用了预聚合或物化视图。
|
||||
|
||||
3. **连接操作**: 确定连接类型(`HASH JOIN`、`BROADCAST`、`SHUFFLE`、`COLOCATE`、`BUCKET SHUFFLE`)。连接方法影响性能:
|
||||
- **Broadcast**: 小表发送到所有节点;适用于小表。
|
||||
- **Shuffle**: 行被分区和洗牌;适用于大表。
|
||||
- **Colocate**: 表按相同方式分区;支持本地连接。
|
||||
- **Bucket Shuffle**: 仅一个表被洗牌以减少网络成本。
|
||||
|
||||
4. **聚合和排序**: 查找 `AGGREGATE`、`TOP-N` 或 `ORDER BY`。这些操作在数据量大或高基数时可能开销较大。
|
||||
|
||||
5. **数据移动**: `EXCHANGE` 节点显示片段或节点之间的数据传输。过多的数据移动会影响性能。
|
||||
|
||||
6. **谓词下推**: 早期应用的过滤器(在扫描时)减少下游数据。检查 `PREDICATES` 或 `PushdownPredicates` 以查看哪些过滤器被下推。
|
||||
|
||||
### 示例查询计划
|
||||
|
||||
```sql
|
||||
EXPLAIN select count(*)
|
||||
from store_sales
|
||||
,household_demographics
|
||||
,time_dim
|
||||
, store
|
||||
where ss_sold_time_sk = time_dim.t_time_sk
|
||||
and ss_hdemo_sk = household_demographics.hd_demo_sk
|
||||
and ss_store_sk = s_store_sk
|
||||
and time_dim.t_hour = 8
|
||||
and time_dim.t_minute >= 30
|
||||
and household_demographics.hd_dep_count = 5
|
||||
and store.s_store_name = 'ese'
|
||||
order by count(*) limit 100;
|
||||
```
|
||||
|
||||
输出是一个分层计划,显示StarRocks将如何执行查询,分为片段和操作符。以下是一个简化的查询计划片段示例:
|
||||
|
||||
```
|
||||
PLAN FRAGMENT 1
|
||||
6:HASH JOIN (BROADCAST)
|
||||
|-- 4:HASH JOIN (BROADCAST)
|
||||
| |-- 2:HASH JOIN (BROADCAST)
|
||||
| | |-- 0:OlapScanNode (store_sales)
|
||||
| | |-- 1:OlapScanNode (time_dim)
|
||||
| |-- 3:OlapScanNode (household_demographics)
|
||||
|-- 5:OlapScanNode (store)
|
||||
```
|
||||
|
||||
- **OlapScanNode**: 扫描一个表,可能带有过滤器和预聚合。
|
||||
- **HASH JOIN (BROADCAST)**: 通过广播较小的表来连接两个表。
|
||||
- **Fragments**: 每个片段可以在不同的节点上并行执行。
|
||||
|
||||
查询96的查询计划分为五个片段,从0到4编号。查询计划可以自下而上逐一阅读。
|
||||
|
||||
片段4负责扫描 `time_dim` 表并提前执行相关查询条件(即 `time_dim.t_hour = 8 and time_dim.t_minute >= 30`)。这一步也称为谓词下推。StarRocks决定是否为聚合表启用 `PREAGGREGATION`。在前面的图中,`time_dim` 的预聚合被禁用。在这种情况下,`time_dim` 的所有维度列都被读取,如果表中有很多维度列,可能会对性能产生负面影响。如果 `time_dim` 表选择 `range partition` 进行数据划分,查询计划中将命中几个分区,并自动过滤掉不相关的分区。如果存在物化视图,StarRocks将根据查询自动选择物化视图。如果没有物化视图,查询将自动命中基表(例如,前图中的 `rollup: time_dim`)。
|
||||
|
||||
扫描完成后,片段4结束。数据将传递给其他片段,如前图中所示的 EXCHANGE ID : 09,传递到标记为9的接收节点。
|
||||
|
||||
对于查询96的查询计划,片段2、3和4具有相似的功能,但它们负责扫描不同的表。具体来说,查询中的 `Order/Aggregation/Join` 操作在片段1中执行。
|
||||
|
||||
片段1使用 `BROADCAST` 方法执行 `Order/Aggregation/Join` 操作,即将小表广播到大表。如果两个表都很大,我们建议使用 `SHUFFLE` 方法。目前,StarRocks仅支持 `HASH JOIN`。`colocate` 字段用于显示两个连接的表是以相同方式分区和分桶的,因此可以在本地执行连接操作而无需迁移数据。当连接操作完成后,将执行上层的 `aggregation`、`order by` 和 `top-n` 操作。
|
||||
|
||||
通过去除特定表达式(仅保留操作符),查询计划可以以更宏观的视角呈现,如下图所示。
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,427 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 80
|
||||
keywords: ['profile', 'query']
|
||||
---
|
||||
|
||||
# 查询概要指标
|
||||
|
||||
> **StarRocks Query Profile** 发出的原始指标的权威参考,按 operator 分组。
|
||||
> 可用作词汇表;如需故障排除指南,请跳转到 **query_profile_tuning_recipes.md**。
|
||||
|
||||
### 概要指标
|
||||
|
||||
关于查询执行的基本信息:
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| Total | 查询消耗的总时间,包括计划、执行和分析阶段的持续时间。 |
|
||||
| Query State | 查询状态,可能的状态包括 Finished、Error 和 Running。 |
|
||||
| Query ID | 查询的唯一标识符。 |
|
||||
| Start Time | 查询开始的时间戳。 |
|
||||
| End Time | 查询结束的时间戳。 |
|
||||
| Total | 查询的总持续时间。 |
|
||||
| Query Type | 查询的类型。 |
|
||||
| Query State | 查询的当前状态。 |
|
||||
| StarRocks Version | 使用的 StarRocks 版本。 |
|
||||
| User | 执行查询的用户。 |
|
||||
| Default Db | 查询使用的默认数据库。 |
|
||||
| Sql Statement | 执行的 SQL 语句。 |
|
||||
| Variables | 查询中使用的重要变量。 |
|
||||
| NonDefaultSessionVariables | 查询中使用的非默认会话变量。 |
|
||||
| Collect Profile Time | 收集概要所花费的时间。 |
|
||||
| IsProfileAsync | 指示概要收集是否为异步。 |
|
||||
|
||||
### 计划器指标
|
||||
|
||||
提供计划器的全面概述。通常,如果在计划器上花费的总时间少于 10ms,则无需担心。
|
||||
|
||||
在某些情况下,计划器可能需要更多时间:
|
||||
1. 复杂查询可能需要额外的时间进行解析和优化,以确保最佳执行计划。
|
||||
2. 存在大量物化视图时,可能会增加查询重写所需的时间。
|
||||
3. 当多个并发查询耗尽系统资源并使用查询队列时,`Pending` 时间可能会延长。
|
||||
4. 涉及外部表的查询可能会因与外部元数据服务器的通信而增加额外时间。
|
||||
|
||||
示例:
|
||||
```
|
||||
- -- Parser[1] 0
|
||||
- -- Total[1] 3ms
|
||||
- -- Analyzer[1] 0
|
||||
- -- Lock[1] 0
|
||||
- -- AnalyzeDatabase[1] 0
|
||||
- -- AnalyzeTemporaryTable[1] 0
|
||||
- -- AnalyzeTable[1] 0
|
||||
- -- Transformer[1] 0
|
||||
- -- Optimizer[1] 1ms
|
||||
- -- MVPreprocess[1] 0
|
||||
- -- MVTextRewrite[1] 0
|
||||
- -- RuleBaseOptimize[1] 0
|
||||
- -- CostBaseOptimize[1] 0
|
||||
- -- PhysicalRewrite[1] 0
|
||||
- -- DynamicRewrite[1] 0
|
||||
- -- PlanValidate[1] 0
|
||||
- -- InputDependenciesChecker[1] 0
|
||||
- -- TypeChecker[1] 0
|
||||
- -- CTEUniqueChecker[1] 0
|
||||
- -- ColumnReuseChecker[1] 0
|
||||
- -- ExecPlanBuild[1] 0
|
||||
- -- Pending[1] 0
|
||||
- -- Prepare[1] 0
|
||||
- -- Deploy[1] 2ms
|
||||
- -- DeployLockInternalTime[1] 2ms
|
||||
- -- DeploySerializeConcurrencyTime[2] 0
|
||||
- -- DeployStageByStageTime[6] 0
|
||||
- -- DeployWaitTime[6] 1ms
|
||||
- -- DeployAsyncSendTime[2] 0
|
||||
- DeployDataSize: 10916
|
||||
Reason:
|
||||
```
|
||||
|
||||
### 执行概览指标
|
||||
|
||||
高层次的执行统计:
|
||||
|
||||
| 指标 | 描述 | 经验法则 |
|
||||
|--------|-------------|---------------|
|
||||
| FrontendProfileMergeTime | FE 端概要处理时间 | < 10ms 正常 |
|
||||
| QueryAllocatedMemoryUsage | 节点间分配的总内存 | |
|
||||
| QueryDeallocatedMemoryUsage | 节点间释放的总内存 | |
|
||||
| QueryPeakMemoryUsagePerNode | 每个节点的最大内存峰值 | < 80% 容量正常 |
|
||||
| QuerySumMemoryUsage | 节点间的总内存峰值 | |
|
||||
| QueryExecutionWallTime | 执行的墙钟时间 | |
|
||||
| QueryCumulativeCpuTime | 节点间的总 CPU 时间 | 与 `walltime * totalCpuCores` 比较 |
|
||||
| QueryCumulativeOperatorTime | operator 执行的总时间 | operator 时间百分比的分母 |
|
||||
| QueryCumulativeNetworkTime | Exchange 节点的总网络时间 | |
|
||||
| QueryCumulativeScanTime | Scan 节点的总 IO 时间 | |
|
||||
| QueryPeakScheduleTime | 最大 Pipeline 调度时间 | 简单查询 < 1s 正常 |
|
||||
| QuerySpillBytes | 溢出到磁盘的数据 | < 1GB 正常 |
|
||||
|
||||
### Fragment 指标
|
||||
|
||||
Fragment 级别的执行细节:
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| InstanceNum | FragmentInstances 的数量 |
|
||||
| InstanceIds | 所有 FragmentInstances 的 ID |
|
||||
| BackendNum | 参与的 BE 数量 |
|
||||
| BackendAddresses | BE 地址 |
|
||||
| FragmentInstancePrepareTime | Fragment 准备阶段的持续时间 |
|
||||
| InstanceAllocatedMemoryUsage | 实例分配的总内存 |
|
||||
| InstanceDeallocatedMemoryUsage | 实例释放的总内存 |
|
||||
| InstancePeakMemoryUsage | 实例间的内存峰值 |
|
||||
|
||||
### Pipeline 指标
|
||||
|
||||
Pipeline 执行细节和关系:
|
||||
|
||||

|
||||
|
||||
关键关系:
|
||||
- DriverTotalTime = ActiveTime + PendingTime + ScheduleTime
|
||||
- ActiveTime = ∑ OperatorTotalTime + OverheadTime
|
||||
- PendingTime = InputEmptyTime + OutputFullTime + PreconditionBlockTime + PendingFinishTime
|
||||
- InputEmptyTime = FirstInputEmptyTime + FollowupInputEmptyTime
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| DegreeOfParallelism | Pipeline 执行的并行度。 |
|
||||
| TotalDegreeOfParallelism | 并行度的总和。由于同一 Pipeline 可能在多台机器上执行,此项汇总了所有值。 |
|
||||
| DriverPrepareTime | 准备阶段所花费的时间。此指标不包含在 DriverTotalTime 中。 |
|
||||
| DriverTotalTime | Pipeline 的总执行时间,不包括准备阶段所花费的时间。 |
|
||||
| ActiveTime | Pipeline 的执行时间,包括每个 operator 的执行时间和整体框架开销,如调用 has_output、need_input 等方法的时间。 |
|
||||
| PendingTime | Pipeline 因各种原因被阻止调度的时间。 |
|
||||
| InputEmptyTime | Pipeline 因输入队列为空而被阻止的时间。 |
|
||||
| FirstInputEmptyTime | Pipeline 首次因输入队列为空而被阻止的时间。首次阻止时间单独计算,因为首次阻止主要由 Pipeline 依赖关系引起。 |
|
||||
| FollowupInputEmptyTime | Pipeline 随后因输入队列为空而被阻止的时间。 |
|
||||
| OutputFullTime | Pipeline 因输出队列已满而被阻止的时间。 |
|
||||
| PreconditionBlockTime | Pipeline 因未满足的依赖关系而被阻止的时间。 |
|
||||
| PendingFinishTime | Pipeline 因等待异步任务完成而被阻止的时间。 |
|
||||
| ScheduleTime | Pipeline 的调度时间,从进入就绪队列到被调度执行。 |
|
||||
| BlockByInputEmpty | Pipeline 因 InputEmpty 被阻止的次数。 |
|
||||
| BlockByOutputFull | Pipeline 因 OutputFull 被阻止的次数。 |
|
||||
| BlockByPrecondition | Pipeline 因未满足的前提条件而被阻止的次数。 |
|
||||
|
||||
### Operator 指标
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| PrepareTime | 准备所花费的时间。 |
|
||||
| OperatorTotalTime | Operator 消耗的总时间。满足方程:OperatorTotalTime = PullTotalTime + PushTotalTime + SetFinishingTime + SetFinishedTime + CloseTime。排除准备所花费的时间。 |
|
||||
| PullTotalTime | Operator 执行 push_chunk 所花费的总时间。 |
|
||||
| PushTotalTime | Operator 执行 pull_chunk 所花费的总时间。 |
|
||||
| SetFinishingTime | Operator 执行 set_finishing 所花费的总时间。 |
|
||||
| SetFinishedTime | Operator 执行 set_finished 所花费的总时间。 |
|
||||
| PushRowNum | Operator 的输入行数累计。 |
|
||||
| PullRowNum | Operator 的输出行数累计。 |
|
||||
| JoinRuntimeFilterEvaluate | Join Runtime Filter 的评估次数。 |
|
||||
| JoinRuntimeFilterHashTime | 计算 Join Runtime Filter 哈希所花费的时间。 |
|
||||
| JoinRuntimeFilterInputRows | Join Runtime Filter 的输入行数。 |
|
||||
| JoinRuntimeFilterOutputRows | Join Runtime Filter 的输出行数。 |
|
||||
| JoinRuntimeFilterTime | Join Runtime Filter 所花费的时间。 |
|
||||
|
||||
### Scan Operator
|
||||
|
||||
#### OLAP Scan Operator
|
||||
|
||||
OLAP_SCAN Operator 负责从 StarRocks 内表中读取数据。
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| Table | 表名。 |
|
||||
| Rollup | 物化视图名称。如果没有命中物化视图,则等同于表名。 |
|
||||
| SharedScan | 是否启用了 enable_shared_scan 会话变量。 |
|
||||
| TabletCount | tablet 的数量。 |
|
||||
| MorselsCount | morsels 的数量,即基本 IO 执行单元。 |
|
||||
| PushdownPredicates | 下推谓词的数量。 |
|
||||
| Predicates | 谓词表达式。 |
|
||||
| BytesRead | 读取的数据大小。 |
|
||||
| CompressedBytesRead | 从磁盘读取的压缩数据大小。 |
|
||||
| UncompressedBytesRead | 从磁盘读取的解压缩数据大小。 |
|
||||
| RowsRead | 读取的行数(经过谓词过滤后)。 |
|
||||
| RawRowsRead | 读取的原始行数(谓词过滤前)。 |
|
||||
| ReadPagesNum | 读取的页数。 |
|
||||
| CachedPagesNum | 缓存的页数。 |
|
||||
| ChunkBufferCapacity | Chunk Buffer 的容量。 |
|
||||
| DefaultChunkBufferCapacity | Chunk Buffer 的默认容量。 |
|
||||
| PeakChunkBufferMemoryUsage | Chunk Buffer 的内存使用峰值。 |
|
||||
| PeakChunkBufferSize | Chunk Buffer 的大小峰值。 |
|
||||
| PrepareChunkSourceTime | 准备 Chunk Source 所花费的时间。 |
|
||||
| ScanTime | 累计扫描时间。扫描操作在异步 I/O 线程池中完成。 |
|
||||
| IOTaskExecTime | IO 任务的执行时间。 |
|
||||
| IOTaskWaitTime | IO 任务从成功提交到调度执行的等待时间。 |
|
||||
| SubmitTaskCount | IO 任务提交的次数。 |
|
||||
| SubmitTaskTime | 任务提交所花费的时间。 |
|
||||
| PeakIOTasks | IO 任务的峰值数量。 |
|
||||
| PeakScanTaskQueueSize | IO 任务队列的峰值大小。 |
|
||||
|
||||
#### Connector Scan Operator
|
||||
|
||||
类似于 OLAP_SCAN operator,但用于扫描外部表,如 Iceberg/Hive/Hudi/Detal。
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| DataSourceType | 数据源类型,可以是 HiveDataSource、ESDataSource 等。 |
|
||||
| Table | 表名。 |
|
||||
| TabletCount | tablet 的数量。 |
|
||||
| MorselsCount | morsels 的数量。 |
|
||||
| Predicates | 谓词表达式。 |
|
||||
| PredicatesPartition | 应用于分区的谓词表达式。 |
|
||||
| SharedScan | 是否启用了 `enable_shared_scan` 会话变量。 |
|
||||
| ChunkBufferCapacity | Chunk Buffer 的容量。 |
|
||||
| DefaultChunkBufferCapacity | Chunk Buffer 的默认容量。 |
|
||||
| PeakChunkBufferMemoryUsage | Chunk Buffer 的内存使用峰值。 |
|
||||
| PeakChunkBufferSize | Chunk Buffer 的大小峰值。 |
|
||||
| PrepareChunkSourceTime | 准备 Chunk Source 所花费的时间。 |
|
||||
| ScanTime | 累计扫描时间。扫描操作在异步 I/O 线程池中完成。 |
|
||||
| IOTaskExecTime | I/O 任务的执行时间。 |
|
||||
| IOTaskWaitTime | I/O 任务从成功提交到调度执行的等待时间。 |
|
||||
| SubmitTaskCount | I/O 任务提交的次数。 |
|
||||
| SubmitTaskTime | 任务提交所花费的时间。 |
|
||||
| PeakIOTasks | I/O 任务的峰值数量。 |
|
||||
| PeakScanTaskQueueSize | I/O 任务队列的峰值大小。 |
|
||||
|
||||
### Exchange Operator
|
||||
|
||||
Exchange Operator 负责在 BE 节点之间传输数据。可以有几种交换操作:GATHER/BROADCAST/SHUFFLE。
|
||||
|
||||
可能使 Exchange Operator 成为查询瓶颈的典型场景:
|
||||
1. Broadcast Join:这是一种适合小表的方法。然而,在某些情况下,当优化器选择了次优的查询计划时,可能导致网络带宽显著增加。
|
||||
2. Shuffle Aggregation/Join:对大表进行 Shuffle 可能导致网络带宽显著增加。
|
||||
|
||||
#### Exchange Sink Operator
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| ChannelNum | 通道数量。通常,通道数量等于接收者数量。 |
|
||||
| DestFragments | 目标 FragmentInstance ID 列表。 |
|
||||
| DestID | 目标节点 ID。 |
|
||||
| PartType | 数据分布模式,包括:UNPARTITIONED、RANDOM、HASH_PARTITIONED 和 BUCKET_SHUFFLE_HASH_PARTITIONED。 |
|
||||
| SerializeChunkTime | 序列化 chunk 所花费的时间。 |
|
||||
| SerializedBytes | 序列化数据的大小。 |
|
||||
| ShuffleChunkAppendCounter | 当 PartType 为 HASH_PARTITIONED 或 BUCKET_SHUFFLE_HASH_PARTITIONED 时,Chunk Append 操作的次数。 |
|
||||
| ShuffleChunkAppendTime | 当 PartType 为 HASH_PARTITIONED 或 BUCKET_SHUFFLE_HASH_PARTITIONED 时,Chunk Append 操作所花费的时间。 |
|
||||
| ShuffleHashTime | 当 PartType 为 HASH_PARTITIONED 或 BUCKET_SHUFFLE_HASH_PARTITIONED 时,计算哈希所花费的时间。 |
|
||||
| RequestSent | 发送的数据包数量。 |
|
||||
| RequestUnsent | 未发送的数据包数量。当存在短路逻辑时,此指标为非零;否则为零。 |
|
||||
| BytesSent | 发送的数据大小。 |
|
||||
| BytesUnsent | 未发送的数据大小。当存在短路逻辑时,此指标为非零;否则为零。 |
|
||||
| BytesPassThrough | 如果目标节点是当前节点,数据将不会通过网络传输,这称为 passthrough 数据。此指标指示此类 passthrough 数据的大小。Passthrough 由 `enable_exchange_pass_through` 控制。 |
|
||||
| PassThroughBufferPeakMemoryUsage | PassThrough Buffer 的内存使用峰值。 |
|
||||
| CompressTime | 压缩时间。 |
|
||||
| CompressedBytes | 压缩数据的大小。 |
|
||||
| OverallThroughput | 吞吐率。 |
|
||||
| NetworkTime | 数据包传输所花费的时间(不包括接收后的处理时间)。 |
|
||||
| NetworkBandwidth | 估计的网络带宽。 |
|
||||
| WaitTime | 由于发送者队列已满而等待的时间。 |
|
||||
| OverallTime | 整个传输过程的总时间,即从发送第一个数据包到确认最后一个数据包正确接收的时间。 |
|
||||
| RpcAvgTime | RPC 的平均时间。 |
|
||||
| RpcCount | RPC 的总次数。 |
|
||||
|
||||
#### Exchange Source Operator
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| RequestReceived | 接收的数据包大小。 |
|
||||
| BytesReceived | 接收的数据大小。 |
|
||||
| DecompressChunkTime | 解压缩 chunk 所花费的时间。 |
|
||||
| DeserializeChunkTime | 反序列化 chunk 所花费的时间。 |
|
||||
| ClosureBlockCount | 被阻止的 Closure 数量。 |
|
||||
| ClosureBlockTime | Closure 被阻止的时间。 |
|
||||
| ReceiverProcessTotalTime | 接收端处理所花费的总时间。 |
|
||||
| WaitLockTime | 锁等待时间。 |
|
||||
|
||||
### Aggregate Operator
|
||||
|
||||
**指标列表**
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| `GroupingKeys` | `GROUP BY` 列。 |
|
||||
| `AggregateFunctions` | 聚合函数计算所花费的时间。 |
|
||||
| `AggComputeTime` | 聚合函数 + Group By 的时间。 |
|
||||
| `ChunkBufferPeakMem` | Chunk Buffer 的内存使用峰值。 |
|
||||
| `ChunkBufferPeakSize` | Chunk Buffer 的大小峰值。 |
|
||||
| `ExprComputeTime` | 表达式计算的时间。 |
|
||||
| `ExprReleaseTime` | 表达式释放的时间。 |
|
||||
| `GetResultsTime` | 提取聚合结果的时间。 |
|
||||
| `HashTableSize` | 哈希表的大小。 |
|
||||
| `HashTableMemoryUsage` | 哈希表的内存大小。 |
|
||||
| `InputRowCount` | 输入行数。 |
|
||||
| `PassThroughRowCount` | 在自动模式下,低聚合导致降级为流模式后以流模式处理的数据行数。 |
|
||||
| `ResultAggAppendTime` | 追加聚合结果列所花费的时间。 |
|
||||
| `ResultGroupByAppendTime` | 追加 Group By 列所花费的时间。 |
|
||||
| `ResultIteratorTime` | 遍历哈希表的时间。 |
|
||||
| `StreamingTime` | 流模式下的处理时间。 |
|
||||
|
||||
### Join Operator
|
||||
|
||||
**指标列表**
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| `DistributionMode` | 分布类型,包括:BROADCAST、PARTITIONED、COLOCATE 等。 |
|
||||
| `JoinPredicates` | Join 谓词。 |
|
||||
| `JoinType` | Join 类型。 |
|
||||
| `BuildBuckets` | 哈希表中的桶数量。 |
|
||||
| `BuildKeysPerBucket` | 哈希表中每个桶的键数量。 |
|
||||
| `BuildConjunctEvaluateTime` | 构建阶段连接评估所花费的时间。 |
|
||||
| `BuildHashTableTime` | 构建哈希表所花费的时间。 |
|
||||
| `ProbeConjunctEvaluateTime` | 探测阶段连接评估所花费的时间。 |
|
||||
| `SearchHashTableTimer` | 搜索哈希表所花费的时间。 |
|
||||
| `CopyRightTableChunkTime` | 从右表复制 chunk 所花费的时间。 |
|
||||
| `OutputBuildColumnTime` | 输出构建侧列所花费的时间。 |
|
||||
| `OutputProbeColumnTime` | 输出探测侧列所花费的时间。 |
|
||||
| `HashTableMemoryUsage` | 哈希表的内存使用。 |
|
||||
| `RuntimeFilterBuildTime` | 构建运行时过滤器所花费的时间。 |
|
||||
| `RuntimeFilterNum` | 运行时过滤器的数量。 |
|
||||
|
||||
### Window Function Operator
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| `ProcessMode` | 执行模式,包括两个部分:第一部分包括 Materializing 和 Streaming;第二部分包括 Cumulative、RemovableCumulative、ByDefinition。 |
|
||||
| `ComputeTime` | 窗口函数计算所花费的时间。 |
|
||||
| `PartitionKeys` | 分区列。 |
|
||||
| `AggregateFunctions` | 聚合函数。 |
|
||||
| `ColumnResizeTime` | 列调整大小所花费的时间。 |
|
||||
| `PartitionSearchTime` | 搜索分区边界所花费的时间。 |
|
||||
| `PeerGroupSearchTime` | 搜索同级组边界所花费的时间。仅当窗口类型为 `RANGE` 时有意义。 |
|
||||
| `PeakBufferedRows` | 缓冲区中的行数峰值。 |
|
||||
| `RemoveUnusedRowsCount` | 移除未使用缓冲区的次数。 |
|
||||
| `RemoveUnusedTotalRows` | 从未使用缓冲区中移除的总行数。 |
|
||||
|
||||
### Sort Operator
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| `SortKeys` | 排序键。 |
|
||||
| `SortType` | 查询结果的排序方法:全排序或排序前 N 个结果。 |
|
||||
| `MaxBufferedBytes` | 缓冲数据的峰值大小。 |
|
||||
| `MaxBufferedRows` | 缓冲行数的峰值。 |
|
||||
| `NumSortedRuns` | 排序运行的次数。 |
|
||||
| `BuildingTime` | 排序期间维护内部数据结构所花费的时间。 |
|
||||
| `MergingTime` | 排序期间合并排序运行所花费的时间。 |
|
||||
| `SortingTime` | 排序所花费的时间。 |
|
||||
| `OutputTime` | 构建输出排序序列所花费的时间。 |
|
||||
|
||||
### Merge Operator
|
||||
|
||||
| 指标 | 描述 | 级别 |
|
||||
|--------|-------------|-------|
|
||||
| `Limit` | 限制。 | 主要 |
|
||||
| `Offset` | 偏移。 | 主要 |
|
||||
| `StreamingBatchSize` | 当在流模式下执行合并时,每次合并操作处理的数据大小 | 主要 |
|
||||
| `LateMaterializationMaxBufferChunkNum` | 启用延迟物化时缓冲区中的最大 chunk 数量。 | 主要 |
|
||||
| `OverallStageCount` | 所有阶段的总执行次数。 | 主要 |
|
||||
| `OverallStageTime` | 每个阶段的总执行时间。 | 主要 |
|
||||
| `1-InitStageCount` | Init 阶段的执行次数。 | 次要 |
|
||||
| `2-PrepareStageCount` | Prepare 阶段的执行次数。 | 次要 |
|
||||
| `3-ProcessStageCount` | Process 阶段的执行次数。 | 次要 |
|
||||
| `4-SplitChunkStageCount` | SplitChunk 阶段的执行次数。 | 次要 |
|
||||
| `5-FetchChunkStageCount` | FetchChunk 阶段的执行次数。 | 次要 |
|
||||
| `6-PendingStageCount` | Pending 阶段的执行次数。 | 次要 |
|
||||
| `7-FinishedStageCount` | Finished 阶段的执行次数。 | 次要 |
|
||||
| `1-InitStageTime` | Init 阶段的执行时间。 | 次要 |
|
||||
| `2-PrepareStageTime` | Prepare 阶段的执行时间。 | 次要 |
|
||||
| `3-ProcessStageTime` | Process 阶段的执行时间。 | 次要 |
|
||||
| `4-SplitChunkStageTime` | Split 阶段所花费的时间。 | 次要 |
|
||||
| `5-FetchChunkStageTime` | Fetch 阶段所花费的时间。 | 次要 |
|
||||
| `6-PendingStageTime` | Pending 阶段所花费的时间。 | 次要 |
|
||||
| `7-FinishedStageTime` | Finished 阶段所花费的时间。 | 次要 |
|
||||
| `LateMaterializationGenerateOrdinalTime` | 延迟物化期间生成序数列所花费的时间。 | 第三级 |
|
||||
| `SortedRunProviderTime` | 在 Process 阶段从提供者检索数据所花费的时间。 | 第三级 |
|
||||
|
||||
### TableFunction Operator
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| `TableFunctionExecTime` | 表函数的计算时间。 |
|
||||
| `TableFunctionExecCount` | 表函数的执行次数。 |
|
||||
|
||||
### Project Operator
|
||||
|
||||
Project Operator 负责执行 `SELECT <expr>`。如果查询中有一些耗时的表达式,此 operator 可能会花费大量时间。
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| `ExprComputeTime` | 表达式的计算时间。 |
|
||||
| `CommonSubExprComputeTime` | 公共子表达式的计算时间。 |
|
||||
|
||||
### LocalExchange Operator
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| Type | Local Exchange 的类型,包括:`Passthrough`、`Partition` 和 `Broadcast`。 |
|
||||
| `ShuffleNum` | Shuffle 的次数。此指标仅在 `Type` 为 `Partition` 时有效。 |
|
||||
| `LocalExchangePeakMemoryUsage` | 内存使用峰值。 |
|
||||
| `LocalExchangePeakBufferSize` | 缓冲区的大小峰值。 |
|
||||
| `LocalExchangePeakBufferMemoryUsage` | 缓冲区的内存使用峰值。 |
|
||||
| `LocalExchangePeakBufferChunkNum` | 缓冲区中的 chunk 数量峰值。 |
|
||||
| `LocalExchangePeakBufferRowNum` | 缓冲区中的行数峰值。 |
|
||||
| `LocalExchangePeakBufferBytes` | 缓冲区中的数据大小峰值。 |
|
||||
| `LocalExchangePeakBufferChunkSize` | 缓冲区中的 chunk 大小峰值。 |
|
||||
| `LocalExchangePeakBufferChunkRowNum` | 缓冲区中每个 chunk 的行数峰值。 |
|
||||
| `LocalExchangePeakBufferChunkBytes` | 缓冲区中每个 chunk 的数据大小峰值。 |
|
||||
|
||||
### OlapTableSink Operator
|
||||
|
||||
OlapTableSink Operator 负责执行 `INSERT INTO <table>` 操作。
|
||||
|
||||
:::tip
|
||||
- 如果 `OlapTableSink` 的 `PushChunkNum` 指标的最大值和最小值之间差异过大,表明上游 operator 中的数据倾斜,可能导致导入性能瓶颈。
|
||||
- `RpcClientSideTime` 等于 `RpcServerSideTime` 加上网络传输时间和 RPC 框架处理时间。如果 `RpcClientSideTime` 和 `RpcServerSideTime` 之间有显著差异,考虑启用压缩以减少传输时间。
|
||||
:::
|
||||
|
||||
| 指标 | 描述 |
|
||||
|--------|-------------|
|
||||
| `IndexNum` | 为目标表创建的同步物化视图的数量。 |
|
||||
| `ReplicatedStorage` | 是否启用了单领导者复制。 |
|
||||
| `TxnID` | 导入事务的 ID。 |
|
||||
| `RowsRead` | 从上游 operator 读取的行数。 |
|
||||
| `RowsFiltered` | 由于数据质量不足而被过滤掉的行数。 |
|
||||
| `RowsReturned` | 写入目标表的行数。 |
|
||||
| `RpcClientSideTime` | 客户端记录的导入的总 RPC 时间消耗。 |
|
||||
| `RpcServerSideTime` | 服务器端记录的导入的总 RPC 时间消耗。 |
|
||||
| `PrepareDataTime` | 数据准备阶段的总时间消耗,包括数据格式转换和数据质量检查。 |
|
||||
| `SendDataTime` | 发送数据的本地时间消耗,包括序列化和压缩数据的时间,以及将任务提交到发送者队列的时间。 |
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 30
|
||||
keywords: ['profile', 'query']
|
||||
---
|
||||
|
||||
# Query Profile 概述
|
||||
|
||||
## 简介
|
||||
|
||||
Query Profile 记录了查询中所有工作节点的执行信息,帮助您快速识别影响查询性能的瓶颈。它是诊断和调优 StarRocks 查询性能的强大工具。
|
||||
|
||||
> 从 v3.3.0 开始,StarRocks 支持为使用 INSERT INTO FILES() 和 Broker Load 的数据导入提供 Query Profile。有关涉及的指标详情,请参见 [OlapTableSink Operator](./query_profile_operator_metrics.md#olaptablesink-operator)。
|
||||
|
||||
## 如何启用 Query Profile
|
||||
|
||||
### 启用 Query Profile
|
||||
|
||||
您可以通过将变量 `enable_profile` 设置为 `true` 来启用 Query Profile:
|
||||
|
||||
```SQL
|
||||
SET enable_profile = true;
|
||||
SET GLOBAL enable_profile = true;
|
||||
```
|
||||
|
||||
### 慢查询的 Query Profile
|
||||
|
||||
不建议在生产环境中长时间全局启用 Query Profile,因为这可能会增加系统开销。为了仅捕获和分析慢查询,可以将变量 `big_query_profile_threshold` 设置为大于 `0s` 的时间。例如,将其设置为 `30s` 表示只有超过 30 秒的查询才会触发 Query Profile。
|
||||
|
||||
```SQL
|
||||
-- 30 秒
|
||||
SET global big_query_profile_threshold = '30s';
|
||||
|
||||
-- 500 毫秒
|
||||
SET global big_query_profile_threshold = '500ms';
|
||||
|
||||
-- 60 分钟
|
||||
SET global big_query_profile_threshold = '60m';
|
||||
```
|
||||
|
||||
### 运行时 Query Profile
|
||||
|
||||
对于长时间运行的查询,可能难以在完成前确定进度或检测问题。运行时 Query Profile 功能(v3.1+)在执行期间以固定间隔收集并报告 Query Profile 数据,提供关于查询进度和瓶颈的实时洞察。
|
||||
|
||||
当启用 Query Profile 时,运行时 Query Profile 会自动激活,默认报告间隔为 10 秒。可以通过 `runtime_profile_report_interval` 调整间隔:
|
||||
|
||||
```SQL
|
||||
SET runtime_profile_report_interval = 30;
|
||||
```
|
||||
|
||||
### 配置
|
||||
|
||||
| 配置项 | 类型 | 有效值 | 默认值 | 描述 |
|
||||
|----------------------------------|--------------|-----------------|---------|------------------------------------------------------------------------------------------|
|
||||
| enable_profile | Session Var | true/false | false | 启用 Query Profile |
|
||||
| pipeline_profile_level | Session Var | 1/2 | 1 | 1: 合并指标;2: 保留原始结构(禁用可视化工具) |
|
||||
| runtime_profile_report_interval | Session Var | 正整数 | 10 | 运行时 Query Profile 报告间隔(秒) |
|
||||
| big_query_profile_threshold | Session Var | 字符串 | 0s | 启用 Query Profile 的查询超过此持续时间(例如,'30s','500ms','60m') |
|
||||
| enable_statistics_collect_profile| FE Dynamic | true/false | false | 启用与统计信息收集相关的查询的 Query Profile |
|
||||
|
||||
## 如何获取 Query Profile
|
||||
|
||||
### 通过 Web UI
|
||||
|
||||
1. 在浏览器中访问 `http://<fe_ip>:<fe_http_port>`。
|
||||
2. 点击顶部导航中的 **queries**。
|
||||
3. 在 **Finished Queries** 列表中,选择要分析的查询并点击 **Profile** 列中的链接。
|
||||
|
||||

|
||||
|
||||
您将被重定向到所选 Query Profile 的详细页面。
|
||||
|
||||

|
||||
|
||||
### 通过 SQL 函数 (`get_query_profile`)
|
||||
|
||||
示例工作流程:
|
||||
- `last_query_id()`: 返回会话中最近执行的查询的 ID。用于快速检索上一个查询的 profile。
|
||||
- `show profilelist;`: 列出最近的查询及其 ID 和状态。使用此功能找到分析 profile 所需的 `query_id`。
|
||||
- `get_query_profile('<query_id>')`: 返回指定查询的详细执行 profile。用于分析查询的执行方式以及时间或资源的消耗位置。
|
||||
|
||||
```sql
|
||||
-- 启用 profiling 功能。
|
||||
set enable_profile = true;
|
||||
-- 运行一个简单的查询。
|
||||
select 1;
|
||||
-- 获取查询的 query_id。
|
||||
select last_query_id();
|
||||
+--------------------------------------+
|
||||
| last_query_id() |
|
||||
+--------------------------------------+
|
||||
| bd3335ce-8dde-11ee-92e4-3269eb8da7d1 |
|
||||
+--------------------------------------+
|
||||
-- 获取 profile 列表
|
||||
show profilelist;
|
||||
-- 获取查询 profile。
|
||||
select get_query_profile('502f3c04-8f5c-11ee-a41f-b22a2c00f66b')\G
|
||||
```
|
||||
|
||||
### 在托管版本中
|
||||
|
||||
在 StarRocks 托管(企业)环境中,您可以方便地从 Web 控制台的查询历史中直接访问查询 profile。托管 UI 提供了每个查询执行 profile 的直观可视化表示,使您无需手动 SQL 命令即可轻松分析性能和识别瓶颈。
|
||||
|
||||
## 解读 Query Profile
|
||||
|
||||
### Explain Analyze
|
||||
|
||||
大多数用户可能会发现直接分析原始文本具有挑战性。StarRocks 提供了一种 [基于文本的 Query Profile 可视化分析](./query_profile_text_based_analysis.md) 方法,以便更直观地理解。
|
||||
|
||||
### 托管版本
|
||||
|
||||
在 StarRocks 企业版(EE)中,托管版本提供了内置的查询 profile 可视化工具。该工具提供了一个交互式图形界面,与原始文本输出相比,使解释复杂的查询执行细节变得更加容易。
|
||||
|
||||
**可视化工具的主要功能包括:**
|
||||
- **Operator 级别分解:** 以树或图的形式查看执行计划,每个 operator 的指标(时间、行数、内存)清晰显示。
|
||||
- **瓶颈高亮:** 通过颜色编码的指示器快速识别慢速或资源密集的 operator。
|
||||
- **深入分析能力:** 点击任意 operator 查看详细统计信息,包括输入/输出行数、CPU 时间、内存使用等。
|
||||
|
||||
**如何使用:**
|
||||
1. 打开 StarRocks 托管 Web 控制台。
|
||||
2. 导航到 **Query** 或 **Query History** 部分。
|
||||
3. 选择一个查询并点击 **Profile** 或 **Visualize** 按钮。
|
||||
4. 探索可视化的 profile 以分析性能并识别优化机会。
|
||||
|
||||
此可视化工具仅限于托管/企业版,旨在加速复杂工作负载的故障排除和性能调优。
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 60
|
||||
---
|
||||
|
||||
# Explain Analyze
|
||||
|
||||
本文档解释了如何在StarRocks中获取和分析基于文本的Query Profiles。它将帮助您理解查询性能,并找到优化SQL查询的方法。
|
||||
|
||||
## 使用ANALYZE PROFILE分析现有查询的Profiles
|
||||
|
||||
要分析集群中现有(历史或正在运行)查询的基于文本的Profile,您首先需要使用[SHOW PROFILELIST](../../sql-reference/sql-statements/cluster-management/plan_profile/SHOW_PROFILELIST.md)语句获取查询的摘要。此命令列出了所有已成功完成、因错误失败以及仍在运行(超过10秒且尚未完成)的查询。通过此语句,您可以获取用于后续分析的相应Query ID。语法如下:
|
||||
|
||||
```SQL
|
||||
SHOW PROFILELIST [LIMIT <num>];
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```SQL
|
||||
SHOW PROFILELIST;
|
||||
SHOW PROFILELIST LIMIT 5;
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```plaintext
|
||||
+--------------------------------------+---------------------+-------+----------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
| QueryId | StartTime | Time | State | Statement |
|
||||
+--------------------------------------+---------------------+-------+----------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
| a40456b2-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:18 | 21ms | Finished | SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES\n WHERE ROUTINE_TYPE="FUNCTION" AND ROUTINE_SCHEMA = "None" |
|
||||
| a3fc4060-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:17 | 39ms | Finished | select TABLE_NAME, COLUMN_NAME from information_schema.columns\n where table_schema = 'Non ... |
|
||||
| a3f7d38d-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:17 | 15ms | Finished | select connection_id() |
|
||||
| a3efbd3b-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:17 | 16ms | Finished | select connection_id() |
|
||||
| a26ec286-8428-11ee-8d02-6a32f8c68848 | 2023-11-16 10:34:15 | 269ms | Error | EXPLAIN ANALYZE SELECT c_nation, s_nation, year(lo_orderdate) AS year , SUM(lo_revenue) AS revenue FROM lineorder_flat WHERE ... |
|
||||
+--------------------------------------+---------------------+-------+----------+-----------------------------------------------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
一旦您获得了Query ID,就可以使用[ANALYZE PROFILE](../../sql-reference/sql-statements/cluster-management/plan_profile/ANALYZE_PROFILE.md)语句进行Query Profile分析。语法如下:
|
||||
|
||||
```SQL
|
||||
ANALYZE PROFILE FROM '<Query_ID>' [, <Node_ID> [, ...] ]
|
||||
```
|
||||
|
||||
- `Query_ID`:通过`SHOW PROFILELIST`语句获得的查询对应的ID。
|
||||
- `Node_ID`:Profile节点ID。对于指定ID的节点,StarRocks返回这些节点的详细度量信息。对于未指定ID的节点,StarRocks仅返回摘要信息。
|
||||
|
||||
Profile包括以下部分:
|
||||
|
||||
- Summary:Profile的摘要信息。
|
||||
- QueryID
|
||||
- 版本信息
|
||||
- 查询状态,包括`Finished`、`Error`和`Running`。
|
||||
- 总查询时间。
|
||||
- 内存使用情况
|
||||
- CPU使用率最高的前10个节点。
|
||||
- 内存使用率最高的前10个节点。
|
||||
- 与默认值不同的会话变量。
|
||||
- Fragments:显示每个Fragment中每个节点的度量。
|
||||
- 每个节点的时间、内存使用、成本估算信息和输出行数。
|
||||
- 时间使用百分比超过30%的节点以红色突出显示。
|
||||
- 时间使用百分比超过15%且小于30%的节点以粉色突出显示。
|
||||
|
||||
示例1:查询不指定节点ID的Query Profile。
|
||||
|
||||

|
||||
|
||||
示例2:查询指定节点ID为`0`的Query Profile。StarRocks返回节点ID `0`的所有详细度量,并突出显示高使用率的度量以便于问题识别。
|
||||
|
||||

|
||||
|
||||
此外,上述方法还支持运行时Query Profile的显示和分析,即为正在运行的查询生成的Profile。当启用Query Profile功能时,您可以使用此方法获取运行超过10秒的查询的Profile。
|
||||
|
||||
与已完成查询的相比,正在运行查询的基于文本的Query Profile包含以下信息:
|
||||
|
||||
- Operator状态:
|
||||
- ⏳:尚未启动的Operators。这些Operators可能由于依赖关系尚未开始执行。
|
||||
- 🚀:正在运行的Operators。
|
||||
- ✅:已完成执行的Operators。
|
||||
|
||||
- 总体进度:基于`已完成执行的Operators数量/总Operators数量`计算。由于缺乏数据行的详细信息,此值可能略有失真。
|
||||
|
||||
- Operator进度:基于`已处理行数/总行数`计算。如果无法计算总行数,进度显示为`?`。
|
||||
|
||||
示例:
|
||||
|
||||

|
||||
|
||||
## 使用EXPLAIN ANALYZE模拟查询进行Profile分析
|
||||
|
||||
StarRocks提供了[EXPLAIN ANALYZE](../../sql-reference/sql-statements/cluster-management/plan_profile/EXPLAIN_ANALYZE.md)语句,允许您直接模拟和分析查询的Profile。语法如下:
|
||||
|
||||
```SQL
|
||||
EXPLAIN ANALYZE <sql_statement>
|
||||
```
|
||||
|
||||
执行`EXPLAIN ANALYZE`时,StarRocks默认会为当前会话启用Query Profile功能。
|
||||
|
||||
目前,`EXPLAIN ANALYZE`支持两种类型的SQL语句:SELECT语句和INSERT INTO语句。您只能在StarRocks的default catalog中的内部表上模拟和分析INSERT INTO语句的Query Profile。请注意,在模拟和分析INSERT INTO语句的Query Profile时,不会实际加载数据。默认情况下,导入事务将被中止,以确保在分析过程中不会对数据进行意外更改。
|
||||
|
||||
示例1:模拟和分析SELECT语句。查询结果将被丢弃。
|
||||
|
||||

|
||||
|
||||
示例2:模拟和分析INSERT INTO语句。加载事务将被中止。
|
||||
|
||||

|
||||
|
||||
## 限制
|
||||
|
||||
- `EXPLAIN ANALYZE INSERT INTO`语句仅支持default catalog中的表。
|
||||
- 为了获得更好的视觉效果,输出文本包含ANSI字符以提供颜色、高亮和其他功能。建议使用MyCLI客户端。对于不支持ANSI功能的客户端,如MySQL客户端,可能会有一些轻微的显示错乱。通常,它们不会影响使用。例如:
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,192 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 40
|
||||
keywords: ['profile', 'query']
|
||||
---
|
||||
|
||||
# 查询优化方案
|
||||
|
||||
> 一个实用的操作手册:**症状 → 根本原因 → 经过验证的解决方案**。
|
||||
> 当你打开一个 profile 并发现一个警示指标,但仍需回答“_接下来怎么办?_”时使用。
|
||||
|
||||
---
|
||||
|
||||
## 1 · 快速诊断流程
|
||||
|
||||
1. **浏览执行概览**
|
||||
如果 `QueryPeakMemoryUsagePerNode > 80 %` 或 `QuerySpillBytes > 1 GB`,直接跳到内存和溢出方案。
|
||||
|
||||
2. **找到最慢的 Pipeline / Operator**
|
||||
⟶ 在 *Query Profile UI* 中点击 **Sort by OperatorTotalTime %**。
|
||||
最热的 operator 告诉你接下来要阅读哪个方案块(Scan, Join, Aggregate, …)。
|
||||
|
||||
3. **确认瓶颈子类型**
|
||||
每个方案以其*特征*指标模式开始。在尝试解决方案之前匹配这些模式。
|
||||
|
||||
---
|
||||
|
||||
## 2 · 按 Operator 分类的方案
|
||||
|
||||
### 2.1 OLAP / Connector Scan [[metrics]](./query_profile_operator_metrics.md#scan-operator)
|
||||
|
||||
为了更好地理解 Scan Operator 中的各种指标,以下图示展示了这些指标与存储结构之间的关联。
|
||||
|
||||

|
||||
|
||||
为了从磁盘检索数据并应用谓词,存储引擎使用了几种技术:
|
||||
1. **数据存储**:编码和压缩的数据以段的形式存储在磁盘上,并附带各种索引。
|
||||
2. **索引过滤**:引擎利用 BitmapIndex、BloomfilterIndex、ZonemapIndex、ShortKeyIndex 和 NGramIndex 等索引来跳过不必要的数据。
|
||||
3. **下推谓词**:简单的谓词,如 `a > 1`,被下推到特定列进行评估。
|
||||
4. **延迟物化**:仅从磁盘中检索所需的列和过滤后的行。
|
||||
5. **非下推谓词**:无法下推的谓词会被评估。
|
||||
6. **投影表达式**:计算诸如 `SELECT a + 1` 的表达式。
|
||||
|
||||
Scan Operator 使用一个额外的线程池来执行 IO 任务。因此,该节点的时间指标关系如下图所示:
|
||||
|
||||

|
||||
|
||||
#### 常见性能瓶颈
|
||||
|
||||
**冷或慢存储** – 当 `BytesRead`、`ScanTime` 或 `IOTaskExecTime` 占主导地位且磁盘 I/O 徘徊在 80-100% 时,扫描正在命中冷或配置不足的存储。将热数据移动到 NVMe/SSD,启用存储缓存,或者如果你正在扫描 S3/HDFS,提高 `remote_cache_capacity`。
|
||||
|
||||
**缺少过滤下推** – 如果 `PushdownPredicates` 接近 0 而 `ExprFilterRows` 很高,谓词没有到达存储层。将它们重写为简单比较(避免 `%LIKE%` 和宽 `OR` 链)或添加 zonemap/Bloom 索引或物化视图以便下推。
|
||||
|
||||
**线程池饥饿** – 高 `IOTaskWaitTime` 以及低 `PeakIOTasks` 表明 I/O 线程池已饱和。增加 BE 上的 `max_io_threads` 或扩大缓存以让更多任务并行运行。
|
||||
|
||||
**tablet 数据倾斜** – 最大和最小 `OperatorTotalTime` 之间的巨大差距意味着某些 tablets 的工作量比其他的多。重新分桶到更高基数的键或增加桶数以分散负载。
|
||||
|
||||
**Rowset/segment 碎片化** – 爆炸性的 `RowsetsReadCount`/`SegmentsReadCount` 加上长时间的 `SegmentInitTime` 表示有许多小的 rowsets。触发手动 compaction 并批量小型导入以便段提前合并。
|
||||
|
||||
**累积的软删除** – 大量的 `DeleteFilterRows` 表示大量使用软删除。运行 BE compaction 以清除墓碑并合并删除位图。
|
||||
|
||||
### 2.2 聚合 [[metrics]](./query_profile_operator_metrics.md#aggregate-operator)
|
||||
|
||||

|
||||
Aggregate Operator 负责执行聚合函数、`GROUP BY` 和 `DISTINCT`。
|
||||
|
||||
**多种形式的聚合算法**
|
||||
|
||||
| 形式 | 规划器选择的条件 | 内部数据结构 | 亮点 / 注意事项 |
|
||||
|------|-----------------|--------------|-----------------|
|
||||
| 哈希聚合 | 键适合内存;基数不极端 | 使用 SIMD 探测的紧凑哈希表 | 默认路径,非常适合适中键数 |
|
||||
| 排序聚合 | 输入已经按 GROUP BY 键排序 | 简单的行比较 + 运行状态 | 零哈希表成本,通常在探测重偏斜时快 2-3 倍 |
|
||||
| 可溢出聚合 (3.2+) | 哈希表超出内存限制 | 混合哈希/合并与磁盘溢出分区 | 防止 OOM,保持管道并行度 |
|
||||
|
||||
**多阶段分布式聚合**
|
||||
|
||||
在 StarRocks 中,聚合以分布式方式实现,具体取决于查询模式和优化器的决策,可以是多阶段的。
|
||||
|
||||
```
|
||||
┌─────────┐ ┌──────────┐ ┌────────────┐ ┌────────────┐
|
||||
│ Stage 0 │ local │ Stage 1 │ shard/ │ Stage 2 │ gather/│ Stage 3 │ final
|
||||
│ Partial │───► │ Update │ hash │ Merge │ shard │ Finalize │ output
|
||||
└─────────┘ └──────────┘ └────────────┘ └────────────┘
|
||||
```
|
||||
|
||||
| 阶段 | 使用条件 | 发生了什么 |
|
||||
|------|----------|------------|
|
||||
| 单阶段 | `DISTRIBUTED BY` 是 `GROUP BY` 的子集,分区是共置的 | 部分聚合立即成为最终结果。 |
|
||||
| 两阶段(本地 + 全局) | 典型的分布式 `GROUP BY` | Stage 0 在每个 BE 内部自适应地折叠重复项;Stage 1 基于 `GROUP BY` 洗牌数据然后执行全局聚合 |
|
||||
| 三阶段(本地 + 洗牌 + 最终) | 重 `DISTINCT` 和高基数 `GROUP BY` | Stage 0 如上;Stage 1 按 `GROUP BY` 洗牌,然后按 `GROUP BY` 和 `DISTINCT` 聚合;Stage 2 合并部分状态为 `GROUP BY` |
|
||||
| 四阶段(本地 + 部分 + 中间 + 最终) | 重 `DISTINCT` 和低基数 `GROUP BY` | 引入额外阶段按 `GROUP BY` 和 `DISTINCT` 洗牌以避免单点瓶颈 |
|
||||
|
||||
#### 常见性能瓶颈
|
||||
|
||||
**高基数 GROUP BY** – 当 `HashTableSize` 或 `HashTableMemoryUsage` 膨胀到内存限制时,分组键太宽或太独特。启用排序流聚合(`enable_streaming_preaggregation = true`),创建汇总物化视图,或将宽字符串键转换为 `INT`。
|
||||
|
||||
**洗牌倾斜** – 各片段之间 `HashTableSize` 或 `InputRowCount` 的巨大差异揭示了不平衡的洗牌。向键添加盐列或使用 `DISTINCT [skew]` 提示以便行均匀分布。
|
||||
|
||||
**状态重的聚合函数** – 如果 `AggregateFunctions` 主导运行时间且函数包括 `HLL_`、`BITMAP_` 或 `COUNT(DISTINCT)`,则巨大的状态对象正在被移动。在导入期间预计算 HLL/bitmap 草图或切换到近似变体。
|
||||
|
||||
**部分聚合降级** – 巨大的 `InputRowCount` 和适中的 `AggComputeTime`,加上上游 EXCHANGE 中巨大的 `BytesSent`,意味着预聚合被绕过。通过 `SET streaming_preaggregation_mode = "force_preaggregation"` 强制重新启用。
|
||||
|
||||
**昂贵的键表达式** – 当 `ExprComputeTime` 与 `AggComputeTime` 相当时,GROUP BY 键是逐行计算的。在子查询中物化这些表达式或将它们提升为生成列。
|
||||
|
||||
### 2.3 Join [[metrics]](./query_profile_operator_metrics.md#join-operator)
|
||||
|
||||

|
||||
|
||||
Join Operator 负责实现显式连接或隐式连接。
|
||||
|
||||
在执行过程中,join operator 被分为构建(哈希表构建)和探测阶段,这些阶段在管道引擎中并行运行。向量块(最多 4096 行)使用 SIMD 批量哈希;消耗的键生成运行时过滤器——Bloom 或 IN 过滤器——被推回上游扫描以提前减少探测输入。
|
||||
|
||||
**Join 策略**
|
||||
|
||||
StarRocks 依赖于一个向量化的、管道友好的哈希连接核心,可以连接到四种物理策略中,成本优化器在计划时会权衡这些策略:
|
||||
|
||||
| 策略 | 优化器选择的条件 | 使其快速的原因 |
|
||||
|------|-----------------|----------------|
|
||||
| Colocate Join | 两个表属于同一个共置组(相同的桶键、桶数和副本布局)。 | 无网络洗牌:每个 BE 仅连接其本地桶。 |
|
||||
| Bucket-Shuffle Join | 其中一个连接表具有与连接键相同的桶键 | 只需洗牌一个连接表,可以减少网络成本 |
|
||||
| Broadcast Join | 构建端非常小(行/字节阈值或显式提示)。 | 小表被复制到每个探测节点;避免洗牌大表。 |
|
||||
| Shuffle (Hash) Join | 一般情况,键不对齐。 | 在连接键上对每行进行哈希分区,以便探测在 BEs 之间均衡分布。 |
|
||||
|
||||
#### 常见性能瓶颈
|
||||
|
||||
**构建端过大** – `BuildHashTableTime` 和 `HashTableMemoryUsage` 的峰值显示构建端已超出内存。交换探测/构建表,预过滤构建表,或启用哈希溢出。
|
||||
|
||||
**缓存不友好的探测** – 当 `SearchHashTableTime` 占主导地位时,探测端不是缓存高效的。对探测行按连接键排序并启用运行时过滤器。
|
||||
|
||||
**洗牌倾斜** – 如果单个片段的 `ProbeRows` 远超其他片段,数据是倾斜的。切换到更高基数的键或附加盐,如 `key || mod(id, 16)`。
|
||||
|
||||
**意外广播** – 连接类型 **BROADCAST** 伴随巨大的 `BytesSent` 意味着你认为小的表并不小。降低 `broadcast_row_limit` 或使用 `SHUFFLE` 提示强制洗牌。
|
||||
|
||||
**缺少运行时过滤器** – 微小的 `JoinRuntimeFilterEvaluate` 以及全表扫描表明运行时过滤器从未传播。将连接重写为纯等式并确保列类型对齐。
|
||||
|
||||
**非等式回退** – 当 operator 类型是 `CROSS` 或 `NESTLOOP` 时,不等式或函数阻止了哈希连接。添加一个真正的等式谓词或预过滤较大的表。
|
||||
|
||||
### 2.4 Exchange (网络) [[metrics]](./query_profile_operator_metrics.md#exchange-operator)
|
||||
|
||||
**过大的洗牌或广播** – 如果 `NetworkTime` 超过 30% 且 `BytesSent` 很大,查询正在传输过多的数据。重新评估连接策略或启用 exchange compaction(`pipeline_enable_exchange_compaction`)。
|
||||
|
||||
**接收器积压** – 接收器无法跟上时,接收器的高 `WaitTime` 以及发送者队列始终满。增加接收器线程池(`brpc_num_threads`)并确认 NIC 带宽和 QoS 设置。
|
||||
|
||||
### 2.5 排序 / 合并 / 窗口
|
||||
|
||||
为了便于理解各种指标,合并可以表示为以下状态机制:
|
||||
|
||||
```plaintext
|
||||
┌────────── PENDING ◄──────────┐
|
||||
│ │
|
||||
│ │
|
||||
├──────────────◄───────────────┤
|
||||
│ │
|
||||
▼ │
|
||||
INIT ──► PREPARE ──► SPLIT_CHUNK ──► FETCH_CHUNK ──► FINISHED
|
||||
▲
|
||||
|
|
||||
| one traverse from leaf to root
|
||||
|
|
||||
▼
|
||||
PROCESS
|
||||
```
|
||||
|
||||
**排序溢出** – 当 `MaxBufferedBytes` 上升到大约 2 GB 以上或 `SpillBytes` 非零时,排序阶段正在溢出到磁盘。添加 `LIMIT`,在上游预聚合,或如果机器有足够的内存,提高 `sort_spill_threshold`。
|
||||
|
||||
**合并饥饿** – 高 `PendingStageTime` 表示合并正在等待上游块。首先优化生产者 operator 或扩大管道缓冲区。
|
||||
|
||||
**宽窗口分区** – 窗口 operator 内巨大的 `PeakBufferedRows` 指向非常宽的分区或缺少帧限制的 ORDER BY。更细粒度地分区,添加 `RANGE BETWEEN` 边界,或物化中间聚合。
|
||||
|
||||
---
|
||||
|
||||
## 3 · 内存和溢出速查表
|
||||
|
||||
| 阈值 | 关注点 | 实际行动 |
|
||||
| --- | --- | --- |
|
||||
| **80 %** 的 BE 内存 | `QueryPeakMemoryUsagePerNode` | 降低会话 `exec_mem_limit` 或增加 BE 内存 |
|
||||
| 检测到溢出(`SpillBytes` > 0) | `QuerySpillBytes`,每个 operator 的 `SpillBlocks` | 增加内存限制;升级到 SR 3.2+ 以获得混合哈希/合并溢出 |
|
||||
|
||||
---
|
||||
|
||||
## 4 · 事后分析模板
|
||||
|
||||
```text
|
||||
1. 症状
|
||||
– 慢阶段:Aggregate (OperatorTotalTime 68 %)
|
||||
– 红旗:HashTableMemoryUsage 9 GB (> exec_mem_limit)
|
||||
2. 根本原因
|
||||
– GROUP BY 高基数 UUID
|
||||
3. 应用的修复
|
||||
– 添加排序流聚合 + 汇总 MV
|
||||
4. 结果
|
||||
– 查询运行时间从 95 s 降至 8 s;内存峰值 0.7 GB```
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
sidebar_position: 50
|
||||
---
|
||||
|
||||
# Schema Tuning Recipes
|
||||
|
||||
本文档提供了通过有效的模式设计和基础表选择来优化 StarRocks 查询性能的实用技巧和最佳实践。通过了解不同表模型、键和分布策略如何影响查询执行,您可以显著提高速度和资源效率。使用这些指南在设计模式、选择表模型以及调整 StarRocks 环境以实现高性能分析时做出明智决策。
|
||||
|
||||
## 表模型选择
|
||||
|
||||
StarRocks 支持四种表模型:明细表、聚合表、更新表和主键表。所有这些表都是按键排序的。
|
||||
|
||||
- `AGGREGATE KEY`:当具有相同 AGGREGATE KEY 的记录导入到 StarRocks 时,新旧记录会被聚合。目前,聚合表支持以下聚合函数:SUM、MIN、MAX 和 REPLACE。聚合表支持提前聚合数据,方便业务报表和多维分析。
|
||||
- `DUPLICATE KEY`:对于明细表,您只需指定排序键。具有相同 DUPLICATE KEY 的记录可以同时存在。适用于不涉及提前聚合数据的分析。
|
||||
- `UNIQUE KEY`:当具有相同 UNIQUE KEY 的记录导入到 StarRocks 时,新记录会覆盖旧记录。更新表类似于具有 REPLACE 函数的聚合表。两者都适用于涉及持续更新的分析。
|
||||
- `PRIMARY KEY`:主键表保证记录的唯一性,并允许您进行实时更新。
|
||||
|
||||
```sql
|
||||
CREATE TABLE site_visit
|
||||
(
|
||||
siteid INT,
|
||||
city SMALLINT,
|
||||
username VARCHAR(32),
|
||||
pv BIGINT SUM DEFAULT '0'
|
||||
)
|
||||
AGGREGATE KEY(siteid, city, username)
|
||||
DISTRIBUTED BY HASH(siteid);
|
||||
|
||||
|
||||
CREATE TABLE session_data
|
||||
(
|
||||
visitorid SMALLINT,
|
||||
sessionid BIGINT,
|
||||
visittime DATETIME,
|
||||
city CHAR(20),
|
||||
province CHAR(20),
|
||||
ip varchar(32),
|
||||
browser CHAR(20),
|
||||
url VARCHAR(1024)
|
||||
)
|
||||
DUPLICATE KEY(visitorid, sessionid)
|
||||
DISTRIBUTED BY HASH(sessionid, visitorid);
|
||||
|
||||
CREATE TABLE sales_order
|
||||
(
|
||||
orderid BIGINT,
|
||||
status TINYINT,
|
||||
username VARCHAR(32),
|
||||
amount BIGINT DEFAULT '0'
|
||||
)
|
||||
UNIQUE KEY(orderid)
|
||||
DISTRIBUTED BY HASH(orderid);
|
||||
|
||||
CREATE TABLE sales_order
|
||||
(
|
||||
orderid BIGINT,
|
||||
status TINYINT,
|
||||
username VARCHAR(32),
|
||||
amount BIGINT DEFAULT '0'
|
||||
)
|
||||
PRIMARY KEY(orderid)
|
||||
DISTRIBUTED BY HASH(orderid);
|
||||
```
|
||||
|
||||
## Colocate Table
|
||||
|
||||
为了加快查询速度,具有相同分布的表可以使用公共分桶列。在这种情况下,数据可以在本地进行连接,而无需在 `join` 操作期间在集群间传输。
|
||||
|
||||
```sql
|
||||
CREATE TABLE colocate_table
|
||||
(
|
||||
visitorid SMALLINT,
|
||||
sessionid BIGINT,
|
||||
visittime DATETIME,
|
||||
city CHAR(20),
|
||||
province CHAR(20),
|
||||
ip varchar(32),
|
||||
browser CHAR(20),
|
||||
url VARCHAR(1024)
|
||||
)
|
||||
DUPLICATE KEY(visitorid, sessionid)
|
||||
DISTRIBUTED BY HASH(sessionid, visitorid)
|
||||
PROPERTIES(
|
||||
"colocate_with" = "group1"
|
||||
);
|
||||
```
|
||||
|
||||
有关 colocate join 和副本管理的更多信息,请参见 [Colocate join](../../using_starrocks/Colocate_join.md)
|
||||
|
||||
## 扁平表和星形模型
|
||||
|
||||
StarRocks 支持星形模型,这比扁平表在建模上更灵活。您可以在建模时创建视图以替换扁平表,然后从多个表中查询数据以加速查询。
|
||||
|
||||
扁平表有以下缺点:
|
||||
|
||||
- 维度更新成本高,因为扁平表通常包含大量维度。每次更新维度时,整个表都必须更新。随着更新频率的增加,情况会变得更糟。
|
||||
- 维护成本高,因为扁平表需要额外的开发工作量、存储空间和数据回填操作。
|
||||
- 数据摄取成本高,因为扁平表有很多字段,而聚合表可能包含更多的键字段。在数据导入期间,需要对更多字段进行排序,这会延长数据导入时间。
|
||||
|
||||
如果您对查询并发性或低延迟有较高要求,您仍然可以使用扁平表。
|
||||
|
||||
## 分区和分桶
|
||||
|
||||
StarRocks 支持两级分区:第一级是 RANGE 分区,第二级是 HASH 分桶。
|
||||
|
||||
- RANGE 分区:RANGE 分区用于将数据划分为不同的区间(可以理解为将原始表划分为多个子表)。大多数用户选择按时间设置分区,这具有以下优点:
|
||||
|
||||
- 更容易区分冷热数据
|
||||
- 能够利用 StarRocks 分级存储(SSD + SATA)
|
||||
- 可以更快地按分区删除数据
|
||||
|
||||
- HASH 分桶:根据哈希值将数据划分为不同的桶。
|
||||
|
||||
- 建议使用高区分度的列进行分桶,以避免数据倾斜。
|
||||
- 为了便于数据恢复,建议保持每个桶中压缩数据的大小在 100 MB 到 1 GB 之间。建议您在创建表或添加分区时配置适当的桶数量。
|
||||
- 不推荐随机分桶。创建表时必须显式指定 HASH 分桶列。
|
||||
|
||||
## 稀疏索引和 bloomfilter 索引
|
||||
|
||||
StarRocks 以有序方式存储数据,并以 1024 行的粒度构建稀疏索引。
|
||||
|
||||
StarRocks 在模式中选择固定长度的前缀(目前为 36 字节)作为稀疏索引。
|
||||
|
||||
创建表时,建议将常用的过滤字段放在模式声明的开头。区分度最高和查询频率最高的字段必须放在最前面。
|
||||
|
||||
VARCHAR 字段必须放在稀疏索引的末尾,因为索引从 VARCHAR 字段开始截断。如果 VARCHAR 字段出现在最前面,索引可能小于 36 字节。
|
||||
|
||||
以上述 `site_visit` 表为例。该表有四列:`siteid, city, username, pv`。排序键包含三列 `siteid, city, username`,分别占用 4、2 和 32 字节。因此,前缀索引(稀疏索引)可以是 `siteid + city + username` 的前 30 字节。
|
||||
|
||||
除了稀疏索引,StarRocks 还提供 bloomfilter 索引,这对于过滤高区分度的列非常有效。如果您希望将 VARCHAR 字段放在其他字段之前,可以创建 bloomfilter 索引。
|
||||
|
||||
## 倒排索引
|
||||
|
||||
StarRocks 采用 Bitmap 索引技术来支持倒排索引,可以应用于明细表的所有列以及聚合表和更新表的键列。Bitmap 索引适用于值范围较小的列,如性别、城市和省份。随着范围的扩大,bitmap 索引也会相应扩大。
|
||||
|
||||
## 物化视图(rollup)
|
||||
|
||||
Rollup 本质上是原始表(基表)的物化索引。创建 rollup 时,只能选择基表的一些列作为模式,并且模式中字段的顺序可以与基表不同。以下是使用 rollup 的一些用例:
|
||||
|
||||
- 基表中的数据聚合度不高,因为基表具有高区分度的字段。在这种情况下,您可以考虑选择一些列来创建 rollup。以上述 `site_visit` 表为例:
|
||||
|
||||
```sql
|
||||
site_visit(siteid, city, username, pv)
|
||||
```
|
||||
|
||||
`siteid` 可能导致数据聚合效果不佳。如果您需要频繁按城市计算 PV,可以创建仅包含 `city` 和 `pv` 的 rollup。
|
||||
|
||||
```sql
|
||||
ALTER TABLE site_visit ADD ROLLUP rollup_city(city, pv);
|
||||
```
|
||||
|
||||
- 基表中的前缀索引无法命中,因为基表的构建方式无法覆盖所有查询模式。在这种情况下,您可以考虑创建 rollup 来调整列顺序。以上述 `session_data` 表为例:
|
||||
|
||||
```sql
|
||||
session_data(visitorid, sessionid, visittime, city, province, ip, browser, url)
|
||||
```
|
||||
|
||||
如果有需要按 `browser` 和 `province` 进行访问分析的情况,您可以创建一个单独的 rollup:
|
||||
|
||||
```sql
|
||||
ALTER TABLE session_data
|
||||
ADD ROLLUP rollup_browser(browser,province,ip,url)
|
||||
DUPLICATE KEY(browser,province);
|
||||
```
|
||||
|
||||
## 模式变更
|
||||
|
||||
在 StarRocks 中有三种方式更改模式:排序模式变更、直接模式变更和链接模式变更。
|
||||
|
||||
- 排序模式变更:更改列的排序并重新排序数据。例如,在排序模式中删除列会导致数据重新排序。
|
||||
|
||||
`ALTER TABLE site_visit DROP COLUMN city;`
|
||||
|
||||
- 直接模式变更:转换数据而不是重新排序数据,例如更改列类型或将列添加到稀疏索引。
|
||||
|
||||
`ALTER TABLE site_visit MODIFY COLUMN username varchar(64);`
|
||||
|
||||
- 链接模式变更:无需转换数据即可完成更改,例如添加列。
|
||||
|
||||
`ALTER TABLE site_visit ADD COLUMN click bigint SUM default '0';`
|
||||
|
||||
建议在创建表时选择适当的模式以加速模式变更。
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
displayed_sidebar: docs
|
||||
---
|
||||
|
||||
# 性能调优
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
||||
<DocCardList />
|
||||
|
|
@ -24,7 +24,7 @@ get_query_profile(x)
|
|||
|
||||
## 返回值说明
|
||||
|
||||
Query Profile 一般包含以下字段,详情可参见 [查看分析 Query Profile](../../../administration/query_profile_overview.md)。
|
||||
Query Profile 一般包含以下字段,详情可参见 [查看分析 Query Profile](../../../best_practices/query_tuning/query_profile_overview.md)。
|
||||
|
||||
```SQL
|
||||
Query:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ displayed_sidebar: docs
|
|||
|
||||
## 功能
|
||||
|
||||
以 Fragment 为单位分析指定 Query Profile,并以树形结构展示。更多信息,参考 [Query Profile 概述](../../../../administration/query_profile_overview.md)。
|
||||
以 Fragment 为单位分析指定 Query Profile,并以树形结构展示。更多信息,参考 [Query Profile 概述](../../../../best_practices/query_tuning/query_profile_overview.md)。
|
||||
|
||||
此功能自 v3.1 起支持。
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ displayed_sidebar: docs
|
|||
|
||||
## 功能
|
||||
|
||||
显示输入查询语句的逻辑或物理执行计划。关于如何分析查询计划,请参考 [分析 Query Plan](../../../../administration/Query_planning.md#分析-query-plan)。
|
||||
显示输入查询语句的逻辑或物理执行计划。关于如何分析查询计划,请参考 [分析 Query Plan](../../../../best_practices/query_tuning/query_planning.md#分析-query-plan)。
|
||||
|
||||
:::tip
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ displayed_sidebar: docs
|
|||
|
||||
## 功能
|
||||
|
||||
执行指定 SQL,并显示相应的 Query Profile 文件。更多信息,参考 [Query Profile 概述](../../../../administration/query_profile_overview.md)。
|
||||
执行指定 SQL,并显示相应的 Query Profile 文件。更多信息,参考 [Query Profile 概述](../../../../best_practices/query_tuning/query_profile_overview.md)。
|
||||
|
||||
此功能自 v3.1 起支持。
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ displayed_sidebar: docs
|
|||
|
||||
## 功能
|
||||
|
||||
列出 StarRocks 集群中缓存的 Query Profile 记录。更多信息,参考 [Query Profile 概述](../../../../administration/query_profile_overview.md)。
|
||||
列出 StarRocks 集群中缓存的 Query Profile 记录。更多信息,参考 [Query Profile 概述](../../../../best_practices/query_tuning/query_profile_overview.md)。
|
||||
|
||||
此功能自 v3.1 起支持。
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ SELECT select_expr[, select_expr ...]
|
|||
> - 从 v3.1 开始,每个同步物化视图支持为基表的每一列使用多个聚合函数,支持形如 `select b, sum(a), min(a) from table group by b` 形式的查询语句。
|
||||
> - 从 v3.1 开始,同步物化视图支持 SELECT 和聚合函数的复杂表达式,即形如 `select b, sum(a + 1) as sum_a1, min(cast (a as bigint)) as min_a from table group by b` 或 `select abs(b) as col1, a + 1 as col2, cast(a as bigint) as col3 from table` 的查询语句。同步物化视图的复杂表达式有以下限制:
|
||||
> - 每个复杂表达式必须有一个列名,并且基表所有同步物化视图中的不同复杂表达式的别名必须不同。例如,查询语句 `select b, sum(a + 1) as sum_a from table group by b` 和`select b, sum(a) as sum_a from table group by b` 不能同时用于为相同的基表创建同步物化视图,你可以为同一复杂表达式设置多个不同别名。
|
||||
> - 您可以通过执行 `EXPLAIN <sql_statement>` 来查看您的查询是否被使用复杂表达式创建的同步物化视图改写。更多信息请参见[查询分析](../../../administration/Query_planning.md)。
|
||||
> - 您可以通过执行 `EXPLAIN <sql_statement>` 来查看您的查询是否被使用复杂表达式创建的同步物化视图改写。更多信息请参见[查询分析](../../../best_practices/query_tuning/query_planning.md)。
|
||||
|
||||
- WHERE (选填)
|
||||
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ DROP INDEX index_name ON [db_name.]table_name;
|
|||
|
||||
### 查看查询是否命中了 Bitmap 索引
|
||||
|
||||
查看该查询的 Profile 中的 `BitmapIndexFilterRows` 字段。关于如何查看 Profile,参见[分析查询](../../administration/Query_planning.md#查看分析-profile)。
|
||||
查看该查询的 Profile 中的 `BitmapIndexFilterRows` 字段。关于如何查看 Profile,参见[分析查询](../../best_practices/query_tuning/query_planning.md#查看分析-profile)。
|
||||
|
||||
## Bitmap 索引性能测试
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ Bloom filter 索引可以快速判断表的数据文件中是否可能包含要
|
|||
- 字符串类型:CHAR、STRING 和 VARCHAR。
|
||||
- 日期类型:DATE、DATETIME。
|
||||
- Bloom filter 索引只能提高包含 `in` 和 `=` 过滤条件的查询效率,例如 `Select xxx from table where xxx in ()` 和 `Select xxx from table where column = xxx`。
|
||||
- 如要了解一个查询是否命中了 Bloom filter 索引,可查看该查询的 Profile 中的 `BloomFilterFilterRows` 字段。关于如何查看 Profile,参见[分析查询](../../administration/Query_planning.md#查看分析-profile)。
|
||||
- 如要了解一个查询是否命中了 Bloom filter 索引,可查看该查询的 Profile 中的 `BloomFilterFilterRows` 字段。关于如何查看 Profile,参见[分析查询](../../best_practices/query_tuning/query_planning.md#查看分析-profile)。
|
||||
|
||||
## 创建索引
|
||||
|
||||
|
|
|
|||
|
|
@ -124,4 +124,4 @@ ORDER BY (uid, name);
|
|||
|
||||
## 如何判断前缀索引是否生效
|
||||
|
||||
执行查询后,您可以通过 [Query Profile](../../administration/query_profile_overview.md) 的 scan 节点中的详细指标查看前缀索引是否生效以及过滤效果,例如 `ShortKeyFilterRows` 等指标。
|
||||
执行查询后,您可以通过 [Query Profile](../../best_practices/query_tuning/query_profile_overview.md) 的 scan 节点中的详细指标查看前缀索引是否生效以及过滤效果,例如 `ShortKeyFilterRows` 等指标。
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ SELECT flat_json_meta(<json_column>)
|
|||
FROM <table_name>[_META_];
|
||||
```
|
||||
|
||||
您可以通过观察以下指标,在[Query Profile](../administration/query_profile_overview.md)中验证执行的查询是否受益于Flat JSON优化:
|
||||
您可以通过观察以下指标,在[Query Profile](../best_practices/query_tuning/query_profile_overview.md)中验证执行的查询是否受益于Flat JSON优化:
|
||||
- `PushdownAccessPaths`: 推送到存储的子字段路径数量。
|
||||
- `AccessPathHits`: Flat JSON子字段命中次数,包含具体JSON命中信息。
|
||||
- `AccessPathUnhits`: Flat JSON子字段未命中次数,包含具体JSON未命中信息。
|
||||
|
|
@ -134,7 +134,7 @@ FROM <table_name>[_META_];
|
|||
SELECT get_json_string(k2,'\$.Bool') FROM t1 WHERE k2->'arr' = '[10,20,30]';
|
||||
```
|
||||
|
||||
7. 在[Query Profile](../administration/query_profile_overview.md)中查看Flat JSON相关指标
|
||||
7. 在[Query Profile](../best_practices/query_tuning/query_profile_overview.md)中查看Flat JSON相关指标
|
||||
```yaml
|
||||
PushdownAccessPaths: 2
|
||||
- Table: t1
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ ExecTime | 2.583 s
|
|||
- `QueryMemCost`:查询的总内存成本。
|
||||
- 其他针对各个运算符的特定指标,比如连接运算符和聚合运算符。
|
||||
|
||||
有关如何分析 Query Profile 和理解其他指标的详细信息,请参阅 [查看分析 Query Profile](../../administration/query_profile_overview.md).
|
||||
有关如何分析 Query Profile 和理解其他指标的详细信息,请参阅 [查看分析 Query Profile](../../best_practices/query_tuning/query_profile_overview.md).
|
||||
|
||||
### 验证查询是否被异步物化视图改写
|
||||
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ where empid < 5;
|
|||
|
||||
## 最佳实践
|
||||
|
||||
在实际业务场景中,您可以通过分析 Audit Log 或[大查询日志](../../../administration/management/monitor_manage_big_queries.md)来识别执行较慢、资源消耗较高的查询。您还可以使用 [Query Profile](../../../administration/query_profile_overview.md) 来精确定位查询缓慢的特定阶段。以下各小节提供了如何通过物化视图提高数据湖查询性能的说明和示例。
|
||||
在实际业务场景中,您可以通过分析 Audit Log 或[大查询日志](../../../administration/management/monitor_manage_big_queries.md)来识别执行较慢、资源消耗较高的查询。您还可以使用 [Query Profile](../../../best_practices/query_tuning/query_profile_overview.md) 来精确定位查询缓慢的特定阶段。以下各小节提供了如何通过物化视图提高数据湖查询性能的说明和示例。
|
||||
|
||||
### 案例一:加速数据湖中的 Join 计算
|
||||
|
||||
|
|
|
|||