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:

Я поместил операторы print в цикл 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()?

2 ответа

Как вы думаете о том, чтобы просто так?

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

Он не выполняет `` запрос '', но он читает (передает) данные из БД через драйвер на каждой итерации, что означает, что на него могут повлиять, например, плохая производительность сети, если, например, ваш БД не является локальным для того места, где вы запускаете свой Go код. Один из способов подтвердить, что ваше приложение go будет запущено на том же компьютере, где находится ваша база данных.

Предполагая, что столбцы, которые сканируются в приведенном выше коде, не имеют очень большого размера и не имеют настраиваемых преобразований - чтение ~400 строк должно занять не более 100 мс (при локальной настройке).

Например, у меня был случай, когда мне нужно было прочитать около 100 тыс. Строк примерно по 300 байт на строку, и это заняло ~4 с (локальная настройка).

Другие вопросы по тегам