Предположим что у нас есть два коннекта к базе (одной или нескольким, это не важно). Далее используя
io.Pipe() создаём Reader и Writer, и используя CopyTo() и CopyFrom() переносим данные.
r, w := io.Pipe()
doneChan := make(chan struct{}, 1)
go func() {
defer close(doneChan)
_, err := db1.PgConn().CopyTo(ctx, w, `copy table1 to stdin binary`)
if err != nil {
slog.Error("error", "error", err)
return
}
_ = w.Close()
doneChan <- struct{}{}
}()
_, err = db2.PgConn().CopyFrom(ctx, r, `copy table1 from stdout binary`)
_ = r.Close()
select {
case <-doneChan:
case <-ctx.Done():
}
Вся прелесть тут в том что используем наиболее быстрый способ с точки зрения PostgreSQL.
Используя `copy (select * from where ... order by ... limit ...) to stdout `можем регулировать нагрузку на чтение, следить за прогрессом и управлять копированием данных.
В качестве
Reader может выступать что угодно, хоть файл csv, хоть другая СУБД, но тогда данные придётся дополнительно конвертировать в формат понимаемый PostgreSQL - csv или tsv, и использовать copy ... from stdin (format csv).Нюанс:
copy ... from stdin binary , binary обязывает использовать одинаковые типы данных, нельзя будет integer колонку перенести в колонку smallint, если такое требуется, то параметр binary надо опустить.Весь код тут. И ещё немного кода для вдохновения.
@sqlhub
