所以我一直在重写一个旧的PHP系统去寻找一些性能提升,但我没有得到任何。而问题似乎是在我正在进入Mysql的插件中。
因此,PHP对CSV文件进行了一些处理,在MySQL中进行一些哈希并插入大约10k行需要40秒(未经优化的代码)。
现在另一方面剥离任何处理,只需插入10k(空)行需要110秒。
两个测试都在同一台机器上运行,而我正在使用go-mysql-driver。
现在有些Go代码:
这是非常愚蠢的代码,这仍然需要将近2分钟,而PHP则只需要不到一半。
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
}
所以它是我的代码,go-mysql-driver还是这是正常的,PHP在插入记录方面真的很快?
== EDIT ==
根据要求,我已经使用tcpdump记录了PHP和Go运行: 文件:
我很难得出比较这两个日志的任何结论,两者似乎都在来回发送相同大小的数据包。但是使用Go(~110),mysql似乎几乎需要花费两倍的时间来处理请求然后使用PHP(~44),Go似乎等待稍长一些再次发送新请求(尽管差异很小)。
答案 0 :(得分:3)
这是一个古老的问题,但仍然 - 迟到总比没有好;你正在享受一种享受:
将所有数据放入bytes.Buffer
作为制表符分隔,换行符和未加引号的行(如果文本导致问题,则必须先将其转义)。 NULL必须编码为\N
。
使用http://godoc.org/github.com/go-sql-driver/mysql#RegisterReaderHandler并注册一个函数,在“instream”下返回该缓冲区。接下来,调用LOAD DATA LOCAL INFILE "Reader::instream" INTO TABLE ...
- 这是一种非常快速的方式将数据泵入MySQL(我从stdin传输的文件中测量大约19 MB /秒,而上传数据时MySQL命令行客户端测量大小为18 MB /秒)来自stdin)。
据我所知,这个驱动程序是加载DATA LOCAL INFILE而不需要文件的唯一方法。
答案 1 :(得分:1)
我注意到你没有使用一个事务,如果你使用一个带有InnoDB的vanilla mysql 5.x,这将是一个巨大的性能阻力,因为它将在每个插入时自动提交。
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)
}