Files
server/app/console/commands/optimize_tables.go
T
2026-01-16 15:49:34 +08:00

122 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package commands
import (
"fmt"
"strings"
"github.com/goravel/framework/contracts/console"
"github.com/goravel/framework/contracts/console/command"
"github.com/goravel/framework/facades"
)
type OptimizeTables struct {
}
func (r *OptimizeTables) Signature() string {
return "db:optimize-tables"
}
func (r *OptimizeTables) Description() string {
// # MySQL: OPTIMIZE TABLE(整理碎片,回收空间)
// # PostgreSQL: VACUUM (ANALYZE)(清理死元组并更新统计信息)
//
// # 传参方式:直接传表名(可多个)
// go run . artisan db:optimize-tables payments
// go run . artisan db:optimize-tables payments orders_202601 order_details_202601
//
// # 选项方式:--tables= 逗号分隔
// go run . artisan db:optimize-tables --tables=payments,orders_202601
//
// # PostgreSQL 重度回收空间(风险高:会锁表,且耗时长)
// go run . artisan db:optimize-tables payments --full=true
//
// # 帮助
// go run . artisan db:optimize-tables --help
return "优化表(MySQL: OPTIMIZE TABLE; PostgreSQL: VACUUM"
}
func (r *OptimizeTables) Extend() command.Extend {
return command.Extend{
Category: "db",
Flags: []command.Flag{
&command.StringFlag{
Name: "tables",
Aliases: []string{"t"},
Usage: "要优化的表名列表(逗号分隔),也可以直接用参数方式传入多个表名",
},
&command.BoolFlag{
Name: "full",
Value: false,
Usage: "PostgreSQL 是否使用 VACUUM FULL(更重,可能锁表,默认 false",
},
},
}
}
func (r *OptimizeTables) Handle(ctx console.Context) error {
dbConnection := strings.ToLower(facades.Config().GetString("database.default", "sqlite"))
full := ctx.OptionBool("full")
var tables []string
// 1) 从 --tables 读取(逗号分隔)
tablesFlag := strings.TrimSpace(ctx.Option("tables"))
if tablesFlag != "" {
parts := strings.Split(tablesFlag, ",")
for _, p := range parts {
t := strings.TrimSpace(p)
if t != "" {
tables = append(tables, t)
}
}
}
// 2) 从参数读取(db:optimize-tables table1 table2 ...
for i := 0; ; i++ {
arg := strings.TrimSpace(ctx.Argument(i))
if arg == "" {
break
}
tables = append(tables, arg)
}
if len(tables) == 0 {
return fmt.Errorf("请提供要优化的表名,例如:go run . artisan db:optimize-tables payments 或使用 --tables=payments,orders_202601")
}
execOptimize := func(table string) error {
var sql string
switch dbConnection {
case "mysql":
sql = fmt.Sprintf("OPTIMIZE TABLE `%s`", table)
case "postgres":
if full {
sql = fmt.Sprintf("VACUUM (FULL, ANALYZE) %s", table)
} else {
sql = fmt.Sprintf("VACUUM (ANALYZE) %s", table)
}
default:
return fmt.Errorf("unsupported database: %s", dbConnection)
}
if _, err := facades.Orm().Query().Exec(sql); err != nil {
return err
}
ctx.Info("✓ " + sql)
return nil
}
ctx.Info("开始执行优化...")
for _, table := range tables {
if facades.Schema().HasTable(table) {
if err := execOptimize(table); err != nil {
return fmt.Errorf("optimize %s failed: %v", table, err)
}
}
}
ctx.Info("完成")
return nil
}