From 0e73692ae641ce96424fe533050dec8b4941ae98 Mon Sep 17 00:00:00 2001 From: Zero Clover Date: Fri, 29 May 2026 19:43:09 +0800 Subject: [PATCH] perf(db): drop redundant single-column indexes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 云数据库巡检标记的 13 个单列索引,其列均为既有复合/唯一索引的最左前缀, PostgreSQL 可用更宽的索引服务相同查询,单列索引纯属冗余,只增加写放大与存储。 - 新增迁移 143_drop_redundant_indexes_notx.sql:以 DROP INDEX CONCURRENTLY IF EXISTS 删除全部 13 个索引(usage_logs×6、两张 dashboard 去重表、 payment_audit_logs、channel_monitors、auth_identities、 auth_identity_migration_reports、user_provider_default_grants), 非事务幂等执行,避免在高写入的 usage_logs 上持有排他锁。 - 同步移除 ent schema 中对应的 9 个单列索引声明并重新生成 ent 代码; 保留 usage_logs.group_id(线上为 group_id IS NOT NULL 的部分复合索引, 无法覆盖 NULL,未被标记为冗余)。 - 修正迁移校验器以首关键字判定 CREATE/DROP,避免名称含 "created" 的 索引(如 idx_usage_logs_created_at)被误判为 CREATE 而要求 IF NOT EXISTS; 补充对应回归用例。 --- backend/ent/migrate/schema.go | 47 ------------------- backend/ent/schema/auth_identity.go | 1 - backend/ent/schema/channel_monitor.go | 1 - backend/ent/schema/payment_audit_log.go | 5 +- backend/ent/schema/usage_log.go | 6 --- .../internal/repository/migrations_runner.go | 5 +- .../repository/migrations_runner_notx_test.go | 6 +++ .../143_drop_redundant_indexes_notx.sql | 16 +++++++ 8 files changed, 26 insertions(+), 61 deletions(-) create mode 100644 backend/migrations/143_drop_redundant_indexes_notx.sql diff --git a/backend/ent/migrate/schema.go b/backend/ent/migrate/schema.go index 447f71ef9c2..07f165ad546 100644 --- a/backend/ent/migrate/schema.go +++ b/backend/ent/migrate/schema.go @@ -370,11 +370,6 @@ var ( Unique: true, Columns: []*schema.Column{AuthIdentitiesColumns[3], AuthIdentitiesColumns[4], AuthIdentitiesColumns[5]}, }, - { - Name: "authidentity_user_id", - Unique: false, - Columns: []*schema.Column{AuthIdentitiesColumns[9]}, - }, { Name: "authidentity_user_id_provider_type", Unique: false, @@ -462,11 +457,6 @@ var ( Unique: false, Columns: []*schema.Column{ChannelMonitorsColumns[11], ChannelMonitorsColumns[13]}, }, - { - Name: "channelmonitor_provider", - Unique: false, - Columns: []*schema.Column{ChannelMonitorsColumns[4]}, - }, { Name: "channelmonitor_provider_api_mode", Unique: false, @@ -804,13 +794,6 @@ var ( Name: "payment_audit_logs", Columns: PaymentAuditLogsColumns, PrimaryKey: []*schema.Column{PaymentAuditLogsColumns[0]}, - Indexes: []*schema.Index{ - { - Name: "paymentauditlog_order_id", - Unique: false, - Columns: []*schema.Column{PaymentAuditLogsColumns[1]}, - }, - }, } // PaymentOrdersColumns holds the columns for the "payment_orders" table. PaymentOrdersColumns = []*schema.Column{ @@ -1386,41 +1369,11 @@ var ( }, }, Indexes: []*schema.Index{ - { - Name: "usagelog_user_id", - Unique: false, - Columns: []*schema.Column{UsageLogsColumns[40]}, - }, - { - Name: "usagelog_api_key_id", - Unique: false, - Columns: []*schema.Column{UsageLogsColumns[37]}, - }, - { - Name: "usagelog_account_id", - Unique: false, - Columns: []*schema.Column{UsageLogsColumns[38]}, - }, { Name: "usagelog_group_id", Unique: false, Columns: []*schema.Column{UsageLogsColumns[39]}, }, - { - Name: "usagelog_subscription_id", - Unique: false, - Columns: []*schema.Column{UsageLogsColumns[41]}, - }, - { - Name: "usagelog_created_at", - Unique: false, - Columns: []*schema.Column{UsageLogsColumns[36]}, - }, - { - Name: "usagelog_model", - Unique: false, - Columns: []*schema.Column{UsageLogsColumns[2]}, - }, { Name: "usagelog_requested_model", Unique: false, diff --git a/backend/ent/schema/auth_identity.go b/backend/ent/schema/auth_identity.go index 3deeadcd96c..ae23b9266dc 100644 --- a/backend/ent/schema/auth_identity.go +++ b/backend/ent/schema/auth_identity.go @@ -91,7 +91,6 @@ func (AuthIdentity) Edges() []ent.Edge { func (AuthIdentity) Indexes() []ent.Index { return []ent.Index{ index.Fields("provider_type", "provider_key", "provider_subject").Unique(), - index.Fields("user_id"), index.Fields("user_id", "provider_type"), } } diff --git a/backend/ent/schema/channel_monitor.go b/backend/ent/schema/channel_monitor.go index 431ab9c8ddd..6ff43f9b0a8 100644 --- a/backend/ent/schema/channel_monitor.go +++ b/backend/ent/schema/channel_monitor.go @@ -107,7 +107,6 @@ func (ChannelMonitor) Edges() []ent.Edge { func (ChannelMonitor) Indexes() []ent.Index { return []ent.Index{ index.Fields("enabled", "last_checked_at"), - index.Fields("provider"), index.Fields("provider", "api_mode"), index.Fields("group_name"), index.Fields("template_id"), diff --git a/backend/ent/schema/payment_audit_log.go b/backend/ent/schema/payment_audit_log.go index 7f8a8c04423..65c1de46270 100644 --- a/backend/ent/schema/payment_audit_log.go +++ b/backend/ent/schema/payment_audit_log.go @@ -8,7 +8,6 @@ import ( "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema" "entgo.io/ent/schema/field" - "entgo.io/ent/schema/index" ) // PaymentAuditLog holds the schema definition for the PaymentAuditLog entity. @@ -48,7 +47,5 @@ func (PaymentAuditLog) Fields() []ent.Field { } func (PaymentAuditLog) Indexes() []ent.Index { - return []ent.Index{ - index.Fields("order_id"), - } + return []ent.Index{} } diff --git a/backend/ent/schema/usage_log.go b/backend/ent/schema/usage_log.go index db9e5178922..231fe8bae18 100644 --- a/backend/ent/schema/usage_log.go +++ b/backend/ent/schema/usage_log.go @@ -193,13 +193,7 @@ func (UsageLog) Edges() []ent.Edge { // Indexes 定义数据库索引,优化查询性能。 func (UsageLog) Indexes() []ent.Index { return []ent.Index{ - index.Fields("user_id"), - index.Fields("api_key_id"), - index.Fields("account_id"), index.Fields("group_id"), - index.Fields("subscription_id"), - index.Fields("created_at"), - index.Fields("model"), index.Fields("requested_model"), index.Fields("request_id"), // 复合索引用于时间范围查询 diff --git a/backend/internal/repository/migrations_runner.go b/backend/internal/repository/migrations_runner.go index 6dbb9fbd7c0..f911ef58b02 100644 --- a/backend/internal/repository/migrations_runner.go +++ b/backend/internal/repository/migrations_runner.go @@ -465,8 +465,9 @@ func validateMigrationExecutionMode(name, content string) (bool, error) { } if strings.Contains(normalizedStmt, "CONCURRENTLY") { - isCreateIndex := strings.Contains(normalizedStmt, "CREATE") && strings.Contains(normalizedStmt, "INDEX") - isDropIndex := strings.Contains(normalizedStmt, "DROP") && strings.Contains(normalizedStmt, "INDEX") + // 按首关键字判定,避免索引名含 "created" 等子串使 DROP 被误判为 CREATE。 + isCreateIndex := strings.HasPrefix(normalizedStmt, "CREATE") && strings.Contains(normalizedStmt, "INDEX") + isDropIndex := strings.HasPrefix(normalizedStmt, "DROP") && strings.Contains(normalizedStmt, "INDEX") if !isCreateIndex && !isDropIndex { return false, errors.New("*_notx.sql currently only supports CREATE/DROP INDEX CONCURRENTLY statements") } diff --git a/backend/internal/repository/migrations_runner_notx_test.go b/backend/internal/repository/migrations_runner_notx_test.go index b7cb396c470..a9b5888867b 100644 --- a/backend/internal/repository/migrations_runner_notx_test.go +++ b/backend/internal/repository/migrations_runner_notx_test.go @@ -49,6 +49,12 @@ DROP INDEX CONCURRENTLY IF EXISTS idx_b; require.True(t, nonTx) require.NoError(t, err) }) + + t.Run("notx迁移允许DROP名称含created的索引", func(t *testing.T) { + nonTx, err := validateMigrationExecutionMode("143_drop_idx_notx.sql", "DROP INDEX CONCURRENTLY IF EXISTS idx_usage_logs_created_at;") + require.True(t, nonTx) + require.NoError(t, err) + }) } func TestApplyMigrationsFS_NonTransactionalMigration(t *testing.T) { diff --git a/backend/migrations/143_drop_redundant_indexes_notx.sql b/backend/migrations/143_drop_redundant_indexes_notx.sql new file mode 100644 index 00000000000..b8a57a94edb --- /dev/null +++ b/backend/migrations/143_drop_redundant_indexes_notx.sql @@ -0,0 +1,16 @@ +-- 143:删除被云数据库巡检标记为冗余的单列索引(均为既有复合/唯一索引的最左前缀,可被覆盖)。 +-- 采用 *_notx + DROP INDEX CONCURRENTLY 避免在高写入表上持有排他锁;IF EXISTS 保证可重复执行。 + +DROP INDEX CONCURRENTLY IF EXISTS idx_usage_logs_user_id; +DROP INDEX CONCURRENTLY IF EXISTS idx_usage_logs_api_key_id; +DROP INDEX CONCURRENTLY IF EXISTS idx_usage_logs_account_id; +DROP INDEX CONCURRENTLY IF EXISTS idx_usage_logs_model; +DROP INDEX CONCURRENTLY IF EXISTS idx_usage_logs_subscription_id; +DROP INDEX CONCURRENTLY IF EXISTS idx_usage_logs_created_at; +DROP INDEX CONCURRENTLY IF EXISTS idx_usage_dashboard_hourly_users_bucket_start; +DROP INDEX CONCURRENTLY IF EXISTS idx_usage_dashboard_daily_users_bucket_date; +DROP INDEX CONCURRENTLY IF EXISTS idx_payment_audit_logs_order_id; +DROP INDEX CONCURRENTLY IF EXISTS idx_channel_monitors_provider; +DROP INDEX CONCURRENTLY IF EXISTS auth_identity_migration_reports_type_idx; +DROP INDEX CONCURRENTLY IF EXISTS auth_identities_user_id_idx; +DROP INDEX CONCURRENTLY IF EXISTS user_provider_default_grants_user_id_idx;