首页 > 解决方案 > SQLite 和大型事务

问题描述

我有一个 Unity 3D 项目,我正在为 Android、OSX、iOs 和 Windows 使用预编译的 SQLite 库。在 Android 上,当使用大型事务时,我的数据库文件可以从 1MB 增长到 1GB。

例如,在 OSX 上执行此操作的行为不同,数据库没有那么大。在完成事务之前,我收到“磁盘 I/O 错误”。我试图通过比较不同的 PRAGMA 语句来弄清楚这一点,但找不到任何东西。

我可能错过了一些东西,但我不知道是什么。

编辑:我已经运行了 sqlite3_analyzer, Size of the file in bytes......................... 3715072 但磁盘上的文件大小约为 1GB

这就是发生错误的 SQL 查询的样子

                                CREATE TEMPORARY TABLE LogRange AS
            SELECT
                l.EntityKey AS EntityKey,
                l.TableName AS TableName,
                l.OrderNumber AS StartOrderNumber,
                l2.OrderNumber AS EndOrderNumber
            FROM IncomingLog AS l 
            INNER JOIN IncomingLog l2 ON l2.OrderNumber > l.OrderNumber AND l2.EntityKey = l.EntityKey AND l2.TableName = l.TableName AND l2.Type = 2
            WHERE l.Type = 0;

            DELETE FROM IncomingLog WHERE Id IN 
            (
                SELECT l.Id
                FROM IncomingLog l
                INNER JOIN LogRange lr ON lr.EntityKey = l.EntityKey AND lr.TableName = l.TableName AND l.OrderNumber >= lr.StartOrderNumber AND l.OrderNumber <= lr.EndOrderNumber
            );
            DROP TABLE LogRange;

            CREATE TEMPORARY TABLE CompressedLog AS
            SELECT
                l.*
            FROM IncomingLog l
            LEFT JOIN 
            (
                SELECT
                    1 as Id,
                    EntityKey,
                    TableName,
                    MAX(OrderNumber) as OrderNumber
                FROM IncomingLog WHERE Type = 1 OR Type = 2
                GROUP BY EntityKey 
            ) updateOrDeleteLogs ON updateOrDeleteLogs.OrderNumber > l.OrderNumber AND updateOrDeleteLogs.EntityKey = l.EntityKey AND updateOrDeleteLogs.TableName = l.TableName
            WHERE ((l.Type=1 OR l.Type = 2) AND updateOrDeleteLogs.Id IS NULL) OR l.Type = 0;

            DELETE FROM IncomingLog;
            INSERT INTO IncomingLog SELECT * FROM CompressedLog;

            DROP TABLE CompressedLog;

这就是 IncomingLog 表的样子

CREATE TABLE IncomingLog (OrderNumber INTEGER PRIMARY KEY AUTOINCREMENT, Id TEXT NOT NULL COLLATE NOCASE, Type INETEGER, CreationDate DATETIME, EntityType TEXT, EntityKey TEXT, TableName TEXT, Data TEXT)

数据列存储 json,因此可能会占用大量空间。在我的示例中,IncomingLog 表中有 5000 行。

我已经为我的包装库实现了扩展错误代码,现在我得到了 SQLITE_IOERR_GETTEMPPATH (6410)。所以现在我必须为此找到解决方案。

标签: sqlite

解决方案


我找到了问题和解决方案。显然,Android 上的 SQLite 找不到临时目录,这就是我收到错误的原因。我发现的唯一解决方法是设置 PRAGMA temp_store_directory。唯一的问题是 PRAGMA temp_store_directory 已弃用,但我找不到任何其他解决方案。

至于为什么数据库会增长到 1GB,我仍然没有答案。


推荐阅读