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

Go语言使用rows.Next()读取Oracle大字段数据时卡顿问题求助

Go读取Oracle大字段时rows.Next()卡顿/卡死的解决办法

问题根源

你遇到的问题是github.com/sijms/go-ora/v2驱动默认行预取数为25行,当结果包含大体积的TEXT、SOLUTION字段时,每次预取的数据包过大,导致网络传输和内存处理瓶颈,表现为每读25行就停顿,最终因资源耗尽卡死。去掉大字段后数据量骤减,速度自然恢复正常。

可行解决方案

1. 调大预取行数

直接修改查询的预取大小,减少网络交互次数,这是最直接的解决办法。go-ora支持通过FetchSize选项设置预取行数,建议根据网络情况调整为1000-5000行。

2. 分批查询数据

将40万条数据拆分为小批次(比如每次查1万条),避免一次性加载大量大字段数据到内存,同时降低Oracle服务器压力。

3. 分段读取大字段(针对超大型文本)

如果TEXT/SOLUTION字段体积特别大(如超过10MB),可使用Oracle的LOB分段读取功能,不过go-ora需要额外处理,适合极端场景。

代码修改示例

方案1:设置FetchSize

修改GetHrTicketsFromOra函数,通过QueryContext指定预取大小:

import (
    "context"
    "database/sql"
    "log"
    "github.com/sijms/go-ora/v2"
)

func GetHrTicketsFromOra() (*sql.Rows, error) {
    // 设置预取行数为1000,可根据实际情况调整
    fetchOpt := go-ora.FetchSize(1000)
    rows, err := oraDB.QueryContext(context.Background(),
        "select id,STATE_ID,REMEDY_ID,HEADER,CREATE_DATE,TEXT,SOLUTION,SOLUTION_USER_LOGIN,LAST_SOLUTION_DATE from TICKET where SOLUTION_GROUP_ID = 5549",
        fetchOpt,
    )
    if err != nil {
        log.Println("Error while getting rows from Ora:", err)
        return nil, err
    }
    log.Println("Finished legacy tickets export")
    return rows, nil
}

方案2:分批查询

按ID分段拉取数据,避免一次性处理过大结果集:

func GetHrTicketsBatch(batchSize int) ([]util.OraTicket, error) {
    var allTickets []util.OraTicket
    lastID := 0

    for {
        rows, err := oraDB.Query(`
            select id,STATE_ID,REMEDY_ID,HEADER,CREATE_DATE,TEXT,SOLUTION,SOLUTION_USER_LOGIN,LAST_SOLUTION_DATE 
            from TICKET 
            where SOLUTION_GROUP_ID = 5549 and id > ? 
            order by id 
            fetch next ? rows only`,
            lastID, batchSize,
        )
        if err != nil {
            return nil, err
        }

        ticketCount := 0
        for rows.Next() {
            ot := util.OraTicket{}
            err := rows.Scan(&ot.ID, &ot.StateId, &ot.RemedyId, &ot.Header, &ot.CreateDate, &ot.Text, &ot.Solution, &ot.SolutionUserLogin, &ot.LastSolutionDate)
            if err != nil {
                rows.Close()
                return nil, err
            }
            allTickets = append(allTickets, ot)
            lastID = ot.ID
            ticketCount++
        }

        rows.Close()
        if ticketCount < batchSize {
            break // 无更多数据
        }
    }

    return allTickets, nil
}

额外优化点

  • 删除ConvertRows中的log.Println("Reading the ticket"),频繁打日志会严重拖慢读取速度。
  • 给转换通道添加缓冲:例如c := make(chan util.ArchTicket, 200),避免PostgreSQL插入速度慢阻塞Oracle数据读取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 08:27:38