perf: 优化 N+1 查询,改为批量 IN 查询
- config.go List 方法:配置列表查询应用名称从循环内逐条查询改为批量 IN 查询 - config_api.go recordClientInstances:客户端实例上报从循环内逐条查询+写入改为批量 IN 查询+批量插入
This commit is contained in:
@@ -80,12 +80,40 @@ func (h *ConfigHandler) List(c *gin.Context) {
|
|||||||
total, _ := dao.Engine.Where(whereClause).Count(&model.AppConfig{})
|
total, _ := dao.Engine.Where(whereClause).Count(&model.AppConfig{})
|
||||||
dao.Engine.Where(whereClause).Limit(req.PageSize, (req.PageNo-1)*req.PageSize).Find(&configs)
|
dao.Engine.Where(whereClause).Limit(req.PageSize, (req.PageNo-1)*req.PageSize).Find(&configs)
|
||||||
|
|
||||||
// build app names and client counts
|
// build app names (batch query) and collect configIds for client counts
|
||||||
configIds := make([]int, 0, len(configs))
|
configIds := make([]int, 0, len(configs))
|
||||||
|
appIds := make(map[int]bool)
|
||||||
for i := range configs {
|
for i := range configs {
|
||||||
configs[i].AppNames = h.buildAppNames(&configs[i])
|
if configs[i].AppId != nil && *configs[i].AppId > 0 {
|
||||||
|
appIds[*configs[i].AppId] = true
|
||||||
|
}
|
||||||
configIds = append(configIds, configs[i].Id)
|
configIds = append(configIds, configs[i].Id)
|
||||||
}
|
}
|
||||||
|
if len(appIds) > 0 {
|
||||||
|
idList := make([]int, 0, len(appIds))
|
||||||
|
for id := range appIds {
|
||||||
|
idList = append(idList, id)
|
||||||
|
}
|
||||||
|
var apps []model.Application
|
||||||
|
dao.Engine.In("id", idList).Find(&apps)
|
||||||
|
appMap := make(map[int]string, len(apps))
|
||||||
|
for _, app := range apps {
|
||||||
|
appMap[app.Id] = app.Name + "(" + app.Code + ")"
|
||||||
|
}
|
||||||
|
for i := range configs {
|
||||||
|
if configs[i].Global || configs[i].AppId == nil || *configs[i].AppId == 0 {
|
||||||
|
configs[i].AppNames = "全局配置"
|
||||||
|
} else {
|
||||||
|
configs[i].AppNames = appMap[*configs[i].AppId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := range configs {
|
||||||
|
if configs[i].Global || configs[i].AppId == nil || *configs[i].AppId == 0 {
|
||||||
|
configs[i].AppNames = "全局配置"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// batch query client counts
|
// batch query client counts
|
||||||
if len(configIds) > 0 {
|
if len(configIds) > 0 {
|
||||||
type countResult struct {
|
type countResult struct {
|
||||||
|
|||||||
@@ -214,18 +214,29 @@ func (h *ConfigApiHandler) recordClientInstances(ip string, configIds []int, app
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
|
// 批量查询已存在的记录
|
||||||
|
var existingList []model.ClientInstance
|
||||||
|
dao.Engine.Where("app_name = ? AND env = ? AND ip = ?", appName, env, ip).
|
||||||
|
In("app_config_id", configIds).
|
||||||
|
Find(&existingList)
|
||||||
|
|
||||||
|
existingMap := make(map[int]*model.ClientInstance, len(existingList))
|
||||||
|
for i := range existingList {
|
||||||
|
existingMap[existingList[i].AppConfigId] = &existingList[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
var toInsert []model.ClientInstance
|
||||||
for _, configId := range configIds {
|
for _, configId := range configIds {
|
||||||
var existing model.ClientInstance
|
if existing, ok := existingMap[configId]; ok {
|
||||||
has, _ := dao.Engine.Where("app_config_id = ? AND app_name = ? AND env = ? AND ip = ?", configId, appName, env, ip).Get(&existing)
|
|
||||||
if has {
|
|
||||||
existing.LastPingAt = &now
|
existing.LastPingAt = &now
|
||||||
existing.UpdatedAt = &now
|
existing.UpdatedAt = &now
|
||||||
if fetchType != "" {
|
if fetchType != "" {
|
||||||
existing.LastFetchAt = &now
|
existing.LastFetchAt = &now
|
||||||
existing.LastFetchType = fetchType
|
existing.LastFetchType = fetchType
|
||||||
dao.Engine.ID(existing.Id).Cols("last_ping_at", "last_fetch_at", "last_fetch_type", "updated_at").Update(&existing)
|
dao.Engine.ID(existing.Id).Cols("last_ping_at", "last_fetch_at", "last_fetch_type", "updated_at").Update(existing)
|
||||||
} else {
|
} else {
|
||||||
dao.Engine.ID(existing.Id).Cols("last_ping_at", "updated_at").Update(&existing)
|
dao.Engine.ID(existing.Id).Cols("last_ping_at", "updated_at").Update(existing)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
instance := model.ClientInstance{
|
instance := model.ClientInstance{
|
||||||
@@ -241,11 +252,13 @@ func (h *ConfigApiHandler) recordClientInstances(ip string, configIds []int, app
|
|||||||
instance.LastFetchAt = &now
|
instance.LastFetchAt = &now
|
||||||
instance.LastFetchType = fetchType
|
instance.LastFetchType = fetchType
|
||||||
}
|
}
|
||||||
_, err := dao.Engine.Insert(&instance)
|
toInsert = append(toInsert, instance)
|
||||||
if err != nil {
|
}
|
||||||
logger.SugaredLogger.Errorf("[recordClientInstances] insert error: %v", err)
|
}
|
||||||
continue
|
|
||||||
}
|
if len(toInsert) > 0 {
|
||||||
|
if _, err := dao.Engine.Insert(&toInsert); err != nil {
|
||||||
|
logger.SugaredLogger.Errorf("[recordClientInstances] batch insert error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user