为了账号安全,请及时绑定邮箱和手机立即绑定

Sqlite并发写入性能

Sqlite并发写入性能

Go
qq_花开花谢_0 2021-12-20 14:47:10
我正在用 Golang 和 Sqlite3 编写一个网站,我预计每天有几分钟的时间每秒大约有 1000 次并发写作,所以我做了以下测试(忽略错误检查以看起来更干净):t1 := time.Now()tx, _ := db.Begin()stmt, _ := tx.Prepare("insert into foo(stuff) values(?)")defer stmt.Close()for i := 0; i < 1000; i++ {    _, _ = stmt.Exec(strconv.Itoa(i) + " - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,./;'[]-=<>?:()*&^%$#@!~`")}tx.Commit()t2 := time.Now()log.Println("Writing time: ", t2.Sub(t1))写入时间约为0.1秒。然后我将循环修改为:for i := 0; i < 1000; i++ {    go func(stmt *sql.Stmt, i int) {        _, err = stmt.Exec(strconv.Itoa(i) + " - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,./;'[]-=<>?:()*&^%$#@!~`")        if err != nil {            log.Fatal(err)        }    }(stmt, i)}这给了我神圣的 46.2 秒!我运行了很多次,每次都超过 40 秒!有时甚至超过一分钟!由于 Golang 并发处理每个用户,是否意味着我必须切换数据库才能使网页正常工作?谢谢!
查看完整描述

1 回答

?
呼啦一阵风

TA贡献1802条经验 获得超6个赞

我最近在 Go 中为网络应用程序评估了 SQLite3 的性能,并了解到它需要一些设置才能远程使用。

打开预写日志

您需要使用 WAL PRAGMA journal_mode=WAL。这就是为什么你的表现如此糟糕的主要原因。使用 WAL,我可以在几秒钟内完成 10000 次没有事务的并发写入。在交易中,这将是闪电般的快速。

禁用连接池

我使用mattn/go-sqlite3它打开一个带有SQLITE_OPEN_FULLMUTEX标志的数据库。这意味着每个 SQLite 调用都会被锁保护。一切都会被序列化。这实际上就是你想要的 SQLite。在这种情况下,Go 的问题是您会收到随机错误,告诉您数据库已锁定。原因是因为sql/DB内部的工作方式。它内部为您管理连接池,因此它将打开多个 SQLite 连接,而您不想这样做。为了解决这个问题,我基本上必须禁用池。打电话db.SetMaxOpenConns(1),它会工作。即使在具有数万次并发读取和写入的非常高的负载下,它也能毫无问题地工作。

其他解决方案可能是使用SQLITE_OPEN_NOMUTEX在多线程模式下运行 SQLite 并让它为您管理。但是 SQLite 在多线程应用程序中并不真正起作用。读取可以并行发生,但一次只能写入一次。您会偶尔遇到busySQLite 完全正常的错误,但需要您对它们做些什么——当发生这种情况时,您可能不想完全停止写入操作。这就是为什么大多数时候人们要么同步地使用 SQLite,要么通过将调用发送到一个单独的线程来为 SQLite 工作。


查看完整回答
反对 回复 2021-12-20
  • 1 回答
  • 0 关注
  • 357 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信