Skip to content

Commit

Permalink
Stats collection details added to Database pages
Browse files Browse the repository at this point in the history
Closes: #67510

Release note (ui change):
- Added status of automatic statistics collection to the Database
and Database table pages on the DB Console.
- Added timestamp of last statistics collection to the Database
details and Database table pages on the DB Console.
  • Loading branch information
ericharmeling committed Feb 14, 2022
1 parent 07a3683 commit 366bf32
Show file tree
Hide file tree
Showing 28 changed files with 439 additions and 32 deletions.
1 change: 1 addition & 0 deletions docs/generated/http/full.md
Original file line number Diff line number Diff line change
Expand Up @@ -4603,6 +4603,7 @@ a table.
| zone_config_level | [ZoneConfigurationLevel](#cockroach.server.serverpb.TableDetailsResponse-cockroach.server.serverpb.ZoneConfigurationLevel) | | The level at which this object's zone configuration is set. | [reserved](#support-status) |
| descriptor_id | [int64](#cockroach.server.serverpb.TableDetailsResponse-int64) | | descriptor_id is an identifier used to uniquely identify this table. It can be used to find events pertaining to this table by filtering on the 'target_id' field of events. | [reserved](#support-status) |
| configure_zone_statement | [string](#cockroach.server.serverpb.TableDetailsResponse-string) | | configure_zone_statement is the output of "SHOW ZONE CONFIGURATION FOR TABLE" for this table. It is a SQL statement that would re-configure the table's current zone if executed. | [reserved](#support-status) |
| stats_last_created_at | [google.protobuf.Timestamp](#cockroach.server.serverpb.TableDetailsResponse-google.protobuf.Timestamp) | | stats_last_created_at is the time at which statistics were last created. | [reserved](#support-status) |



Expand Down
6 changes: 6 additions & 0 deletions docs/generated/swagger/spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,12 @@
"format": "int64",
"x-go-name": "RangeCount"
},
"stats_last_created_at": {
"description": "stats_last_created_at is the time at which statistics were last created.",
"type": "string",
"format": "date-time",
"x-go-name": "StatsLastCreatedAt"
},
"zone_config": {
"$ref": "#/definitions/ZoneConfig"
},
Expand Down
2 changes: 2 additions & 0 deletions pkg/gen/excluded.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ EXCLUDED_SRCS = [
"//pkg/ui/workspaces/cluster-ui:dist/types/sessions/sessionsTableContent.d.ts",
"//pkg/ui/workspaces/cluster-ui:dist/types/sessions/terminateQueryModal.d.ts",
"//pkg/ui/workspaces/cluster-ui:dist/types/sessions/terminateSessionModal.d.ts",
"//pkg/ui/workspaces/cluster-ui:dist/types/settings/booleanSetting.d.ts",
"//pkg/ui/workspaces/cluster-ui:dist/types/settings/index.d.ts",
"//pkg/ui/workspaces/cluster-ui:dist/types/sortedtable/index.d.ts",
"//pkg/ui/workspaces/cluster-ui:dist/types/sortedtable/sortedtable.d.ts",
"//pkg/ui/workspaces/cluster-ui:dist/types/sortedtable/tableHead/index.d.ts",
Expand Down
19 changes: 19 additions & 0 deletions pkg/server/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,25 @@ func (s *adminServer) tableDetailsHelper(
resp.CreateTableStatement = createStmt
}

// Marshal SHOW STATISTICS result.
row, cols, err = s.server.sqlServer.internalExecutor.QueryRowExWithCols(
ctx, "admin-show-statistics", nil, /* txn */
sessiondata.InternalExecutorOverride{User: userName},
fmt.Sprintf("SELECT max(created) AS created FROM [SHOW STATISTICS FOR TABLE %s]", escQualTable),
)
if err != nil {
return nil, err
}
if row != nil {
scanner := makeResultScanner(cols)
const createdCol = "created"
var createdTs *time.Time
if err := scanner.Scan(row, createdCol, &createdTs); err != nil {
return nil, err
}
resp.StatsLastCreatedAt = createdTs
}

// Marshal SHOW ZONE CONFIGURATION result.
row, cols, err = s.server.sqlServer.internalExecutor.QueryRowExWithCols(
ctx, "admin-show-zone-config", nil, /* txn */
Expand Down
17 changes: 17 additions & 0 deletions pkg/server/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,7 @@ func TestAdminAPITableDetails(t *testing.T) {
"CREATE USER app",
fmt.Sprintf("GRANT SELECT ON %s.%s TO readonly", escDBName, tblName),
fmt.Sprintf("GRANT SELECT,UPDATE,DELETE ON %s.%s TO app", escDBName, tblName),
fmt.Sprintf("CREATE STATISTICS test_stats FROM %s.%s", escDBName, tblName),
}
pgURL, cleanupGoDB := sqlutils.PGUrl(
t, s.ServingSQLAddr(), "StartServer" /* prefix */, url.User(security.RootUser))
Expand Down Expand Up @@ -779,6 +780,22 @@ func TestAdminAPITableDetails(t *testing.T) {
}
}

// Verify statistics last updated.
{

showStatisticsForTableQuery := fmt.Sprintf("SELECT max(created) AS created FROM [SHOW STATISTICS FOR TABLE %s.%s]", escDBName, tblName)

row := db.QueryRow(showStatisticsForTableQuery)
var createdTs time.Time
if err := row.Scan(&createdTs); err != nil {
t.Fatal(err)
}

if a, e := resp.StatsLastCreatedAt, createdTs; reflect.DeepEqual(a, e) {
t.Fatalf("mismatched statistics creation timestamp; expected %s, got %s", e, a)
}
}

// Verify Descriptor ID.
tableID, err := ts.admin.queryTableID(ctx, security.RootUserName(), tc.dbName, tc.tblName)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions pkg/server/serverpb/admin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ message TableDetailsResponse {
// for this table. It is a SQL statement that would re-configure the table's current
// zone if executed.
string configure_zone_statement = 9;
// stats_last_created_at is the time at which statistics were last created.
google.protobuf.Timestamp stats_last_created_at = 10 [(gogoproto.stdtime) = true];
}

// TableStatsRequest is a request for detailed, computationally expensive
Expand Down
1 change: 1 addition & 0 deletions pkg/ui/workspaces/cluster-ui/src/core/colors.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ $colors--functional-orange-5: #764205;
$colors--title: $colors--neutral-8;
$colors--primary-text: $colors--neutral-7;
$colors--secondary-text: $colors--neutral-6;
$colors--success: $colors--primary-green-3;
$colors--disabled: $colors--neutral-5;
$colors--link: $colors--primary-blue-3;
$colors--white: $colors--neutral-0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
} from "./databaseDetailsPage";

import * as H from "history";
import moment from "moment";
const history = H.createHashHistory();

const withLoadingIndicator: DatabaseDetailsPageProps = {
Expand Down Expand Up @@ -107,6 +108,7 @@ const withData: DatabaseDetailsPageProps = {
userCount: roles.length,
roles: roles,
grants: grants,
statsLastUpdated: moment("0001-01-01T00:00:00Z"),
},
showNodeRegionsColumn: true,
stats: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
baseHeadingClasses,
statisticsClasses,
} from "src/transactionsPage/transactionsPageClasses";
import { Moment } from "moment";
import { formatDate } from "antd/es/date-picker/utils";

const cx = classNames.bind(styles);
const sortableTableCx = classNames.bind(sortableTableStyles);
Expand Down Expand Up @@ -101,6 +103,7 @@ export interface DatabaseDetailsPageDataTableDetails {
userCount: number;
roles: string[];
grants: string[];
statsLastUpdated?: Moment;
}

export interface DatabaseDetailsPageDataTableStats {
Expand Down Expand Up @@ -351,6 +354,26 @@ export class DatabaseDetailsPage extends React.Component<
showByDefault: this.props.showNodeRegionsColumn,
hideIfTenant: true,
},
{
title: (
<Tooltip
placement="bottom"
title="The last time table statistics were created or updated."
>
Table Stats Last Updated (UTC)
</Tooltip>
),
cell: table =>
!table.details.statsLastUpdated
? "No table statistics found"
: formatDate(
table.details.statsLastUpdated,
"MMM DD, YYYY [at] h:mm A",
),
sort: table => table.details.statsLastUpdated,
className: cx("database-table__col--table-stats"),
name: "tableStatsUpdated",
},
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ const history = H.createHashHistory();
const withLoadingIndicator: DatabaseTablePageProps = {
databaseName: randomName(),
name: randomName(),
automaticStatsCollectionEnabled: true,
details: {
loading: true,
loaded: false,
createStatement: "",
replicaCount: 0,
indexNames: [],
grants: [],
statsLastUpdated: moment("0001-01-01T00:00:00Z"),
},
stats: {
loading: true,
Expand All @@ -58,13 +60,15 @@ const withLoadingIndicator: DatabaseTablePageProps = {
refreshTableStats: () => {},
refreshIndexStats: () => {},
resetIndexUsageStats: () => {},
refreshSettings: () => {},
};

const name = randomName();

const withData: DatabaseTablePageProps = {
databaseName: randomName(),
name: name,
automaticStatsCollectionEnabled: true,
details: {
loading: false,
loaded: true,
Expand All @@ -89,6 +93,7 @@ const withData: DatabaseTablePageProps = {
};
}),
),
statsLastUpdated: moment("0001-01-01T00:00:00Z"),
},
showNodeRegionsSection: true,
stats: {
Expand Down Expand Up @@ -136,6 +141,7 @@ const withData: DatabaseTablePageProps = {
refreshTableStats: () => {},
refreshIndexStats: () => {},
resetIndexUsageStats: () => {},
refreshSettings: () => {},
};

storiesOf("Database Table Page", module)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ import _ from "lodash";
import { Tooltip } from "antd";
import { Heading } from "@cockroachlabs/ui-components";

import { Anchor } from "src/anchor";
import { Breadcrumbs } from "src/breadcrumbs";
import { CaretRight } from "src/icon/caretRight";
import { StackIcon } from "src/icon/stackIcon";
import { SqlBox } from "src/sql";
import { ColumnDescriptor, SortSetting, SortedTable } from "src/sortedtable";
import { SummaryCard, SummaryCardItem } from "src/summaryCard";
import {
SummaryCard,
SummaryCardItem,
SummaryCardItemBoolSetting,
} from "src/summaryCard";
import * as format from "src/util/format";
import { syncHistory } from "src/util";
import { syncHistory, tableStatsClusterSetting } from "src/util";

import styles from "./databaseTablePage.module.scss";
import { commonStyles } from "src/common";
Expand All @@ -32,7 +37,10 @@ import moment, { Moment } from "moment";
import { Search as IndexIcon } from "@cockroachlabs/icons";
import { formatDate } from "antd/es/date-picker/utils";
import { Link } from "react-router-dom";
import classnames from "classnames/bind";
import booleanSettingStyles from "../settings/booleanSetting.module.scss";
const cx = classNames.bind(styles);
const booleanSettingCx = classnames.bind(booleanSettingStyles);

const { TabPane } = Tabs;

Expand Down Expand Up @@ -84,6 +92,7 @@ export interface DatabaseTablePageData {
stats: DatabaseTablePageDataStats;
indexStats: DatabaseTablePageIndexStats;
showNodeRegionsSection?: boolean;
automaticStatsCollectionEnabled: boolean;
}

export interface DatabaseTablePageDataDetails {
Expand All @@ -93,6 +102,7 @@ export interface DatabaseTablePageDataDetails {
replicaCount: number;
indexNames: string[];
grants: Grant[];
statsLastUpdated?: Moment;
}

export interface DatabaseTablePageIndexStats {
Expand Down Expand Up @@ -125,6 +135,7 @@ export interface DatabaseTablePageDataStats {
export interface DatabaseTablePageActions {
refreshTableDetails: (database: string, table: string) => void;
refreshTableStats: (database: string, table: string) => void;
refreshSettings: () => void;
refreshIndexStats?: (database: string, table: string) => void;
resetIndexUsageStats?: (database: string, table: string) => void;
refreshNodes?: () => void;
Expand Down Expand Up @@ -203,6 +214,10 @@ export class DatabaseTablePage extends React.Component<
this.props.name,
);
}

if (this.props.refreshSettings != null) {
this.props.refreshSettings();
}
}

minDate = moment.utc("0001-01-01"); // minimum value as per UTC
Expand Down Expand Up @@ -359,6 +374,36 @@ export class DatabaseTablePage extends React.Component<
label="Ranges"
value={this.props.stats.rangeCount}
/>
{this.props.details.statsLastUpdated && (
<SummaryCardItem
label="Table Stats Last Updated"
value={formatDate(
this.props.details.statsLastUpdated,
"MMM DD, YYYY [at] h:mm A [(UTC)]",
)}
/>
)}
<SummaryCardItemBoolSetting
label="Auto Stats Collection"
value={this.props.automaticStatsCollectionEnabled}
toolTipText={
<span>
{" "}
Automatic statistics can help improve query
performance. Learn how to{" "}
<Anchor
href={tableStatsClusterSetting}
target="_blank"
className={booleanSettingCx(
"crl-hover-text__link-text",
)}
>
manage statistics collection
</Anchor>
.
</span>
}
/>
</SummaryCard>
</Col>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ const history = H.createHashHistory();
const withLoadingIndicator: DatabasesPageProps = {
loading: true,
loaded: false,
automaticStatsCollectionEnabled: true,
databases: [],
sortSetting: {
ascending: false,
columnTitle: "name",
},
onSortingChange: () => {},
refreshDatabases: () => {},
refreshSettings: () => {},
refreshDatabaseDetails: () => {},
refreshTableStats: () => {},
location: history.location,
Expand All @@ -44,13 +46,15 @@ const withLoadingIndicator: DatabasesPageProps = {
const withoutData: DatabasesPageProps = {
loading: false,
loaded: true,
automaticStatsCollectionEnabled: true,
databases: [],
sortSetting: {
ascending: false,
columnTitle: "name",
},
onSortingChange: () => {},
refreshDatabases: () => {},
refreshSettings: () => {},
refreshDatabaseDetails: () => {},
refreshTableStats: () => {},
location: history.location,
Expand All @@ -67,6 +71,7 @@ const withData: DatabasesPageProps = {
loading: false,
loaded: true,
showNodeRegionsColumn: true,
automaticStatsCollectionEnabled: true,
sortSetting: {
ascending: false,
columnTitle: "name",
Expand All @@ -86,6 +91,7 @@ const withData: DatabasesPageProps = {
}),
onSortingChange: () => {},
refreshDatabases: () => {},
refreshSettings: () => {},
refreshDatabaseDetails: () => {},
refreshTableStats: () => {},
location: history.location,
Expand Down
Loading

0 comments on commit 366bf32

Please sign in to comment.