简体   繁体   English

Golang 慢扫描()多行

[英]Golang slow scan() for multiple rows

I am running a query in Golang where I select multiple rows from my Postgresql Database.我在 Golang 中运行一个查询,我从我的 Postgresql 数据库中选择多行。

I am using the following imports for my query我正在为我的查询使用以下导入

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

I have narrowed down to my loop for scanning the results into my struct.我已经缩小到我的循环以将结果扫描到我的结构中。

// 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()

The above code takes about 8 seconds to run, and while the query is fast, the loop in rows.Next() takes the entire 8 seconds over to complete.上面的代码运行大约需要 8 秒,虽然查询速度很快,但 rows.Next() 中的循环需要整个 8 秒才能完成。

Any ideas?有什么想法吗? Am I doing something wrong, or is there a better way?我做错了什么,还是有更好的方法?

My configuration for my database我的数据库配置

// 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)

UPDATE 1:更新1:

I placed print statements in the for loop.我在 for 循环中放置了打印语句。 Below is my updated snippet下面是我更新的片段

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

I noticed that in this loop, it will actually pause half-way, and continue after a short break.我注意到在这个循环中,它实际上会中途暂停,并在短暂休息后继续。 It looks like this:它看起来像这样:

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

and it will happen again later on at another row count, and again after a few hundred records.稍后会在另一行计数时再次发生,并且在几百条记录后再次发生。


UPDATE 2:更新 2:

Below is a snippet of my InfrastructureInit() method下面是我的 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
}

I am not exactly sure what is causing this slowness, but I currently placed a quick patch on my server to using a redis database and precache my infrastructures, saving it as a string.我不确定是什么导致了这种缓慢,但我目前在我的服务器上放置了一个快速补丁,以使用 redis 数据库并预缓存我的基础设施,将其保存为字符串。 It seems to be okay for now, but I now have to maintain both redis and my postgres.现在似乎没问题,但我现在必须同时维护 redis 和我的 postgres。

I am still puzzled over this weird behavior, but I'm not exactly how rows.Next() work - does it make a query to the database everytime I call rows.Next()?我仍然对这种奇怪的行为感到困惑,但我并不完全了解 rows.Next() 是如何工作的 - 每次我调用 rows.Next() 时它是否都会对数据库进行查询?

How do you think about just do like this?你怎么想就这么干?

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)
    }
}

Hope this help.希望这有帮助。

I went some weird path myself while consolidating my understanding of how rows.Next() work and what might be impacting performance so thought about sharing this here for posterity (despite the question asked a long time ago).在巩固我对rows.Next()工作方式以及可能影响性能的理解的同时,我自己走了一些奇怪的道路,所以考虑在这里为后代分享这个(尽管这个问题很久以前提出过)。

Related to:相关:

I am still puzzled over this weird behavior, but I'm not exactly how rows.Next() work - does it make a query to the database everytime I call rows.Next()?我仍然对这种奇怪的行为感到困惑,但我并不完全了解 rows.Next() 是如何工作的 - 每次我调用 rows.Next() 时它是否都会对数据库进行查询?

It doesn't make a 'query' but it reads (transfers) data from the db through a driver on each iteration which means it can be impacted by eg bad network performance.它不会进行“查询”,但会在每次迭代时通过驱动程序从数据库读取(传输)数据,这意味着它可能会受到不良网络性能等的影响。 Especially true if, for example, your db is not local to where you are running your Go code.例如,如果您的数据库不在您运行 Go 代码的本地,则尤其如此。 One approach to confirm whether network performance is an issue would be to run your go app on the same machine where your db is (if possible).确认网络性能是否存在问题的一种方法是在您的数据库所在的同一台机器上运行您的 go 应用程序(如果可能)。

Assuming columns that are scanned in the above code are not of extremely large size or having custom conversions - reading ~400 rows should take in the order of 100ms at most (in a local setup).假设在上述代码中扫描的列不是非常大的大小或具有自定义转换 - 读取约 400 行最多应花费100 毫秒的时间(在本地设置中)。

For example - I had a case where I needed to read about 100k rows with about 300B per row and that was taking ~4s (local setup).例如 - 我有一个案例,我需要读取大约100k行,每行大约300B ,这需要大约 4 秒(本地设置)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM