簡體   English   中英

Golang 慢掃描()多行

[英]Golang slow scan() for multiple rows

我在 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 循環中放置了打印語句。 下面是我更新的片段

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() 時它是否都會對數據庫進行查詢?

你怎么想就這么干?

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

希望這有幫助。

在鞏固我對rows.Next()工作方式以及可能影響性能的理解的同時,我自己走了一些奇怪的道路,所以考慮在這里為后代分享這個(盡管這個問題很久以前提出過)。

相關:

我仍然對這種奇怪的行為感到困惑,但我並不完全了解 rows.Next() 是如何工作的 - 每次我調用 rows.Next() 時它是否都會對數據庫進行查詢?

它不會進行“查詢”,但會在每次迭代時通過驅動程序從數據庫讀取(傳輸)數據,這意味着它可能會受到不良網絡性能等的影響。 例如,如果您的數據庫不在您運行 Go 代碼的本地,則尤其如此。 確認網絡性能是否存在問題的一種方法是在您的數據庫所在的同一台機器上運行您的 go 應用程序(如果可能)。

假設在上述代碼中掃描的列不是非常大的大小或具有自定義轉換 - 讀取約 400 行最多應花費100 毫秒的時間(在本地設置中)。

例如 - 我有一個案例,我需要讀取大約100k行,每行大約300B ,這需要大約 4 秒(本地設置)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM