복붙노트

[SQL] 어떻게 패키지 데이터베이스 / SQL과 I 배치 SQL 문

SQL

어떻게 패키지 데이터베이스 / SQL과 I 배치 SQL 문

어떻게 이동 데이터베이스 / SQL 패키지 I 배치 SQL 문은 무엇입니까?

자바에서 나는 이런 식으로 할 것입니다 :

// Create a prepared statement
String sql = "INSERT INTO my_table VALUES(?)";
PreparedStatement pstmt = connection.prepareStatement(sql);

// Insert 10 rows of data
for (int i=0; i<10; i++) {
    pstmt.setString(1, ""+i);
    pstmt.addBatch();
}

// Execute the batch
int [] updateCounts = pstmt.executeBatch();

어떻게 이동에서 동일한을 달성 것인가?

해결법

  1. ==============================

    1.db.Exec 기능이 가변이기 때문에, 하나의 옵션은 (실제로 단 하나의 네트워크 왕복을 않습니다) 문을 직접 구성하고 인수를 폭발하고 그들을 전달하는 것입니다.

    db.Exec 기능이 가변이기 때문에, 하나의 옵션은 (실제로 단 하나의 네트워크 왕복을 않습니다) 문을 직접 구성하고 인수를 폭발하고 그들을 전달하는 것입니다.

    샘플 코드 :

    func BulkInsert(unsavedRows []*ExampleRowStruct) error {
        valueStrings := make([]string, 0, len(unsavedRows))
        valueArgs := make([]interface{}, 0, len(unsavedRows) * 3)
        for _, post := range unsavedRows {
            valueStrings = append(valueStrings, "(?, ?, ?)")
            valueArgs = append(valueArgs, post.Column1)
            valueArgs = append(valueArgs, post.Column2)
            valueArgs = append(valueArgs, post.Column3)
        }
        stmt := fmt.Sprintf("INSERT INTO my_sample_table (column1, column2, column3) VALUES %s", 
                            strings.Join(valueStrings, ","))
        _, err := db.Exec(stmt, valueArgs...)
        return err
    }
    

    간단한 테스트 I 달렸다에서,이 솔루션은 약 4 배 빠른 속도로보다 10,000 행을 삽입에있는 다른 답변을 제시 커밋, 준비, 시작 - 실제 개선 등 개별 설정, 네트워크 대기 시간에 많이 의존한다하더라도

  2. ==============================

    2.당신의 PostgreSQL을 사용하는 경우 다음 PQ 지원 수입을 일괄.

    당신의 PostgreSQL을 사용하는 경우 다음 PQ 지원 수입을 일괄.

  3. ==============================

    3.PostgreSQL를위한 앤드류의 솔루션을 적응의를하는 지원하지 않습니다? 다음 작품, 자리 표시 자 :

    PostgreSQL를위한 앤드류의 솔루션을 적응의를하는 지원하지 않습니다? 다음 작품, 자리 표시 자 :

    func BulkInsert(unsavedRows []*ExampleRowStruct) error {
        valueStrings := make([]string, 0, len(unsavedRows))
        valueArgs := make([]interface{}, 0, len(unsavedRows) * 3)
        i := 0
        for _, post := range unsavedRows {
            valueStrings = append(valueStrings, fmt.Sprintf("($%d, $%d, $%d)", i*3+1, i*3+2, i*3+3))
            valueArgs = append(valueArgs, post.Column1)
            valueArgs = append(valueArgs, post.Column2)
            valueArgs = append(valueArgs, post.Column3)
            i++
        }
        stmt := fmt.Sprintf("INSERT INTO my_sample_table (column1, column2, column3) VALUES %s", strings.Join(valueStrings, ","))
        _, err := db.Exec(stmt, valueArgs...)
        return err
    }
    
  4. ==============================

    4.아비 아마의 대답에 확장, 내 INSERT에 ON CONFLICT DO UPDATE 절을 필요로했다.

    아비 아마의 대답에 확장, 내 INSERT에 ON CONFLICT DO UPDATE 절을 필요로했다.

    이에 대한 해결책은 (트랜잭션의 끝에서 삭제하도록 설정) 후 영구 테이블에 임시 테이블에서 INSERT 임시 테이블에 복사하는 것입니다.

    저는 여기에 정착 코드는 다음과 같습니다

    func (fdata *FDataStore) saveToDBBulk(items map[fdataKey][]byte) (err error) {
        tx, err := fdata.db.Begin()
        if err != nil {
            return errors.Wrap(err, "begin transaction")
        }
        txOK := false
        defer func() {
            if !txOK {
                tx.Rollback()
            }
        }()
    
        // The ON COMMIT DROP clause at the end makes sure that the table
        // is cleaned up at the end of the transaction.
        // While the "for{..} state machine" goroutine in charge of delayed
        // saving ensures this function is not running twice at any given time.
        _, err = tx.Exec(sqlFDataMakeTempTable)
        // CREATE TEMPORARY TABLE fstore_data_load
        // (map text NOT NULL, key text NOT NULL, data json)
        // ON COMMIT DROP
        if err != nil {
            return errors.Wrap(err, "create temporary table")
        }
    
        stmt, err := tx.Prepare(pq.CopyIn(_sqlFDataTempTableName, "map", "key", "data"))
        for key, val := range items {
            _, err = stmt.Exec(string(key.Map), string(key.Key), string(val))
            if err != nil {
                return errors.Wrap(err, "loading COPY data")
            }
        }
    
        _, err = stmt.Exec()
        if err != nil {
            return errors.Wrap(err, "flush COPY data")
        }
        err = stmt.Close()
        if err != nil {
            return errors.Wrap(err, "close COPY stmt")
        }
    
        _, err = tx.Exec(sqlFDataSetFromTemp)
        // INSERT INTO fstore_data (map, key, data)
        // SELECT map, key, data FROM fstore_data_load
        // ON CONFLICT DO UPDATE SET data = EXCLUDED.data
        if err != nil {
            return errors.Wrap(err, "move from temporary to real table")
        }
    
        err = tx.Commit()
        if err != nil {
            return errors.Wrap(err, "commit transaction")
        }
        txOK = true
        return nil
    }
    
  5. ==============================

    5.다음은 포스트 그레스를 사용하는 경우 @Debasish 미트라의 솔루션에 걸릴 수 있습니다.

    다음은 포스트 그레스를 사용하는 경우 @Debasish 미트라의 솔루션에 걸릴 수 있습니다.

    기능 예 : https://play.golang.org/p/dFFD2MrEy3J

    대체 예 : https://play.golang.org/p/vUtW0K4jVMd

    data := []Person{{"John", "Doe", 27}, {"Leeroy", "Jenkins", 19}}
    
    vals := []interface{}{}
    for _, row := range data {
        vals = append(vals, row.FirstName, row.LastName, row.Age)
    }
    
    sqlStr := `INSERT INTO test(column1, column2, column3) VALUES %s`
    sqlStr = ReplaceSQL(sqlStr, "(?, ?, ?)", len(data))
    
    //Prepare and execute the statement
    stmt, _ := db.Prepare(sqlStr)
    res, _ := stmt.Exec(vals...)
    

    FUNC ReplaceSQL

    func ReplaceSQL(stmt, pattern string, len int) string {
        pattern += ","
        stmt = fmt.Sprintf(stmt, strings.Repeat(pattern, len))
        n := 0
        for strings.IndexByte(stmt, '?') != -1 {
            n++
            param := "$" + strconv.Itoa(n)
            stmt = strings.Replace(stmt, "?", param, 1)
        }
        return strings.TrimSuffix(stmt, ",")
    }
    
  6. ==============================

    6.포스트 그레스 LIB PQ 지원을 위해 삽입을 일괄 : https://godoc.org/github.com/lib/pq#hdr-Bulk_imports

    포스트 그레스 LIB PQ 지원을 위해 삽입을 일괄 : https://godoc.org/github.com/lib/pq#hdr-Bulk_imports

    그러나 같은 코드 아래를 통해 달성하지만 정말 도움이 어디 한 시도가 대량 조건 업데이트를 수행 (따라 쿼리를 변경) 할 때입니다 수 있습니다.

    포스트 그레스 유사한 대량 삽입을 수행하려면, 다음과 같은 기능을 사용할 수 있습니다.

    // ReplaceSQL replaces the instance occurrence of any string pattern with an increasing $n based sequence
    func ReplaceSQL(old, searchPattern string) string {
       tmpCount := strings.Count(old, searchPattern)
       for m := 1; m <= tmpCount; m++ {
          old = strings.Replace(old, searchPattern, "$"+strconv.Itoa(m), 1)
       }
       return old
    }
    

    그래서 위의 샘플이된다

    sqlStr := "INSERT INTO test(n1, n2, n3) VALUES "
    vals := []interface{}{}
    
    for _, row := range data {
       sqlStr += "(?, ?, ?)," // Put "?" symbol equal to number of columns
       vals = append(vals, row["v1"], row["v2"], row["v3"]) // Put row["v{n}"] blocks equal to number of columns
    }
    
    //trim the last ,
    sqlStr = strings.TrimSuffix(sqlStr, ",")
    
    //Replacing ? with $n for postgres
    sqlStr = ReplaceSQL(sqlStr, "?")
    
    //prepare the statement
    stmt, _ := db.Prepare(sqlStr)
    
    //format all vals at once
    res, _ := stmt.Exec(vals...)
    
  7. ==============================

    7.일괄 처리는 데이터베이스 / SQL에서 사용할 수있는 인터페이스를 통해 할 수 없습니다. 특정 데이터베이스 드라이버는하지만, 별도로 지원할 수 있습니다. 예를 들어 https://github.com/ziutek/mymysql은 MySQL과 배치를 지원하기 위해 나타납니다.

    일괄 처리는 데이터베이스 / SQL에서 사용할 수있는 인터페이스를 통해 할 수 없습니다. 특정 데이터베이스 드라이버는하지만, 별도로 지원할 수 있습니다. 예를 들어 https://github.com/ziutek/mymysql은 MySQL과 배치를 지원하기 위해 나타납니다.

  8. ==============================

    8.앤드류 C의 아이디어를 가지고 SQL 스칼라 변수를 사용하여 내 작업의 필요를 위해 적응. 그것은 내 작품의 특정 요구 사항에 대해 완벽하게 작동합니다. 이 golang에서 SQL의 일괄 거래를 시뮬레이션하는 데 유용하기 때문에 어쩌면 누군가에게 유용합니다. 즉, 생각입니다.

    앤드류 C의 아이디어를 가지고 SQL 스칼라 변수를 사용하여 내 작업의 필요를 위해 적응. 그것은 내 작품의 특정 요구 사항에 대해 완벽하게 작동합니다. 이 golang에서 SQL의 일괄 거래를 시뮬레이션하는 데 유용하기 때문에 어쩌면 누군가에게 유용합니다. 즉, 생각입니다.

    func BulkInsert(unsavedRows []*ExampleRowStruct) error {
        valueStrings := make([]string, 0, len(unsavedRows))
        valueArgs := make([]interface{}, 0, len(unsavedRows) * 3)
        i := 0
        for _, post := range unsavedRows {
            valueStrings = append(valueStrings, fmt.Sprintf("(@p%d, @p%d, @p%d)", i*3+1, i*3+2, i*3+3))
            valueArgs = append(valueArgs, post.Column1)
            valueArgs = append(valueArgs, post.Column2)
            valueArgs = append(valueArgs, post.Column3)
            i++
        }
        sqlQuery := fmt.Sprintf("INSERT INTO my_sample_table (column1, column2, column3) VALUES %s", strings.Join(valueStrings, ","))
    
        var params []interface{}
    
        for i := 0; i < len(valueArgs); i++ {
            var param sql.NamedArg
            param.Name = fmt.Sprintf("p%v", i+1)
            param.Value = valueArgs[i]
            params = append(params, param)
        }
    
        _, err := db.Exec(sqlQuery, params...)
        return err
    }
    
  9. ==============================

    9.체인 구문을 보는 또 하나 개의 좋은 도서관은 이동-페이지입니다

    체인 구문을 보는 또 하나 개의 좋은 도서관은 이동-페이지입니다

    https://github.com/go-pg/pg/wiki/Writing-Queries#insert

    단일 쿼리로 여러 권의 책을 삽입합니다 :

    err := db.Model(book1, book2).Insert()
    
  10. ==============================

    10.여기 @ 앤드류-C와 @mastercarl에서 응답에 따라 쿼리 및 값 인수를 생성하는 더 일반적인 버전입니다 :

    여기 @ 앤드류-C와 @mastercarl에서 응답에 따라 쿼리 및 값 인수를 생성하는 더 일반적인 버전입니다 :

    // 대량 / insert.go

    import (
        "strconv"
        "strings"
    )
    
    type ValueExtractor = func(int) []interface{}
    
    func Generate(tableName string, columns []string, numRows int, postgres bool, valueExtractor ValueExtractor) (string, []interface{}) {
        numCols := len(columns)
        var queryBuilder strings.Builder
        queryBuilder.WriteString("INSERT INTO ")
        queryBuilder.WriteString(tableName)
        queryBuilder.WriteString("(")
        for i, column := range columns {
            queryBuilder.WriteString("\"")
            queryBuilder.WriteString(column)
            queryBuilder.WriteString("\"")
            if i < numCols-1 {
                queryBuilder.WriteString(",")
            }
        }
        queryBuilder.WriteString(") VALUES ")
        var valueArgs []interface{}
        valueArgs = make([]interface{}, 0, numRows*numCols)
        for rowIndex := 0; rowIndex < numRows; rowIndex++ {
            queryBuilder.WriteString("(")
            for colIndex := 0; colIndex < numCols; colIndex++ {
                if postgres {
                    queryBuilder.WriteString("$")
                    queryBuilder.WriteString(strconv.Itoa(rowIndex*numCols + colIndex + 1))
                } else {
                    queryBuilder.WriteString("?")
                }
                if colIndex < numCols-1 {
                    queryBuilder.WriteString(",")
                }
            }
            queryBuilder.WriteString(")")
            if rowIndex < numRows-1 {
                queryBuilder.WriteString(",")
            }
            valueArgs = append(valueArgs, valueExtractor(rowIndex)...)
        }
        return queryBuilder.String(), valueArgs
    }
    

    // 대량 / insert_test.go

    import (
        "fmt"
        "strconv"
    )
    
    func valueExtractor(index int) []interface{} {
        return []interface{}{
            "trx-" + strconv.Itoa(index),
            "name-" + strconv.Itoa(index),
            index,
        }
    }
    
    func ExampleGeneratePostgres() {
        query, valueArgs := Generate("tbl_persons", []string{"transaction_id", "name", "age"}, 3, true, valueExtractor)
        fmt.Println(query)
        fmt.Println(valueArgs)
        // Output:
        // INSERT INTO tbl_persons("transaction_id","name","age") VALUES ($1,$2,$3),($4,$5,$6),($7,$8,$9)
        // [[trx-0 name-0 0] [trx-1 name-1 1] [trx-2 name-2 2]]
    }
    
    func ExampleGenerateOthers() {
        query, valueArgs := Generate("tbl_persons", []string{"transaction_id", "name", "age"}, 3, false, valueExtractor)
        fmt.Println(query)
        fmt.Println(valueArgs)
        // Output:
        // INSERT INTO tbl_persons("transaction_id","name","age") VALUES (?,?,?),(?,?,?),(?,?,?)
        // [[trx-0 name-0 0] [trx-1 name-1 1] [trx-2 name-2 2]]
    }
    
  11. ==============================

    11.나는 pq.CopyIn 작업 얻고, 더 빨리 / 인수가 접근 문자열 값에 비해 실제로 2.4 배를의 (BTW, 너무 감사합니다, 슈퍼 유용하고 우아한 해결책이었다!)

    나는 pq.CopyIn 작업 얻고, 더 빨리 / 인수가 접근 문자열 값에 비해 실제로 2.4 배를의 (BTW, 너무 감사합니다, 슈퍼 유용하고 우아한 해결책이었다!)

    나는 구조체로 INT, VARCHAR의 1000 만 개 테스트 값을 삽입, 다음과 같은 기능을로드. 그래서 나와 함께 곰 GoLang에 좀 새로운 해요 ...

    func copyData(client *client.DbClient, dataModels []*dataModel) error{
        db := *client.DB
        txn, err := db.Begin()
        if err != nil {
            return err
        }
        defer txn.Commit()
    
        stmt, err := txn.Prepare(pq.CopyIn("_temp", "a", "b"))
        if err != nil {
            return(err)
        }
    
        for _, model := range dataModels{
            _, err := stmt.Exec(model.a, model.b)
            if err != nil {
                txn.Rollback()
                return err
            }
        }
    
        _, err = stmt.Exec()
        if err != nil {
            return err
        }
    
        err = stmt.Close()
        if err != nil {
            return err
        }
    
        return nil
        }
    

    `

    경과 (stringValues ​​/ 인수) : 1m30.60s.

    경과 (copyIn) : 37.57s.

  12. from https://stackoverflow.com/questions/12486436/how-do-i-batch-sql-statements-with-package-database-sql by cc-by-sa and MIT license