golang 高性能的 MySQL 数据导出
- 需求
- 导出方式对比
- 方案1:快照导出(耗时:1.5s)
- 方案2: 偏移分页(耗时:4s)
- 方案 3:普通分页(耗时:4min40s)
需求
- 导出 MySQL 数据
分析:
- 一次性 select 大量数据带来的问题
性能问题:
数据库负载:大量数据查询会增加数据库的CPU、内存和I/O负担,可能影响其他操作。
网络传输:大数据量传输会占用大量带宽,导致网络延迟或超时。
内存消耗:
服务器内存: 消耗太大,影响其他业务运行
导出方式对比
- 条件:
- 200 万数据
- 查询全表耗时 3s
方案1:快照导出(耗时:1.5s)
data, err := db.Query("select * from user2")
if err != nil {
log.Fatal("err1:", err)
}
defer data.Close()
columns, err := data.Columns()
if err != nil {
log.Printf("[error] %v \n", err)
}
l := len(columns)
val := &User{}
valPointer := make([]interface{}, l)
valPointer[0] = &val.Id
valPointer[1] = &val.Name
valPointer[2] = &val.Tag
valPointer[3] = &val.Phone
valPointer[4] = &val.Create_time
//计数
num := 0
for data.Next() {
err := data.Scan(valPointer...)
if err != nil {
log.Fatal("err5:", err)
}
}
方案2: 偏移分页(耗时:4s)
// 定义分页参数
starId := 0
pageSize := 2000
// 定义查询条件
var users []User
// 执行分页查询
for {
result := db.Limit(pageSize).Where("id >= ?", starId).Find(&users)
if result.Error != nil {
log.Fatal("err5:", result.Error)
}
if len(users) < pageSize {
break
}
starId = users[len(users)-1].Id
}
方案 3:普通分页(耗时:4min40s)
// 定义分页参数
page := 1
pageSize := 2000
// 导出数据
for {
var users []User
result := db.Offset((page - 1) * pageSize).Limit(pageSize).Find(&users)
if result.Error != nil {
log.Fatal("err5:", result.Error)
}
if len(users) < pageSize {
break
}
page++
}