feat: Native DDL智能推荐 + MySQL版本检测 + 云数据库自动跳过gh-ost
- 新增 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
This commit is contained in:
1 parent
b2b13661fd
commit
78986fe5bf
1 file changed
+77
-14
@@ -143,6 +143,49 @@ func GhOstGetConfig(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, getGhostConfig())
|
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
|
// POST /api/v1/ghost/analyze — analyze DDL and return OSC recommendation
|
||||||
func GhOstAnalyzeDDL(c *gin.Context) {
|
func GhOstAnalyzeDDL(c *gin.Context) {
|
||||||
var req struct {
|
var req struct {
|
||||||
@@ -158,29 +201,49 @@ func GhOstAnalyzeDDL(c *gin.Context) {
|
|||||||
|
|
||||||
analysis := analyzeDDL(req.Alter)
|
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
|
// Also check table row count if instance_id provided
|
||||||
rowCount := -1
|
rowCount := -1
|
||||||
if req.InstanceID > 0 {
|
if req.InstanceID > 0 {
|
||||||
rowCount = getTableRowCount(req.InstanceID, req.Database, req.Table)
|
rowCount = getTableRowCount(req.InstanceID, req.Database, req.Table)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check auto-trigger by row count
|
// Check auto-trigger by row count (only for self-hosted)
|
||||||
triggerRows := getSettingInt("ghost_auto_trigger_rows", 10) * 10000
|
if cloudType == "self_hosted" {
|
||||||
if rowCount >= 0 && rowCount > triggerRows && !analysis.NeedsOSC {
|
triggerRows := getSettingInt("ghost_auto_trigger_rows", 10) * 10000
|
||||||
analysis.NeedsOSC = true
|
if rowCount >= 0 && rowCount > triggerRows && !analysis.NeedsOSC {
|
||||||
analysis.RecommendedTool = "gh-ost"
|
analysis.NeedsOSC = true
|
||||||
analysis.Reason = fmt.Sprintf("表行数(%d)超过阈值(%d),推荐使用 gh-ost", rowCount, triggerRows)
|
analysis.RecommendedTool = "gh-ost"
|
||||||
|
analysis.Reason = fmt.Sprintf("表行数(%d)超过阈值(%d),推荐使用 gh-ost", rowCount, triggerRows)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"enabled": isGhostEnabled(),
|
"enabled": isGhostEnabled(),
|
||||||
"ddl_types": analysis.DDLTypes,
|
"ddl_types": analysis.DDLTypes,
|
||||||
"needs_osc": analysis.NeedsOSC,
|
"needs_osc": analysis.NeedsOSC,
|
||||||
"recommended_tool": analysis.RecommendedTool,
|
"recommended_tool": analysis.RecommendedTool,
|
||||||
"reason": analysis.Reason,
|
"reason": analysis.Reason,
|
||||||
"table_rows": rowCount,
|
"table_rows": rowCount,
|
||||||
"trigger_rows": triggerRows,
|
"mysql_version": mysqlVersion,
|
||||||
"config": getGhostConfig(),
|
"supports_instant": instantDDL,
|
||||||
|
"cloud_type": cloudType,
|
||||||
|
"config": getGhostConfig(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user