Golang慢扫描()多行

时间:2017-05-25 16:28:41

标签: postgresql loops go pq

我在Golang中运行一个查询,我从Postgresql数据库中选择了多行。

我正在使用以下导入进行查询

"database/sql"
"github.com/lib/pq"

我已经缩小到我的循环,将结果扫描到我的结构中。

// Returns about 400 rows
rows, err = db.Query('SELECT * FROM infrastructure')
if err != nil {
    return nil, err
}

var arrOfInfra []model.Infrastructure
for rows.Next() {
    obj, ptrs := model.InfrastructureInit()
    rows.Scan(ptrs...)
    arrOfInfra = append(arrOfInfra, *obj)
}
rows.Close()

上面的代码大约需要8秒才能运行,而且查询速度很快时,rows.Next()中的循环需要整整8秒才能完成。

有什么想法吗?我做错了什么,还是有更好的方法?

我的数据库配置

// host, port, dbname, user, password masked for obvious reasons
db, err := sql.Open("postgres", "host=... port=... dbname=... user=... password=... sslmode=require")
if err != nil {
    panic(err)
}

// I have tried using the default, or setting to high number (100), but it doesn't seem to help with my situation
db.SetMaxIdleConns(1)
db.SetMaxOpenConns(1)

更新1:

我在for循环中放置了print语句。以下是我更新的代码段

for rows.Next() {
    obj, ptrs := model.InfrastructureInit()
    rows.Scan(ptrs...)
    arrOfInfra = append(arrOfInfra, *obj)
    fmt.Println("Len: " + fmt.Sprint(len(arrOfInfra)))
    fmt.Println(obj)
}

我注意到在这个循环中,它实际上会暂停一半,并在短暂休息后继续。它看起来像这样:

Len: 221
Len: 222
Len: 223
Len: 224
<a short pause about 1 second, then prints Len: 225 and continues>
Len: 226
Len: 227
...
..
.

它将在稍后的另一行计数中再次发生,并且在几百条记录之后再次发生。

更新2:

以下是我的InfrastructureInit()方法的片段

func InfrastructureInit() (*Infrastructure, []interface{}) {
    irf := new(Infrastructure)
    var ptrs []interface{}
    ptrs = append(ptrs,
        &irf.Base.ID,
        &irf.Base.CreatedAt,
        &irf.Base.UpdatedAt,
        &irf.ListingID,
        &irf.AddressID,
        &irf.Type,
        &irf.Name,
        &irf.Description,
        &irf.Details,
        &irf.TravellingFor,
    )
    return irf, ptrs
}

我不确定导致这种缓慢的原因,但我目前在我的服务器上安装了一个快速补丁,使用redis数据库并预先处理我的基础设施,将其保存为字符串。它现在似乎没问题,但我现在必须保持redis和postgres。

我仍然对这种奇怪的行为感到困惑,但我并不完全知道rows.Next()是如何工作的 - 每当我调用rows.Next()时它是否会对数据库进行查询?

2 个答案:

答案 0 :(得分:0)

您如何看待这样的事情?

defer rows.Close()

var arrOfInfra []*Infrastructure
for rows.Next() {
    irf := &Infrastructure{}

    err = rows.Scan(
        &irf.Base.ID,
        &irf.Base.CreatedAt,
        &irf.Base.UpdatedAt,
        &irf.ListingID,
        &irf.AddressID,
        &irf.Type,
        &irf.Name,
        &irf.Description,
        &irf.Details,
        &irf.TravellingFor,
    ) 

    if err == nil {
        arrOfInfra = append(arrOfInfra, irf)
    }
}

希望获得帮助。

答案 1 :(得分:0)

在巩固我对 nil 的工作方式以及可能影响性能的因素的理解的同时,我自己走了一些奇怪的道路,因此考虑在此分享给后代(尽管这个问题很久以前就提出了)。

相关:

<块引用>

我仍然对这种奇怪的行为感到困惑,但我不太清楚 rows.Next() 工作 - 每次我都会查询数据库吗? 调用rows.Next()?

它不会进行“查询”,但会在每次迭代时通过驱动程序从数据库读取(传输)数据,这意味着它可能会受到例如网络性能不好。例如,如果您的数据库不在您运行 Go 代码的本地,则尤其如此。 确认网络性能是否存在问题的一种方法是在您的数据库所在的同一台机器上运行您的 go 应用程序(如果可能)。

假设在上述代码中扫描的列不是非常大的大小或具有自定义转换 - 读取约 400 行应该最多需要 100 毫秒(在本地设置中)。

例如 - 我有一个案例,我需要读取大约 100k 行,每行大约 300B,这需要大约 4 秒(本地设置)。