我有一个测试设置来将行写入数据库。 每个事务都插入10,000行,没有更新。 每个步骤的线性时间比最后一个长。 前十个步骤在ms中花费了以下时间来执行提交
568,772,942,1247,1717,1906,2268,2797,2922,3816,3945
当它向500,000行的表中添加10,00行时,提交需要37149 ms!
我没有外键约束。
我发现使用WAL,提高性能(给出上面的数字),但仍然是线性退化
PRAGMA Synchronous = OFF无效
PRAGMA locking_mode = EXCLUSIVE无效
没有其他索引和其他索引。大致恒定的时差,所以仍然是线性退化。
我有其他一些设置
完整架构如下(我已经运行了带索引和不带索引,但已包含)
create table if not exists [EventLog] (
Id INTEGER PRIMARY KEY ASC,
DocumentId TEXT NOT NULL,
Event TEXT NOT NULL,
Content TEXT NOT NULL,
TransactionId TEXT NOT NULL,
Date INTEGER NOT NULL,
User TEXT NOT NULL)
create index if not exists DocumentId ON EventLog (DocumentId)
create index if not exists TransactionId ON EventLog (TransactionId)
create index if not exists Date ON EventLog (Date)
这是在Windows环境中运行的sqlite-jdbc-3.7.2
答案 0 :(得分:2)
SQLite表和索引are internally organized as B-Trees。在表中,Rowid是排序键。 (你的INTEGER PRIMARY KEY
是Rowid。)
如果插入的ID不大于表中已有的最大ID,则不会追加记录,而是将其插入树中间的某处。在一个事务中插入足够的记录时,如果ID的分布是随机的,这意味着几乎每个页面都必须重写。
为避免这种情况,
NULL
,以便SQLite选择下一个值;或INTEGER UNIQUE
(如果您不需要额外的检查/索引,则只需INTEGER
),从而使表格排序独立于您的ID。对于索引,插入具有随机分布的索引字段需要在随机位置更新索引。与表一样,当在一个事务中插入足够的记录时,这意味着必须重写索引中的几乎每个页面。
当您加载大量数据时,建议在没有任何索引的情况下执行此操作,然后再重新创建它们。 (与其他一些数据库不同,SQLite没有暂时禁用索引的功能;只需删除它们。)
答案 1 :(得分:0)
仅供参考,虽然我没有限制关键内容的结构,但在99.999%的情况下,这将是一个指导。因此,为了解决性能问题,我刚刚编写了一个算法,用于使用前8个十六进制数字的基于时间的值生成顺序guid。即使使用早期时间值生成guid块,这也非常有效。