使用gomobile+go-sqlite3构建了一个 Android AAR 的库文件。发现性能很差,大数据库文件(200M-1G 的 sqlite 文件)只要执行insert into select xx
或者 update xx set where id in (batch id)
就会出现 disk I/O error: read-only file system
的文件系统错误。但如果使用相同的 sql+sqlite 文件通过 Android 原生调用,就能够执行成功。同时 AAR 的方式使用模拟器也能够执行成功,似乎电脑端的模拟器性能更高一些。
从表象上看 Android 似乎对 AAR 的方式做了一些性能限制,可以确定文件权限没有问题,通过 Android Studio 查看文件和目录权限正常。实在没啥排查思路,目前的改法是分批提交,减少单次数据操作量。不知道如何才能够在 AAR 中达到 Android 原生调用的性能,现在新版的 Android 不 root 真是费事,啥也看不了,啥命令行执行也不行。
1
zhanlanhuizhang 2023-09-26 09:23:45 +08:00
gomobile+go-sqlite3 ,直接调试你就可以知道。逐步增加数量,就可以看出哪里是性能瓶颈。但是这种方案肯定是有性能损失的。因为 go 和 sqlite3 交互,比 C 和 sqlite3 交互,肯定更加耗时。
|
2
ysc3839 2023-09-26 11:59:15 +08:00 via Android
为什么要先调用 Golang 再调用 SQLite ?楼主不会 Java ,只会 Golang ?建议先试试用 Java 调用 SQLite 看看性能如何。
|
3
SilenceLL OP @zhanlanhuizhang @ysc3839 有一定的历史原因,因为我们现在有一个库就是用 beego+go-sqlite3 打包成可执行文件当做 android 本地服务器使用的,新版 android 30 限制使用这种方式执行二进制,只能改成 aar 执行。结果性能下降非常严重,相同的数据和 sql 直接调用不管是通过二进制文件( targetVerison<30 )还是通过 android 直接调用都能执行成功,但是影响数据量大的情况下 gomobile+go-sqlite3 构建的 aar 直接报错。
如下例子(打包成 aar ),同一个事务中,修改数据少的 sql 可以执行成功,修改数据多的不能执行成功。 ```go func Test3(dir string, times int) { fmt.Println("Test3 exec start:", times) //os.Remove(dir) os.Chmod(dir, 0777) //db, err := sql.Open("sqlite3", "file:"+dir+"?mode=rwc") db, err := sql.Open("sqlite3", dir) if err != nil { fmt.Println(err) } defer db.Close() var readOnly string row := db.QueryRow("PRAGMA query_only") err = row.Scan(&readOnly) if err != nil { fmt.Println(fmt.Sprintf("pragma query_only error:%s", err.Error())) } fmt.Println(fmt.Sprintf("pragma query_only:%s", readOnly)) tx, err := db.Begin() if err != nil { fmt.Println(err) } for i := 0; i < times; i++ { _, err := tx.Exec(`update table set is_del = 1 where id <101`) if err != nil { fmt.Println(fmt.Sprintf("exec1 error:%s", err.Error())) } _, err = tx.Exec(`update table set is_del = 1 where is_del = 0 and id not in (select id from (select max(create_at), id from table where is_del =0 group by a_id,b_idhaving count(*)>0))`) if err != nil { fmt.Println(fmt.Sprintf("exec2 error:%s", err.Error())) } } err = tx.Commit() if err != nil { fmt.Println(err) } fileInfo, err := os.Stat(dir) if err != nil { fmt.Println(err) } fileMode := fileInfo.Mode() fmt.Println(fileMode) //perm := fileMode.Perm() //fmt.Println("permission:", uint32(perm)) fmt.Println("Test3 exec end:", times) } ``` ```shell 2023-09-22 10:09:28.473 27362-27496 GoLog I Test3 exec start: 1 2023-09-22 10:09:28.476 27362-27493 GoLog I pragma query_only:0 2023-09-22 10:09:28.521 27362-27496 GoLog I exec2 error:disk I/O error: read-only file system 2023-09-22 10:09:28.521 27362-27496 GoLog I cannot commit - no transaction is active 2023-09-22 10:09:28.521 27362-27493 GoLog I -rwxrwxrwx 2023-09-22 10:09:28.521 27362-27493 GoLog I Test3 exec end: 1 2023-09-22 10:09:28.530 27362-27490 Android E Shell Command Output:-rwxrwxrwx 1 u0_a1451 u0_a1451 17772544 2023-09-22 10:03 /data/user/0/packagename/16fc0efec1104515b0244ddae36a4123.db ``` |
4
SilenceLL OP 另外还有一个现象,就是如果我每次执行 sql 之前都宠幸 sql.open 一个新的 db ,这种问题出现的概率会大幅下降。有点像是一个连接性能有限,开个新的就能申请一些新的资源占用。
|
5
zhanlanhuizhang 2023-09-27 09:29:29 +08:00
@SilenceLL 应该是整个 app 只打开一次 db ,你这多次打开,影响很大。是不是调用错误。
|
6
SilenceLL OP @zhanlanhuizhang 现在就是只打开一次,出现写入错误概率高。如果每次执行前打开一个新的链接,写入错误概率就低了,甚至不出现了。
|