Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release-22.2: server, sql, ui: add plan gist to active queries, add explain plan to active stms and insights #90557

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/generated/http/full.md
Original file line number Diff line number Diff line change
Expand Up @@ -2139,6 +2139,7 @@ ActiveQuery represents a query in flight on some Session.
| sql_summary | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | A summarized version of the sql query. | [reserved](#support-status) |
| is_full_scan | [bool](#cockroach.server.serverpb.ListSessionsResponse-bool) | | True if the query contains a full table or index scan. Note that this field is only valid if the query is in the EXECUTING phase. | [reserved](#support-status) |
| elapsed_time | [google.protobuf.Duration](#cockroach.server.serverpb.ListSessionsResponse-google.protobuf.Duration) | | Time elapsed since this query started execution. | [reserved](#support-status) |
| plan_gist | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | The compressed plan that can be converted back into the statement's logical plan. Empty if the statement is in the PREPARING state. | [reserved](#support-status) |



Expand Down Expand Up @@ -2281,6 +2282,7 @@ ActiveQuery represents a query in flight on some Session.
| sql_summary | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | A summarized version of the sql query. | [reserved](#support-status) |
| is_full_scan | [bool](#cockroach.server.serverpb.ListSessionsResponse-bool) | | True if the query contains a full table or index scan. Note that this field is only valid if the query is in the EXECUTING phase. | [reserved](#support-status) |
| elapsed_time | [google.protobuf.Duration](#cockroach.server.serverpb.ListSessionsResponse-google.protobuf.Duration) | | Time elapsed since this query started execution. | [reserved](#support-status) |
| plan_gist | [string](#cockroach.server.serverpb.ListSessionsResponse-string) | | The compressed plan that can be converted back into the statement's logical plan. Empty if the statement is in the PREPARING state. | [reserved](#support-status) |



Expand Down
8 changes: 4 additions & 4 deletions pkg/ccl/logictestccl/testdata/logic_test/crdb_internal_tenant
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,15 @@ SELECT * FROM crdb_internal.session_variables WHERE variable = ''
----
variable value hidden

query TTITTTTTTBTB colnames
query TTITTTTTTBTBT colnames
SELECT * FROM crdb_internal.node_queries WHERE node_id < 0
----
query_id txn_id node_id session_id user_name start query client_address application_name distributed phase full_scan
query_id txn_id node_id session_id user_name start query client_address application_name distributed phase full_scan plan_gist

query TTITTTTTTBTB colnames
query TTITTTTTTBTBT colnames
SELECT * FROM crdb_internal.cluster_queries WHERE node_id < 0
----
query_id txn_id node_id session_id user_name start query client_address application_name distributed phase full_scan
query_id txn_id node_id session_id user_name start query client_address application_name distributed phase full_scan plan_gist

query TITTTTIIIT colnames
SELECT * FROM crdb_internal.node_transactions WHERE node_id < 0
Expand Down
4 changes: 4 additions & 0 deletions pkg/server/serverpb/status.proto
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,10 @@ message ActiveQuery {
// Time elapsed since this query started execution.
google.protobuf.Duration elapsed_time = 11
[ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ];

// The compressed plan that can be converted back into the statement's logical plan.
// Empty if the statement is in the PREPARING state.
string plan_gist = 12;
}

// Request object for ListSessions and ListLocalSessions.
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/conn_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3195,6 +3195,7 @@ func (ex *connExecutor) serialize() serverpb.Session {
Phase: (serverpb.ActiveQuery_Phase)(query.phase),
Progress: float32(progress),
IsFullScan: query.isFullScan,
PlanGist: query.planGist,
})
}
lastActiveQuery := ""
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/conn_executor_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,7 @@ func (ex *connExecutor) dispatchToExecutionEngine(
if !ok {
return nil, errors.AssertionFailedf("query %d not in registry", stmt.QueryID)
}
queryMeta.planGist = planner.instrumentation.planGist.String()
queryMeta.phase = executing
// TODO(yuzefovich): introduce ternary PlanDistribution into queryMeta.
queryMeta.isDistributed = distributePlan.WillDistribute()
Expand Down
11 changes: 10 additions & 1 deletion pkg/sql/crdb_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -1764,7 +1764,8 @@ CREATE TABLE crdb_internal.%s (
application_name STRING, -- the name of the application as per SET application_name
distributed BOOL, -- whether the query is running distributed
phase STRING, -- the current execution phase
full_scan BOOL -- whether the query contains a full table or index scan
full_scan BOOL, -- whether the query contains a full table or index scan
plan_gist STRING -- Compressed logical plan.
)`

func (p *planner) makeSessionsRequest(
Expand Down Expand Up @@ -1893,6 +1894,12 @@ func populateQueriesTable(
if err != nil {
return err
}

planGistDatum := tree.DNull
if len(query.PlanGist) > 0 {
planGistDatum = tree.NewDString(query.PlanGist)
}

if err := addRow(
tree.NewDString(query.ID),
txnID,
Expand All @@ -1906,6 +1913,7 @@ func populateQueriesTable(
isDistributedDatum,
tree.NewDString(phase),
isFullScanDatum,
planGistDatum,
); err != nil {
return err
}
Expand All @@ -1930,6 +1938,7 @@ func populateQueriesTable(
tree.DNull, // distributed
tree.DNull, // phase
tree.DNull, // full_scan
tree.DNull, // plan_gist
); err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/sql/exec_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -1962,6 +1962,10 @@ type queryMeta struct {
hidden bool

progressAtomic uint64

// The compressed plan for this query. This can converted back into the
// logical plan. This field will only be populated in the EXECUTING phase.
planGist string
}

// cancel cancels the query associated with this queryMeta, by closing the
Expand Down
8 changes: 4 additions & 4 deletions pkg/sql/logictest/testdata/logic_test/crdb_internal
Original file line number Diff line number Diff line change
Expand Up @@ -347,15 +347,15 @@ SELECT * FROM crdb_internal.session_variables WHERE variable = ''
----
variable value hidden

query TTITTTTTTBTB colnames
query TTITTTTTTBTBT colnames
SELECT * FROM crdb_internal.node_queries WHERE node_id < 0
----
query_id txn_id node_id session_id user_name start query client_address application_name distributed phase full_scan
query_id txn_id node_id session_id user_name start query client_address application_name distributed phase full_scan plan_gist

query TTITTTTTTBTB colnames
query TTITTTTTTBTBT colnames
SELECT * FROM crdb_internal.cluster_queries WHERE node_id < 0
----
query_id txn_id node_id session_id user_name start query client_address application_name distributed phase full_scan
query_id txn_id node_id session_id user_name start query client_address application_name distributed phase full_scan plan_gist

query TITTTTIIIT colnames
SELECT * FROM crdb_internal.node_transactions WHERE node_id < 0
Expand Down
12 changes: 8 additions & 4 deletions pkg/sql/logictest/testdata/logic_test/create_statements
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,8 @@ CREATE TABLE crdb_internal.cluster_queries (
application_name STRING NULL,
distributed BOOL NULL,
phase STRING NULL,
full_scan BOOL NULL
full_scan BOOL NULL,
plan_gist STRING NULL
) CREATE TABLE crdb_internal.cluster_queries (
query_id STRING NULL,
txn_id UUID NULL,
Expand All @@ -379,7 +380,8 @@ CREATE TABLE crdb_internal.cluster_queries (
application_name STRING NULL,
distributed BOOL NULL,
phase STRING NULL,
full_scan BOOL NULL
full_scan BOOL NULL,
plan_gist STRING NULL
) {} {}
CREATE TABLE crdb_internal.cluster_sessions (
node_id INT8 NOT NULL,
Expand Down Expand Up @@ -1058,7 +1060,8 @@ CREATE TABLE crdb_internal.node_queries (
application_name STRING NULL,
distributed BOOL NULL,
phase STRING NULL,
full_scan BOOL NULL
full_scan BOOL NULL,
plan_gist STRING NULL
) CREATE TABLE crdb_internal.node_queries (
query_id STRING NULL,
txn_id UUID NULL,
Expand All @@ -1071,7 +1074,8 @@ CREATE TABLE crdb_internal.node_queries (
application_name STRING NULL,
distributed BOOL NULL,
phase STRING NULL,
full_scan BOOL NULL
full_scan BOOL NULL,
plan_gist STRING NULL
) {} {}
CREATE TABLE crdb_internal.node_runtime_info (
node_id INT8 NOT NULL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export function getActiveExecutionsFromSessions(
user: session.username,
clientAddress: session.client_address,
isFullScan: query.is_full_scan || false, // Or here is for conversion in case the field is null.
planGist: query.plan_gist,
};

statements.push(activeStmt);
Expand Down
1 change: 1 addition & 0 deletions pkg/ui/workspaces/cluster-ui/src/activeExecutions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type ActiveStatement = ActiveExecution &
user: string;
clientAddress: string;
isFullScan: boolean;
planGist?: string;
};

export type ActiveTransaction = ActiveExecution & {
Expand Down
68 changes: 68 additions & 0 deletions pkg/ui/workspaces/cluster-ui/src/api/decodePlanGistApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2022 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

import { SqlExecutionRequest, executeInternalSql } from "./sqlApi";

export type DecodePlanGistResponse = {
explainPlan?: string;
error?: string;
};

export type DecodePlanGistRequest = {
planGist: string;
};

type DecodePlanGistColumns = {
plan_row: string;
};

/**
* getExplainPlanFromGist decodes the provided planGist into the logical
* plan string.
* @param req the request providing the planGist
*/
export function getExplainPlanFromGist(
req: DecodePlanGistRequest,
): Promise<DecodePlanGistResponse> {
const request: SqlExecutionRequest = {
statements: [
{
sql: `SELECT crdb_internal.decode_plan_gist('${req.planGist}') as plan_row`,
},
],
execute: true,
timeout: "10s",
};

return executeInternalSql<DecodePlanGistColumns>(request).then(result => {
if (
result.execution.txn_results.length === 0 ||
!result.execution.txn_results[0].rows
) {
return {
error: result.execution.txn_results
? result.execution.txn_results[0].error?.message
: null,
};
}

if (result.execution.txn_results[0].error) {
return {
error: result.execution.txn_results[0].error.message,
};
}

const explainPlan = result.execution.txn_results[0].rows
.map(col => col.plan_row)
.join("\n");

return { explainPlan };
});
}
3 changes: 3 additions & 0 deletions pkg/ui/workspaces/cluster-ui/src/api/insightsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ type ExecutionInsightsResponseRow = {
causes: string[];
problem: string;
index_recommendations: string[];
plan_gist: string;
};

export type StatementInsights = StatementInsightEvent[];
Expand Down Expand Up @@ -628,6 +629,7 @@ function getStatementInsightsFromClusterExecutionInsightsResponse(
problem: row.problem,
indexRecommendations: row.index_recommendations,
insights: null,
planGist: row.plan_gist,
};
});
}
Expand Down Expand Up @@ -667,6 +669,7 @@ const statementInsightsQuery: InsightQuery<
index_recommendations,
problem,
causes,
plan_gist,
row_number() OVER (
PARTITION BY txn_fingerprint_id
ORDER BY end_time DESC
Expand Down
1 change: 1 addition & 0 deletions pkg/ui/workspaces/cluster-ui/src/insights/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export type StatementInsightEvent = {
application: string;
insights: Insight[];
indexRecommendations: string[];
planGist: string;
};

export type Insight = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.section {
padding: 12px 24px 12px 0px;
}
Loading