[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.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.당신의 PostgreSQL을 사용하는 경우 다음 PQ 지원 수입을 일괄.
당신의 PostgreSQL을 사용하는 경우 다음 PQ 지원 수입을 일괄.
-
==============================
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.아비 아마의 대답에 확장, 내 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.다음은 포스트 그레스를 사용하는 경우 @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.포스트 그레스 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.일괄 처리는 데이터베이스 / SQL에서 사용할 수있는 인터페이스를 통해 할 수 없습니다. 특정 데이터베이스 드라이버는하지만, 별도로 지원할 수 있습니다. 예를 들어 https://github.com/ziutek/mymysql은 MySQL과 배치를 지원하기 위해 나타납니다.
일괄 처리는 데이터베이스 / SQL에서 사용할 수있는 인터페이스를 통해 할 수 없습니다. 특정 데이터베이스 드라이버는하지만, 별도로 지원할 수 있습니다. 예를 들어 https://github.com/ziutek/mymysql은 MySQL과 배치를 지원하기 위해 나타납니다.
-
==============================
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.체인 구문을 보는 또 하나 개의 좋은 도서관은 이동-페이지입니다
체인 구문을 보는 또 하나 개의 좋은 도서관은 이동-페이지입니다
https://github.com/go-pg/pg/wiki/Writing-Queries#insert
단일 쿼리로 여러 권의 책을 삽입합니다 :
err := db.Model(book1, book2).Insert()
-
==============================
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.나는 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.
from https://stackoverflow.com/questions/12486436/how-do-i-batch-sql-statements-with-package-database-sql by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] 어떻게 SQL Server의 문자열에서 공백 문자를 제거 (0) | 2020.06.24 |
---|---|
[SQL] SQL 뷰에합니까 JPA 지원 매핑? (0) | 2020.06.24 |
[SQL] DB2 쿼리는 주어진 스키마에 대한 모든 테이블 이름을 검색하기 (0) | 2020.06.24 |
[SQL] PostgreSQL의 : 대소 문자를 구분 문자열 비교 (0) | 2020.06.24 |
[SQL] 나는 4.3 코드 첫 번째 엔티티 프레임 워크의 기본 스키마 이름을 변경할 수 있습니까? (0) | 2020.06.24 |