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

163 lines
4.0 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"
"time"
"github.com/goravel/framework/contracts/console"
"github.com/goravel/framework/contracts/console/command"
"github.com/goravel/framework/facades"
"goravel/app/utils"
)
type AnalyzeStats struct {
}
func (r *AnalyzeStats) Signature() string {
return "db:analyze-stats"
}
func (r *AnalyzeStats) Description() string {
// # 默认:分析当前月+上个月的 orders/order_details 分表,并分析 payments 表
// go run . artisan db:analyze-stats
//
// # 指定向前分析几个月(含当前月)
// go run . artisan db:analyze-stats --months=2
// go run . artisan db:analyze-stats --months=6
//
// # 指定某一个月(只分析该月的分表)
// go run . artisan db:analyze-stats --month=202601
//
// # 只分析订单分表,不分析支付表
// go run . artisan db:analyze-stats --payments=false
//
// # 只分析 payments 表
// go run . artisan db:analyze-stats --orders=false --order-details=false
//
// # 帮助
// go run . artisan db:analyze-stats --help
return "更新订单分表与支付表统计信息(ANALYZE)"
}
func (r *AnalyzeStats) Extend() command.Extend {
return command.Extend{
Category: "db",
Flags: []command.Flag{
&command.StringFlag{
Name: "month",
Aliases: []string{"m"},
Usage: "指定月份(格式: YYYYMM,如:202512),不指定则按 months 向前分析",
},
&command.IntFlag{
Name: "months",
Aliases: []string{"n"},
Value: 2,
Usage: "向前分析几个月(默认2:当前月+上个月)",
},
&command.BoolFlag{
Name: "orders",
Value: true,
Usage: "是否分析订单分表(orders_YYYYMM",
},
&command.BoolFlag{
Name: "order-details",
Value: true,
Usage: "是否分析订单详情分表(order_details_YYYYMM",
},
&command.BoolFlag{
Name: "payments",
Value: true,
Usage: "是否分析支付记录表(payments",
},
},
}
}
func (r *AnalyzeStats) Handle(ctx console.Context) error {
dbConnection := strings.ToLower(facades.Config().GetString("database.default", "sqlite"))
monthsFlag := ctx.OptionInt("months")
if monthsFlag <= 0 {
monthsFlag = 2
}
monthFlag := strings.TrimSpace(ctx.Option("month"))
analyzeOrders := ctx.OptionBool("orders")
analyzeOrderDetails := ctx.OptionBool("order-details")
analyzePayments := ctx.OptionBool("payments")
var months []time.Time
if monthFlag != "" {
parsedTime, err := time.ParseInLocation("200601", monthFlag, time.UTC)
if err != nil {
return fmt.Errorf("月份格式错误,应为 YYYYMM 格式(如:202512): %v", err)
}
months = []time.Time{parsedTime}
} else {
now := time.Now().UTC()
currentMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC)
for i := 0; i < monthsFlag; i++ {
months = append(months, currentMonth.AddDate(0, -i, 0))
}
}
ctx.Info("开始执行 ANALYZE...")
execAnalyze := func(table string) error {
var sql string
switch dbConnection {
case "mysql":
sql = fmt.Sprintf("ANALYZE TABLE `%s`", table)
case "postgres":
sql = fmt.Sprintf("ANALYZE %s", table)
default:
return fmt.Errorf("unsupported database: %s", dbConnection)
}
_, err := facades.Orm().Query().Exec(sql)
if err != nil {
return err
}
ctx.Info("✓ " + sql)
return nil
}
if analyzeOrders {
for _, m := range months {
table := utils.GetShardingTableName("orders", m)
if facades.Schema().HasTable(table) {
if err := execAnalyze(table); err != nil {
return fmt.Errorf("analyze %s failed: %v", table, err)
}
}
}
}
if analyzeOrderDetails {
for _, m := range months {
table := utils.GetShardingTableName("order_details", m)
if facades.Schema().HasTable(table) {
if err := execAnalyze(table); err != nil {
return fmt.Errorf("analyze %s failed: %v", table, err)
}
}
}
}
if analyzePayments {
if facades.Schema().HasTable("payments") {
if err := execAnalyze("payments"); err != nil {
return fmt.Errorf("analyze payments failed: %v", err)
}
}
}
ctx.Info("完成")
return nil
}