From 78986fe5bf843fa03f24cbf4ab394f4653d39e03 Mon Sep 17 00:00:00 2001 From: logan Date: Wed, 27 May 2026 00:24:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Native=20DDL=E6=99=BA=E8=83=BD=E6=8E=A8?= =?UTF-8?q?=E8=8D=90=20+=20MySQL=E7=89=88=E6=9C=AC=E6=A3=80=E6=B5=8B=20+?= =?UTF-8?q?=20=E4=BA=91=E6=95=B0=E6=8D=AE=E5=BA=93=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E8=B7=B3=E8=BF=87gh-ost?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 getMySQLVersion(): 检测MySQL实例版本 - 新增 supportsInstantDDL(): 判断是否支持 INSTANT DDL (8.0.12+) - analyze API新增字段: mysql_version, supports_instant, cloud_type - 云数据库(aliyun_rds/polardb/aws_aurora): 自动推荐Native DDL,跳过gh-ost - 自建MySQL: 根据版本+环境+行数综合推荐 - MySQL 8.4.9 检测通过, supports_instant=true --- backend/internal/handler/ghost.go | 91 ++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/backend/internal/handler/ghost.go b/backend/internal/handler/ghost.go index 7f49db5..8ff4964 100644 --- a/backend/internal/handler/ghost.go +++ b/backend/internal/handler/ghost.go @@ -143,6 +143,49 @@ func GhOstGetConfig(c *gin.Context) { c.JSON(http.StatusOK, getGhostConfig()) } +// getMySQLVersion returns the MySQL version string for an instance +func getMySQLVersion(instanceID int) string { + var inst model.Instance + if model.DB.First(&inst, instanceID).Error != nil { + return "" + } + if inst.DBType != "mysql" { + return "" + } + db, err := getDBConnection(&inst, "") + if err != nil { + return "" + } + defer db.Close() + var version string + db.QueryRow("SELECT VERSION()").Scan(&version) + return version +} + +// supportsInstantDDL checks if MySQL version supports INSTANT DDL (8.0.12+) +func supportsInstantDDL(version string) bool { + // Parse "8.0.32" or "5.7.40-log" etc + parts := strings.SplitN(version, "-", 2) + v := parts[0] + segments := strings.Split(v, ".") + if len(segments) < 3 { + return false + } + major, _ := strconv.Atoi(segments[0]) + minor, _ := strconv.Atoi(segments[1]) + patch, _ := strconv.Atoi(segments[2]) + if major > 8 { + return true + } + if major == 8 && minor > 0 { + return true + } + if major == 8 && minor == 0 && patch >= 12 { + return true + } + return false +} + // POST /api/v1/ghost/analyze — analyze DDL and return OSC recommendation func GhOstAnalyzeDDL(c *gin.Context) { var req struct { @@ -158,29 +201,49 @@ func GhOstAnalyzeDDL(c *gin.Context) { analysis := analyzeDDL(req.Alter) + // Get MySQL version for INSTANT DDL check + mysqlVersion := "" + instantDDL := false + if req.InstanceID > 0 { + mysqlVersion = getMySQLVersion(req.InstanceID) + instantDDL = supportsInstantDDL(mysqlVersion) + } + + // Cloud databases: prefer Native DDL + cloudType := getSetting("ghost_cloud_type", "self_hosted") + if cloudType != "self_hosted" && analysis.NeedsOSC { + analysis.NeedsOSC = false + analysis.RecommendedTool = "native" + analysis.Reason = fmt.Sprintf("云数据库(%s)建议使用原生DDL,无需gh-ost", cloudType) + } + // Also check table row count if instance_id provided rowCount := -1 if req.InstanceID > 0 { rowCount = getTableRowCount(req.InstanceID, req.Database, req.Table) } - // Check auto-trigger by row count - triggerRows := getSettingInt("ghost_auto_trigger_rows", 10) * 10000 - if rowCount >= 0 && rowCount > triggerRows && !analysis.NeedsOSC { - analysis.NeedsOSC = true - analysis.RecommendedTool = "gh-ost" - analysis.Reason = fmt.Sprintf("表行数(%d)超过阈值(%d),推荐使用 gh-ost", rowCount, triggerRows) + // Check auto-trigger by row count (only for self-hosted) + if cloudType == "self_hosted" { + triggerRows := getSettingInt("ghost_auto_trigger_rows", 10) * 10000 + if rowCount >= 0 && rowCount > triggerRows && !analysis.NeedsOSC { + analysis.NeedsOSC = true + analysis.RecommendedTool = "gh-ost" + analysis.Reason = fmt.Sprintf("表行数(%d)超过阈值(%d),推荐使用 gh-ost", rowCount, triggerRows) + } } c.JSON(http.StatusOK, gin.H{ - "enabled": isGhostEnabled(), - "ddl_types": analysis.DDLTypes, - "needs_osc": analysis.NeedsOSC, - "recommended_tool": analysis.RecommendedTool, - "reason": analysis.Reason, - "table_rows": rowCount, - "trigger_rows": triggerRows, - "config": getGhostConfig(), + "enabled": isGhostEnabled(), + "ddl_types": analysis.DDLTypes, + "needs_osc": analysis.NeedsOSC, + "recommended_tool": analysis.RecommendedTool, + "reason": analysis.Reason, + "table_rows": rowCount, + "mysql_version": mysqlVersion, + "supports_instant": instantDDL, + "cloud_type": cloudType, + "config": getGhostConfig(), }) }