首页 > 解决方案 > 如何将巨大的 csv 数据(4GB)转储到 mysql 中

问题描述

如果有人在使用 Go 之前尝试过这个,请用代码来理解这个想法,那将非常感激。

我写了几行很慢

// 这是读取csv文件

func usersFileLoader(filename string, channel chan User) {
    defer close(channel)
    file, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer file.Close()
    var user User
    reader := csv.NewReader(file)
    for {
        err := Unmarshal(reader, &user)
        if err == io.EOF {
            break
        }
        if err != nil {
            panic(err)
        }
        channel <- user
    }
}

// 这是插入csv文件

func saveUser(channel <-chan User, db *sql.DB) {
    stmt, err := db.Prepare(`
        INSERT INTO Users( id, name, address) values ( ?, ?, ?)`)
    if err != nil {
        log.Fatal(err)
    }

    for usr := range channel {
        _, err := stmt.Exec(
            usr.ID,
            usr.Name,
            usr.Address,
        )
        if err != nil {
            log.Fatal(err)
        }
    }
}

// 这里是用户的结构体

type User struct {
    ID      int `csv:"id"`
    Name    int `csv:"name"`
    Address int `csv:"address"`
}

// 这是我的主要功能

func main() {
    db := DBconnect(ConnectionString(dbConfig()))
    channel := make(chan User)
    go usersFileLoader("../user.csv", channel)
    saveUser(channel, db)
    defer db.Close()
}

// 这段代码可以工作,但对我来说很慢。分享您的想法和想法

标签: go

解决方案


我不会尝试使用 Go 内置的标准库函数将非常大的 CSV 文件加载到 MySQL 中(当然,除非您只是想了解它们是如何工作的)。

为了获得最佳性能,我将简单地使用MySQL 的内置LOAD DATA INFILE功能。

例如:

result, err := db.Exec("LOAD DATA INFILE ?", filename)
if err != nil {
    log.Fatal(err)
}
log.Printf("%d rows inserted\n", result.RowsAffected())

如果您以前没有使用过 LOAD DATA INFILE,请仔细注意有关 LOCAL 的文档。根据您的服务器配置和权限,您可能需要改用 LOAD DATA LOCAL INFILE。(例如,如果您打算使用 Docker 容器,则绝对需要使用 LOCAL。)


推荐阅读