在Go中的MySQL中插入行非常慢?

So I have been rewriting an old PHP system to Go looking for some performance gains but I'm not get any. And the problem seems to be in the Inserts i'm doing into Mysql.

So where PHP does some processing of a CSV file, does some hashing and inserts around 10k rows in MySQL it takes 40 seconds (unoptimized code).

Now Go on the other hand stripped away of any processing and just the same inserting of 10k(empty) rows takes 110 seconds.

Both tests are run on the same machine and I'm using the go-mysql-driver.

Now for some Go code:

This is extremely dumbed down code and this still takes almost 2 minutes, compared to PHP which does it in less then half.

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:bla@/bla")

    return *db
}

Profiler result

So is it my code, the go-mysql-driver or is this normal and is PHP just really fast in inserting records?

==EDIT==

As per requested, I have recorded both PHP and Go runs with tcpdump: The files:

I have a hard time reaching any conclusions comparing the two logs, both seem to be sending the same size packets back and forth. But with Go(~110) mysql seems to almost take twice as long to process the request then with PHP(~44), also Go seems to wait slightly longer before sending a new request again(the difference is minimal though).

It's an old question but still - better late than never; you're in for a treat:

put all your data into a bytes.Buffer as tab-separated, newline terminated and unquoted lines (if the text causes problems, it has to be escaped first). NULL has to be encoded as \N.

Use http://godoc.org/github.com/go-sql-driver/mysql#RegisterReaderHandler and register a function returning that buffer under "instream". Next, call LOAD DATA LOCAL INFILE "Reader::instream" INTO TABLE ... - that's a very fast way to pump data into MySQL (I measured about 19 MB/sec with Go from a file piped from stdin compared to 18 MB/sec for the MySQL command line client when uploading data from stdin).

As far as I know, that very driver is the only way to LOAD DATA LOCAL INFILE without the need of a file.

I notice you're not using a transaction, if you're a using a vanilla mysql 5.x with InnoDB this will be a huge performance drag as it will auto-commit on every insert.

func GetDbCon() (sql.DB) {
    db, _ := sql.Open("mysql", "bla:bla@/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)
}