V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
SilenceLL
V2EX  ›  程序员

请教一个 SQLite+Android+Gomobile 的问题

  •  
  •   SilenceLL · 2023-09-25 19:24:23 +08:00 · 823 次点击
    这是一个创建于 450 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景:

    使用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 真是费事,啥也看不了,啥命令行执行也不行。

    6 条回复    2023-09-27 10:17:31 +08:00
    zhanlanhuizhang
        1
    zhanlanhuizhang  
       2023-09-26 09:23:45 +08:00
    gomobile+go-sqlite3 ,直接调试你就可以知道。逐步增加数量,就可以看出哪里是性能瓶颈。但是这种方案肯定是有性能损失的。因为 go 和 sqlite3 交互,比 C 和 sqlite3 交互,肯定更加耗时。
    ysc3839
        2
    ysc3839  
       2023-09-26 11:59:15 +08:00 via Android
    为什么要先调用 Golang 再调用 SQLite ?楼主不会 Java ,只会 Golang ?建议先试试用 Java 调用 SQLite 看看性能如何。
    SilenceLL
        3
    SilenceLL  
    OP
       2023-09-26 14:02:53 +08:00
    @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

    ```
    SilenceLL
        4
    SilenceLL  
    OP
       2023-09-26 14:05:46 +08:00
    另外还有一个现象,就是如果我每次执行 sql 之前都宠幸 sql.open 一个新的 db ,这种问题出现的概率会大幅下降。有点像是一个连接性能有限,开个新的就能申请一些新的资源占用。
    zhanlanhuizhang
        5
    zhanlanhuizhang  
       2023-09-27 09:29:29 +08:00
    @SilenceLL 应该是整个 app 只打开一次 db ,你这多次打开,影响很大。是不是调用错误。
    SilenceLL
        6
    SilenceLL  
    OP
       2023-09-27 10:17:31 +08:00
    @zhanlanhuizhang 现在就是只打开一次,出现写入错误概率高。如果每次执行前打开一个新的链接,写入错误概率就低了,甚至不出现了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3270 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 11:54 · PVG 19:54 · LAX 03:54 · JFK 06:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.