Skip to content

Commit

Permalink
Merge #104270
Browse files Browse the repository at this point in the history
104270: server, ui: don't recommend drop index to unique indexes r=maryliag a=maryliag

Previously, when an index was not being used we were recommending it to be dropped, and only if the index was primary, we would not recommend.
We should not be recommending to drop unique indexes, because even when they are not used for read, they're important for inserts and being dropped would change the schema of the table.

Part Of #104143

https://www.loom.com/share/b4e7fae3594944d09ec9af7e53bed7be

Release note (ui change): No longer show drop index recommendation for unique indexes.

Co-authored-by: maryliag <[email protected]>
  • Loading branch information
craig[bot] and maryliag committed Jun 2, 2023
2 parents 4ac97a8 + f679234 commit b250d9c
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 18 deletions.
2 changes: 1 addition & 1 deletion docs/generated/http/full.md
Original file line number Diff line number Diff line change
Expand Up @@ -4878,7 +4878,7 @@ Response object returned by TableIndexStatsResponse.
| index_name | [string](#cockroach.server.serverpb.TableIndexStatsResponse-string) | | index_name is the name of the index. | [reserved](#support-status) |
| index_type | [string](#cockroach.server.serverpb.TableIndexStatsResponse-string) | | index_type is the type of the index i.e. primary, secondary. | [reserved](#support-status) |
| create_statement | [string](#cockroach.server.serverpb.TableIndexStatsResponse-string) | | create_statement is the SQL statement that would re-create the current index if executed. | [reserved](#support-status) |
| created_at | [google.protobuf.Timestamp](#cockroach.server.serverpb.TableIndexStatsResponse-google.protobuf.Timestamp) | | CreatedAt is an approximate timestamp at which the index was created. Note that it may not always be populated. | [reserved](#support-status) |
| created_at | [google.protobuf.Timestamp](#cockroach.server.serverpb.TableIndexStatsResponse-google.protobuf.Timestamp) | | created_at is an approximate timestamp at which the index was created. Note that it may not always be populated. | [reserved](#support-status) |
| index_id | [string](#cockroach.server.serverpb.TableIndexStatsResponse-string) | | index_id is the ID of the index. | [reserved](#support-status) |
| table_id | [string](#cockroach.server.serverpb.TableIndexStatsResponse-string) | | table_id is the ID of the table which the index belongs to. | [reserved](#support-status) |

Expand Down
10 changes: 8 additions & 2 deletions pkg/server/index_usage_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ func getTableIndexUsageStats(
total_reads,
last_read,
indexdef,
ti.created_at
ti.created_at,
ti.is_unique
FROM crdb_internal.index_usage_statistics AS us
JOIN crdb_internal.table_indexes AS ti ON us.index_id = ti.index_id
AND us.table_id = ti.descriptor_id
Expand Down Expand Up @@ -294,6 +295,7 @@ func getTableIndexUsageStats(
ts := tree.MustBeDTimestamp(row[6])
createdAt = &ts.Time
}
isUnique := tree.MustBeDBool(row[7])

if err != nil {
return nil, err
Expand Down Expand Up @@ -322,6 +324,7 @@ func getTableIndexUsageStats(
CreatedAt: idxStatsRow.CreatedAt,
LastRead: idxStatsRow.Statistics.Stats.LastRead,
IndexType: idxStatsRow.IndexType,
IsUnique: bool(isUnique),
UnusedIndexKnobs: execConfig.UnusedIndexRecommendationsKnobs,
}
recommendations := statsRow.GetRecommendationsFromIndexStats(req.Database, st)
Expand Down Expand Up @@ -396,7 +399,8 @@ func getDatabaseIndexRecommendations(
ti.index_id,
ti.index_type,
last_read,
ti.created_at
ti.created_at,
ti.is_unique
FROM %[1]s.crdb_internal.index_usage_statistics AS us
JOIN %[1]s.crdb_internal.table_indexes AS ti ON (us.index_id = ti.index_id AND us.table_id = ti.descriptor_id AND index_type = 'secondary')
JOIN %[1]s.crdb_internal.tables AS t ON (ti.descriptor_id = t.table_id AND t.database_name != 'system');`, escDBName)
Expand Down Expand Up @@ -433,6 +437,7 @@ func getDatabaseIndexRecommendations(
ts := tree.MustBeDTimestamp(row[4])
createdAt = &ts.Time
}
isUnique := tree.MustBeDBool(row[5])

if err != nil {
return []*serverpb.IndexRecommendation{}, err
Expand All @@ -444,6 +449,7 @@ func getDatabaseIndexRecommendations(
CreatedAt: createdAt,
LastRead: lastRead,
IndexType: string(indexType),
IsUnique: bool(isUnique),
UnusedIndexKnobs: knobs,
}
recommendations := statsRow.GetRecommendationsFromIndexStats(dbName, st)
Expand Down
2 changes: 1 addition & 1 deletion pkg/server/serverpb/status.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1899,7 +1899,7 @@ message TableIndexStatsResponse {
// create_statement is the SQL statement that would re-create the
// current index if executed.
string create_statement = 4;
// CreatedAt is an approximate timestamp at which the index was created.
// created_at is an approximate timestamp at which the index was created.
// Note that it may not always be populated.
google.protobuf.Timestamp created_at = 5 [(gogoproto.stdtime) = true];
// index_id is the ID of the index.
Expand Down
3 changes: 2 additions & 1 deletion pkg/sql/idxusage/index_usage_stats_rec.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type IndexStatsRow struct {
CreatedAt *time.Time
LastRead time.Time
IndexType string
IsUnique bool
UnusedIndexKnobs *UnusedIndexRecommendationTestingKnobs
}

Expand Down Expand Up @@ -85,7 +86,7 @@ func (i IndexStatsRow) GetRecommendationsFromIndexStats(
func (i IndexStatsRow) maybeAddUnusedIndexRecommendation(
unusedIndexDuration time.Duration,
) *serverpb.IndexRecommendation {
if i.IndexType == "primary" {
if i.IsUnique {
return nil
}

Expand Down
28 changes: 24 additions & 4 deletions pkg/sql/idxusage/index_usage_stats_rec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TestGetRecommendationsFromIndexStats(t *testing.T) {
- drop unused rec
- drop never used rec
- recently used index
- secondary unique index
*/

testData := []struct {
Expand All @@ -50,6 +51,7 @@ func TestGetRecommendationsFromIndexStats(t *testing.T) {
IndexID: 2,
LastRead: anHourBefore,
IndexType: "secondary",
IsUnique: false,
CreatedAt: nil,
UnusedIndexKnobs: nil,
},
Expand All @@ -66,6 +68,7 @@ func TestGetRecommendationsFromIndexStats(t *testing.T) {
CreatedAt: nil,
UnusedIndexKnobs: nil,
IndexType: "primary",
IsUnique: true,
},
dbName: "testdb",
unusedIndexDuration: time.Hour,
Expand All @@ -78,6 +81,7 @@ func TestGetRecommendationsFromIndexStats(t *testing.T) {
IndexID: 2,
LastRead: anHourBefore,
IndexType: "secondary",
IsUnique: false,
CreatedAt: nil,
UnusedIndexKnobs: nil,
},
Expand All @@ -95,11 +99,11 @@ func TestGetRecommendationsFromIndexStats(t *testing.T) {
// Index has never been used and has no creation time, expect never used index recommendation.
{
idxStats: IndexStatsRow{
TableID: 1,
IndexID: 3,
LastRead: time.Time{},

TableID: 1,
IndexID: 3,
LastRead: time.Time{},
IndexType: "secondary",
IsUnique: false,
CreatedAt: nil,
UnusedIndexKnobs: nil,
},
Expand All @@ -121,13 +125,29 @@ func TestGetRecommendationsFromIndexStats(t *testing.T) {
IndexID: 4,
LastRead: aMinuteBefore,
IndexType: "secondary",
IsUnique: false,
CreatedAt: nil,
UnusedIndexKnobs: nil,
},
dbName: "testdb",
unusedIndexDuration: defaultUnusedIndexDuration,
expectedReturn: []*serverpb.IndexRecommendation{},
},
// Index exceeds the unused index duration, but is unique, so expect no index recommendation.
{
idxStats: IndexStatsRow{
TableID: 1,
IndexID: 5,
LastRead: anHourBefore,
IndexType: "secondary",
IsUnique: true,
CreatedAt: nil,
UnusedIndexKnobs: nil,
},
dbName: "testdb",
unusedIndexDuration: time.Hour,
expectedReturn: []*serverpb.IndexRecommendation{},
},
}

st := cluster.MakeTestingClusterSettings()
Expand Down
7 changes: 2 additions & 5 deletions pkg/ui/workspaces/cluster-ui/src/api/databaseDetailsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@ import {
executeInternalSql,
formatApiResult,
isMaxSizeError,
LARGE_RESULT_SIZE,
LONG_TIMEOUT,
SqlApiQueryResponse,
SqlApiResponse,
SqlExecutionErrorMessage,
SqlExecutionRequest,
SqlExecutionResponse,
SqlStatement,
SqlTxnResult,
txnResultIsEmpty,
Expand Down Expand Up @@ -423,9 +420,9 @@ const getDatabaseIndexUsageStats: DatabaseDetailsQuery<IndexUsageStatistic> = {
cs.value::interval as interval_threshold,
now() - COALESCE(us.last_read AT TIME ZONE 'UTC', COALESCE(ti.created_at, '0001-01-01')) as unused_interval
FROM %1.crdb_internal.index_usage_statistics AS us
JOIN %1.crdb_internal.table_indexes AS ti ON (us.index_id = ti.index_id AND us.table_id = ti.descriptor_id AND ti.index_type = 'secondary')
JOIN %1.crdb_internal.table_indexes AS ti ON (us.index_id = ti.index_id AND us.table_id = ti.descriptor_id)
CROSS JOIN cs
WHERE $1 != 'system')
WHERE $1 != 'system' AND ti.is_unique IS false)
WHERE unused_interval > interval_threshold
ORDER BY total_reads DESC;`,
[new Identifier(dbName)],
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/workspaces/cluster-ui/src/api/schemaInsightsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ const dropUnusedIndexQuery: SchemaInsightQuery<ClusterIndexUsageStatistic> = {
JOIN "".crdb_internal.tables as t
ON t.table_id = ti.descriptor_id and t.name = ti.descriptor_name
CROSS JOIN cs
WHERE t.database_name != 'system' AND ti.index_type != 'primary')
WHERE t.database_name != 'system' AND ti.is_unique IS false)
WHERE unused_interval > interval_threshold
ORDER BY total_reads DESC;`,
toSchemaInsight: clusterIndexUsageStatsToSchemaInsight,
Expand Down
5 changes: 2 additions & 3 deletions pkg/ui/workspaces/cluster-ui/src/api/tableDetailsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,11 +494,10 @@ const getTableIndexUsageStats: TableDetailsQuery<IndexUsageStatistic> = {
JOIN tableId ON us.table_id = tableId.table_id
JOIN %1.crdb_internal.table_indexes AS ti ON (
us.index_id = ti.index_id AND
tableId.table_id = ti.descriptor_id AND
ti.index_type = 'secondary'
tableId.table_id = ti.descriptor_id
)
CROSS JOIN cs
WHERE $2 != 'system')
WHERE $2 != 'system' AND ti.is_unique IS false)
WHERE unused_interval > interval_threshold
ORDER BY total_reads DESC`,
[new Identifier(dbName)],
Expand Down

0 comments on commit b250d9c

Please sign in to comment.