使用 pgx 在 GO 中的 Postgres 中批量插入

Ans*_*Rex 9 postgresql go pgx

我正在尝试在 go 中的 db 中批量插入键,这里是代码 Key Struct

type tempKey struct {
keyVal  string
lastKey int
Run Code Online (Sandbox Code Playgroud)

}

测试键

data := []tempKey{
    {keyVal: "abc", lastKey: 10},
    {keyVal: "dns", lastKey: 11},
    {keyVal: "qwe", lastKey: 12},
    {keyVal: "dss", lastKey: 13},
    {keyVal: "xcmk", lastKey: 14},
}
Run Code Online (Sandbox Code Playgroud)

插入部分

dbUrl := "db url...."
conn, err := pgx.Connect(context.Background(), dbUrl)
if err != nil {
    println("Errrorr...")
}
defer conn.Close(context.Background())
sqlStr := "INSERT INTO keys (keyval,lastval) VALUES "
dollars := ""
vals := []interface{}{}
count := 1
for _, row := range data {
    dollars = fmt.Sprintf("%s($%d, $%d),", dollars, count, count+1)
    vals = append(vals, row.keyVal, row.lastKey)
    count += 2
}
sqlStr += dollars
sqlStr = sqlStr[0 : len(sqlStr)-1]
fmt.Printf("%s \n", sqlStr)

_, erro := conn.Exec(context.Background(), sqlStr, vals)
if erro != nil {
    fmt.Fprint(os.Stderr, "Error : \n", erro)
}
Run Code Online (Sandbox Code Playgroud)

运行时会抛出错误:预期 10 个参数,得到 1

批量插入的正确方法是什么?

col*_*tor 23

您正在手工编写 SQL 语句,这很好,但您没有利用pgx这可以帮助实现这一点(见下文)。

对于大型输入,像这样附加到 SQL 字符串可能效率低下

dollars = fmt.Sprintf("%s($%d, $%d),", dollars, count, count+1)
Run Code Online (Sandbox Code Playgroud)

而且最终值还有一个尾随,,您需要一个终止字符;来指示语句的结束。

顺便说一句,这个字符串截断行是多余的:

sqlStr = sqlStr[0 : len(sqlStr)-1] // this is a NOOP
Run Code Online (Sandbox Code Playgroud)

无论如何,在制作长字符串时,最好使用像strings.Builder这样性能更高的东西。


pgx文档中,使用pgx.Conn.CopyFrom

func (c *Conn) CopyFrom(tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int, error)
Run Code Online (Sandbox Code Playgroud)

CopyFrom 使用 PostgreSQL 复制协议来执行批量数据插入。它返回复制的行数和错误。

复制的用法示例

rows := [][]interface{}{
    {"John", "Smith", int32(36)},
    {"Jane", "Doe", int32(29)},
}

copyCount, err := conn.CopyFrom(
    pgx.Identifier{"people"},
    []string{"first_name", "last_name", "age"},
    pgx.CopyFromRows(rows),
)
Run Code Online (Sandbox Code Playgroud)

  • @AnswerRex,根据表结构,这可能是 CopyFrom 上的 PK 违规。如果是你的情况,那么在会话上创建临时表,在那里批量插入,然后执行“在冲突时从临时表中选择到维护表,不执行任何操作”。请参阅以下详细信息:/sf/ask/976312921/ (3认同)

ser*_*e-v 16

使用批处理(https://github.com/jackc/pgx/blob/master/batch_test.go):

batch := &pgx.Batch{}
batch.Queue("insert into ledger(description, amount) values($1, $2)", "q1", 1)
batch.Queue("insert into ledger(description, amount) values($1, $2)", "q2", 2)
br := conn.SendBatch(context.Background(), batch)
Run Code Online (Sandbox Code Playgroud)