2013-10-16 3 views
3

그래서 이전의 PHP 시스템을 약간의 성능 향상을 찾기 위해 다시 작성했지만 아무 것도 얻지 못했습니다. 그리고 문제는 삽입물에 내가 MySQL을하고있어 것 같습니다.Go에서 MySQL에 행 삽입 속도가 매우 느립니까?

PHP가 CSV 파일의 일부 처리를 수행하는 경우 MySQL에서 약 10k 행을 해싱하고 삽입하는 데 40 초 (최적화되지 않은 코드)가 필요합니다.

이제 다른 처리 방법을 사용하지 말고 10k (빈) 행을 삽입하는 데 110 초가 걸립니다.

두 시스템 모두 동일한 시스템에서 실행되며 go-mysql 드라이버를 사용하고 있습니다. 일부 이동 코드에 대한 지금

는 :

이 매우 코드를 무식하게되고이 여전히 절반 적은 다음에 그것을 않습니다 PHP에 비해 약 2 분 정도 소요됩니다.

db := GetDbCon() 
defer db.Close() 

stmt, _ := db.Prepare("INSERT INTO ticket (event_id, entry_id, column_headers, column_data, hash, salt) VALUES (?, ?, ?, ?, ?, ?)") 

for i := 0; i < 10000; i++{ 
    //CreateTicket(columns, line, storedEvent) 
    StoreTicket(models.Ticket{int64(0), storedEvent.Id, int64(i), 
        "", "", "", "", int64(0), int64(0)}, *stmt) 
} 

//Extra functions 
func StoreTicket(ticket models.Ticket, stmt sql.Stmt){ 
    stmt.Exec(ticket.EventId, ticket.EntryId, ticket.ColumnHeaders, ticket.ColumnData, ticket.Hash, ticket.Salt) 
} 

func GetDbCon() (sql.DB) { 
    db, _ := sql.Open("mysql", "bla:[email protected]/bla") 

    return *db 
} 

Profiler result

그래서, 내 코드 이동-mysql을 드라이버의 경우, 또는이 정상이며 PHP 레코드를 삽입하기에 정말 빠르다?

== 편집 ==

요청에 따라 경찰, 내가 녹음 한 PHP와 이동 모두 tcpdump와 함께 실행 : 파일 :

두 로그를 비교하는 데 아무런 결론이 도출되지 않았습니다. 둘 다 동일한 크기의 패킷을 앞뒤로 보내는 것처럼 보입니다. 하지만 Go (~ 110)를 사용하면 mysql이 PHP (~ 44)로 요청을 처리하는 데 거의 두 배의 시간이 소요되는 것처럼 보입니다. Go는 다시 새로운 요청을 보내기 전에 약간 기다리는 것처럼 보입니다.

+0

같은 컴퓨터가 괜찮지 만 동일한 데이터베이스 및 테이블입니까? 여분의 인덱스를 정의 했습니까? 단지 야생의 추측. – Litmus

+0

그들은 (구조는 동일합니다) 명명법의 사소한 차이점을 가지고 다른 데이터베이스에서 작동하지만 인덱스는 정확히 같고 데이터베이스는 각 테스트 전에 잘립니다. – Rohan

+0

어떤 버전의 MySQL 드라이버를 사용하고 있습니까? – thwd

답변

3

낡은 질문이지만 여전히 늦지 않는 것이 좋습니다.

모든 데이터를 탭으로 구분되고 개행 문자로 끝나고 따옴표가없는 줄로 넣으십시오 (텍스트가 문제를 일으키는 경우 먼저 이스케이프 처리해야 함). NULL은 \N으로 인코딩되어야합니다.

http://godoc.org/github.com/go-sql-driver/mysql#RegisterReaderHandler을 사용하고 해당 버퍼를 "instream"아래에 반환하는 함수를 등록하십시오. 다음으로 LOAD DATA LOCAL INFILE "Reader::instream" INTO TABLE ...으로 전화하십시오 - 데이터를 MySQL로 펌핑하는 매우 빠른 방법입니다 (표준 입력에서 데이터를 업로드 할 때 MySQL 명령 행 클라이언트의 경우 18MB/초에 비해 stdin에서 파이프 된 파일에서 Go를 사용하여 약 19MB/초를 측정했습니다).

필자가 아는 바로는 파일이 없어도 바로 드라이버가 로컬 데이터를로드 할 수있는 유일한 방법입니다.

1

InnoDB와 함께 바닐라 mysql 5.x를 사용한다면 트랜잭션을 사용하지 않는다는 것을 알게 될 것입니다. 이것은 모든 삽입물에 자동 커밋 (auto-commit)을 할 것이므로 큰 성능 드래그가 될 것입니다.

func GetDbCon() (sql.DB) { 
    db, _ := sql.Open("mysql", "bla:[email protected]/bla") 
    return *db 
} 

func PrepareTx(db *db.DB,qry string) (tx *db.Tx, s *db.Stmt, e error) { 
if tx,e=db.Begin(); e!=nil { 
    return 
} 

if s, e = tx.Prepare(qry);e!=nil { 
    tx.Close() 
} 
return 
} 


db := GetDbCon() 
defer db.Close() 

qry := "INSERT INTO ticket (event_id, entry_id, column_headers, column_data, hash, salt) VALUES (?, ?, ?, ?, ?, ?)" 

tx,stmt,e:=PrepareTx(db,qry) 
if e!=nil { 
panic(e) 
} 

defer tx.Rollback() 
for i := 0; i < 10000; i++{ 
ticket:=models.Ticket{int64(0), storedEvent.Id, int64(i),"", "", "", "", int64(0), int64(0)} 
stmt.Exec(ticket.EventId, ticket.EntryId, ticket.ColumnHeaders, ticket.ColumnData, ticket.Hash, ticket.Salt) 

// To avoid huge transactions 
if i % 1000 == 0 { 
    if e:=tx.Commit();e!=nil { 
    panic(e) 
    } else { 
    // can only commit once per transaction 
    tx,stmt,e=PrepareTx(db,qry) 
    if e!=nil { 
    panic(e) 
    } 
    } 
} 
} 

// Handle left overs - should also check it isn't already committed 
if e:=tx.Commit();e!=nil { 
panic(e) 
} 
관련 문제