You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang中基于API返回数据关联数据库表的优化实现问询

优化Golang数据合并方案的建议

问题背景

现有数据库表结构如下:

Industry表

industry_idname
1industry A
2industry B

Guide表

industry_idguide_idname
11guide A
12guide B
13guide C
14guide D
211guide E

此前依赖Summary表关联查询获取目标格式数据,原简化SQL存在语法错误,修正后如下:

select s.industry_id, 
       case when s.guide_id is null then null else g.guide_id end as guide_id,
       case when s.guide_id is null then i.name else g.name end as name,
       s.uuid,
       case when s.guide_id is null then null else (uuid of parent) end as parent_uuid
from summary s
left join industry i on s.industry_id = i.industry_id
left join guide g on s.industry_id = g.industry_id and s.guide_id = g.guide_id
where s.industry_id = 4;

现在无法使用Summary表,需改用API接口获取基础数据,API返回示例:

[ 
{
"industry_id": 1,
"guide_id": null,
"uuid": "AAAA"
},
{
"industry_id": 1,
"guide_id": 1,
"uuid": "BBBB"
},
{
"industry_id": 1,
"guide_id": 2,
"uuid": "CCCC"
},
{
"industry_id": 1,
"guide_id": 3,
"uuid": "DDDD"
}
]

当前设想的Golang实现步骤:

  • 调用API获取响应数据;
  • 提取响应中的guide_id列表;
  • 执行SQL查询Guide表信息:select * from guide where industry_id=4 and guide_id in (<步骤2生成的列表>);
  • 执行SQL查询Industry表信息:select * from industry where industry_id=4;
  • 将步骤4的记录合并到步骤3的结果中;
  • 补充API返回的UUID信息后返回最终结果。

希望找到更简洁、优雅的实现方式。


优化实现方案

1. 合并数据库查询,减少交互次数

把Industry和Guide的查询用UNION ALL合并成一次SQL请求,避免两次数据库调用,降低开销:

SELECT industry_id, guide_id, name 
FROM guide 
WHERE industry_id = 4 AND guide_id IN (<提取的非空guide_id列表>)
UNION ALL
SELECT industry_id, NULL AS guide_id, name 
FROM industry 
WHERE industry_id = 4;

如果API返回的guide_id存在重复,先对其去重再生成IN列表,可以进一步缩小查询范围。

2. 构建内存映射,高效匹配数据

在Golang中,将数据库查询结果转换成键值对映射,遍历API返回数据时直接匹配,避免多次循环查找:

// 定义映射的键结构体,用指针区分guide_id的null和0值
type NameMapKey struct {
    IndustryID int
    GuideID    *int
}

// 定义数据库查询结果的结构体
type DBNameItem struct {
    IndustryID int    `db:"industry_id"`
    GuideID    *int   `db:"guide_id"`
    Name       string `db:"name"`
}

// 定义最终返回的结构体
type FinalResult struct {
    IndustryID int     `json:"industry_id"`
    GuideID    *int    `json:"guide_id"`
    Name       string  `json:"name"`
    UUID       string  `json:"uuid"`
    ParentUUID *string `json:"parent_uuid"`
}

func processData(apiResponse []APIData) ([]FinalResult, error) {
    // 1. 提取API中的非空guide_id并去重
    guideIDs := make(map[int]struct{})
    var industryID int
    for _, item := range apiResponse {
        industryID = item.IndustryID
        if item.GuideID != nil {
            guideIDs[*item.GuideID] = struct{}{}
        }
    }

    // 2. 生成IN列表的参数,执行合并后的SQL查询
    idList := make([]int, 0, len(guideIDs))
    for id := range guideIDs {
        idList = append(idList, id)
    }

    var dbItems []DBNameItem
    query := `
        SELECT industry_id, guide_id, name 
        FROM guide 
        WHERE industry_id = $1 AND guide_id = ANY($2)
        UNION ALL
        SELECT industry_id, NULL AS guide_id, name 
        FROM industry 
        WHERE industry_id = $1;
    `
    if err := db.Select(&dbItems, query, industryID, idList); err != nil {
        return nil, err
    }

    // 3. 构建名称映射字典
    nameMap := make(map[NameMapKey]string)
    for _, item := range dbItems {
        key := NameMapKey{
            IndustryID: item.IndustryID,
            GuideID:    item.GuideID,
        }
        nameMap[key] = item.Name
    }

    // 4. 遍历API数据,组装最终结果
    finalResults := make([]FinalResult, 0, len(apiResponse))
    for _, apiItem := range apiResponse {
        key := NameMapKey{
            IndustryID: apiItem.IndustryID,
            GuideID:    apiItem.GuideID,
        }
        name := nameMap[key]

        var parentUUID *string
        if apiItem.GuideID != nil {
            // 根据业务逻辑获取父UUID,比如从缓存或其他映射中获取
            parentUUIDVal := "父UUID示例值"
            parentUUID = &parentUUIDVal
        }

        finalResults = append(finalResults, FinalResult{
            IndustryID: apiItem.IndustryID,
            GuideID:    apiItem.GuideID,
            Name:       name,
            UUID:       apiItem.UUID,
            ParentUUID: parentUUID,
        })
    }

    return finalResults, nil
}

3. 可选优化:并发执行API请求与数据库查询

如果API请求和数据库查询的参数仅依赖industry_id(无需先获取API返回的guide_id),可以用goroutine并发执行两个操作,减少整体处理耗时:

func fetchDataConcurrently(industryID int) ([]APIData, []DBNameItem, error) {
    var apiResp []APIData
    var dbItems []DBNameItem
    errChan := make(chan error, 2)

    // 并发调用API
    go func() {
        resp, err := callAPI(industryID)
        if err != nil {
            errChan <- err
            return
        }
        apiResp = resp
        errChan <- nil
    }()

    // 并发查询数据库
    go func() {
        items, err := queryDB(industryID)
        if err != nil {
            errChan <- err
            return
        }
        dbItems = items
        errChan <- nil
    }()

    // 等待两个任务完成
    for i := 0; i < 2; i++ {
        if err := <-errChan; err != nil {
            return nil, nil, err
        }
    }
    return apiResp, dbItems, nil
}

内容的提问来源于stack exchange,提问作者Erdinc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:12:05