【问题标题】:MySQL sequential inserts are slow while threaded inserts are fast - why?MySQL顺序插入很慢,而线程插入很快 - 为什么?
【发布时间】:2020-04-05 22:09:45
【问题描述】:

我发现,与插入相同行数的多线程解决方案相比,按顺序将数据插入我的数据库非常慢。 在我的顺序方法中插入 50000 行大约需要 4 分钟,而在并行版本中只需大约 10 秒。

我使用https://github.com/go-sql-driver/mysql 驱动程序。
对于数据库,我刚刚使用了最新版本的 Windows 版 XAMPP,并使用 MySQL 数据库及其标准配置。

连续版本:

for i := 0; i < 50000; i++ {

        _, err2 := db.Exec("insert into testtable (num, text1, text2) values (?, ?, ?)", i, "txt1", "txt2")

        if err2 != nil {
            fmt.Println(err2)
        }

}

并行版本:

for i := 0; i < 50; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for j := 0; j < 1000; j++ {
                _, err2 := db.Exec("insert into testtable (num, text1, text2) values (?, ?, ?)", 1, "txt1", "txt2")
                if err2 != nil {
                    fmt.Println(err2)
                }
            }
        }()
}

为什么第一个版本比第二个版本慢?
有任何想法吗?我是否使用了错误的函数来插入数据?

【问题讨论】:

  • @armmie 你在问为什么顺序版本需要大约 4 分钟?或者你在问为什么一般来说并发执行的代码比顺序执行的代码“快”?
  • “MySQL 顺序插入很慢,而线程插入很快 - 为什么?” @armmie 我会问“为什么不呢?”。为什么您希望顺序代码与并行代码执行相同的操作?如果不是为了提供比顺序代码更好的性能,并行代码的目的是什么?
  • 我假设数据库无论如何都会按顺序处理对同一个表的插入,因此预计性能不会有差异。这就是我感到惊讶的原因。
  • @armmie 如果db 表示单个连接,则可能是这种情况,但是*sql.DB 类型是一个为并发使用而设计的连接,所以当你的顺序代码,因为它是顺序的,只使用池中的单个连接,并发代码使用 mysql 服务器允许和池可以管理的尽可能多的连接。
  • 哦,所以运行时会自动创建更多连接。我认为它只会将并发插入序列化到同一个连接中,因为它们都具有相同的数据库引用。谢谢您的帮助!! :)

标签: mysql performance go goroutine


【解决方案1】:

运行INSERT 有很多开销:

  • 客户端和服务器之间的通信。
  • 解析INSERT
  • 打开表等
  • 获取下一个AUTO_INCREMENT 值。
  • 检查是否存在冲突、死锁等
  • 提交事务。

所有这些都在单个 CPU 中完成,如有必要,还需要等待 I/O。

你有 50 个线程;他们跑得快 24 倍。

但是您可以做到 10 倍——一次将这些行批处理成一个 INSERT 100 行。这消除了大部分开销,尤其是提交。 (超过 100-1000 行会导致收益递减和其他开销;所以到此为止。)

同时,使用的线程数不要超过 CPU 内核数的两倍。否则,他们只会相互绊倒。 可能是为什么 50 个线程的速度只有 24 倍。

【讨论】:

    猜你喜欢
    • 2013-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多