diff --git a/pkg/kv/kvserver/metrics.go b/pkg/kv/kvserver/metrics.go index 1742838b7e03..f255c978f933 100644 --- a/pkg/kv/kvserver/metrics.go +++ b/pkg/kv/kvserver/metrics.go @@ -531,6 +531,12 @@ var ( Measurement: "Keys", Unit: metric.Unit_COUNT, } + metaRdbKeysTombstones = metric.Metadata{ + Name: "storage.keys.tombstone.count", + Help: "Approximate count of DEL, SINGLEDEL and RANGEDEL internal keys across the storage engine.", + Measurement: "Keys", + Unit: metric.Unit_COUNT, + } // NB: bytes only ever get flushed into L0, so this metric does not // exist for any other level. metaRdbL0BytesFlushed = storageLevelMetricMetadata( @@ -1811,6 +1817,7 @@ type StoreMetrics struct { RdbPendingCompaction *metric.Gauge RdbMarkedForCompactionFiles *metric.Gauge RdbKeysRangeKeySets *metric.Gauge + RdbKeysTombstones *metric.Gauge RdbL0BytesFlushed *metric.Gauge RdbL0Sublevels *metric.Gauge RdbL0NumFiles *metric.Gauge @@ -2349,6 +2356,7 @@ func newStoreMetrics(histogramWindow time.Duration) *StoreMetrics { RdbPendingCompaction: metric.NewGauge(metaRdbPendingCompaction), RdbMarkedForCompactionFiles: metric.NewGauge(metaRdbMarkedForCompactionFiles), RdbKeysRangeKeySets: metric.NewGauge(metaRdbKeysRangeKeySets), + RdbKeysTombstones: metric.NewGauge(metaRdbKeysTombstones), RdbL0BytesFlushed: metric.NewGauge(metaRdbL0BytesFlushed), RdbL0Sublevels: metric.NewGauge(metaRdbL0Sublevels), RdbL0NumFiles: metric.NewGauge(metaRdbL0NumFiles), @@ -2677,6 +2685,7 @@ func (sm *StoreMetrics) updateEngineMetrics(m storage.Metrics) { sm.RdbPendingCompaction.Update(int64(m.Compact.EstimatedDebt)) sm.RdbMarkedForCompactionFiles.Update(int64(m.Compact.MarkedFiles)) sm.RdbKeysRangeKeySets.Update(int64(m.Keys.RangeKeySetsCount)) + sm.RdbKeysTombstones.Update(int64(m.Keys.TombstoneCount)) sm.RdbNumSSTables.Update(m.NumSSTables()) sm.RdbWriteStalls.Update(m.WriteStallCount) sm.RdbWriteStallNanos.Update(m.WriteStallDuration.Nanoseconds()) diff --git a/pkg/ts/catalog/chart_catalog.go b/pkg/ts/catalog/chart_catalog.go index b7f180f84ae7..67dfa14e08d9 100644 --- a/pkg/ts/catalog/chart_catalog.go +++ b/pkg/ts/catalog/chart_catalog.go @@ -3029,6 +3029,10 @@ var charts = []sectionDescription{ Title: "Range Key Set Count", Metrics: []string{"storage.keys.range-key-set.count"}, }, + { + Title: "Tombstone Count", + Metrics: []string{"storage.keys.tombstone.count"}, + }, }, }, { diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsOverviewTab.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsOverviewTab.tsx index 30bb4f67e8ea..7e1db250ee31 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsOverviewTab.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetailsOverviewTab.tsx @@ -56,7 +56,7 @@ export const StatementInsightDetailsOverviewTab: React.FC< const isCockroachCloud = useContext(CockroachCloudContext); const insightsColumns = useMemo( - () => makeInsightsColumns(isCockroachCloud, hasAdminRole, true), + () => makeInsightsColumns(isCockroachCloud, hasAdminRole), [isCockroachCloud, hasAdminRole], ); diff --git a/pkg/ui/workspaces/cluster-ui/src/insightsTable/insightsTable.tsx b/pkg/ui/workspaces/cluster-ui/src/insightsTable/insightsTable.tsx index 673a37d17e04..d800ad82db4a 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insightsTable/insightsTable.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insightsTable/insightsTable.tsx @@ -131,11 +131,15 @@ const StatementExecution = ({ function descriptionCell( insightRec: InsightRecommendation, - isExecution: boolean, + disableStmtLink: boolean, isCockroachCloud: boolean, + isFingerprint: boolean, ): React.ReactElement { const stmtLink = isIndexRec(insightRec) ? ( - + ) : null; const clusterSettingsLink = ( @@ -201,7 +205,7 @@ function descriptionCell( case "HighContention": return ( <> - {isExecution && ( + {!isFingerprint && (
Time Spent Waiting: {" "} {Duration(insightRec.details.duration * 1e6)} @@ -209,7 +213,7 @@ function descriptionCell( )} {stmtLink}
- {isExecution && ( + {!isFingerprint && ( Description: )} {insightRec.details.description} {clusterSettingsLink} @@ -272,7 +276,7 @@ function descriptionCell( case "Unknown": return ( <> - {isExecution && ( + {!isFingerprint && (
Elapsed Time: {Duration(insightRec.details.duration * 1e6)} @@ -280,7 +284,7 @@ function descriptionCell( )} {stmtLink}
- {isExecution && ( + {!isFingerprint && ( Description: )} {insightRec.details.description} {clusterSettingsLink} @@ -390,7 +394,8 @@ const isIndexRec = (rec: InsightRecommendation) => { export function makeInsightsColumns( isCockroachCloud: boolean, hasAdminRole: boolean, - isExecution?: boolean, + disableStmtLink?: boolean, + isFingerprint?: boolean, ): ColumnDescriptor[] { const columns: ColumnDescriptor[] = [ { @@ -403,17 +408,17 @@ export function makeInsightsColumns( name: "details", title: insightsTableTitles.details(), cell: (item: InsightRecommendation) => - descriptionCell(item, isExecution, isCockroachCloud), + descriptionCell(item, disableStmtLink, isCockroachCloud, isFingerprint), sort: (item: InsightRecommendation) => item.type, }, { name: "action", title: insightsTableTitles.actions(), cell: (item: InsightRecommendation) => - actionCell(item, isCockroachCloud || !hasAdminRole || !isExecution), + actionCell(item, isCockroachCloud || !hasAdminRole || isFingerprint), }, ]; - if (!isExecution) { + if (isFingerprint) { columns.push({ name: "latestExecution", title: insightsTableTitles.latestExecution(), diff --git a/pkg/ui/workspaces/cluster-ui/src/statementDetails/planDetails/planDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/statementDetails/planDetails/planDetails.tsx index 3d56b12424a2..699eafd1c117 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementDetails/planDetails/planDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/statementDetails/planDetails/planDetails.tsx @@ -295,7 +295,7 @@ export function Insights({ hasAdminRole, }: InsightsProps): React.ReactElement { const hideAction = useContext(CockroachCloudContext) || database?.length == 0; - const insightsColumns = makeInsightsColumns(hideAction, hasAdminRole, false); + const insightsColumns = makeInsightsColumns(hideAction, hasAdminRole, true); const data = formatIdxRecommendations( idxRecommendations, database, diff --git a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx index 436843f55381..29413afb5570 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx @@ -665,7 +665,8 @@ export class StatementDetails extends React.Component< const insightsColumns = makeInsightsColumns( isCockroachCloud, this.props.hasAdminRole, - false, + true, + true, ); const tableData: InsightRecommendation[] = []; if (statementFingerprintInsights) { diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx index c334bb33989c..5c2982033a45 100644 --- a/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx @@ -456,7 +456,8 @@ export class TransactionDetails extends React.Component< const insightsColumns = makeInsightsColumns( isCockroachCloud, this.props.hasAdminRole, - false, + true, + true, ); const tableData: InsightRecommendation[] = []; if (transactionInsights) {