针对 20,000 多次更新优化 Sqlite3

Posted

技术标签:

【中文标题】针对 20,000 多次更新优化 Sqlite3【英文标题】:Optimizing Sqlite3 for 20,000+ Updates 【发布时间】:2011-07-15 18:07:38 【问题描述】:

我有大约 20,000 个要插入到表中的项目的列表(其中大约有 50,000 行)。这些项目中的大多数会更新现有行中的某些字段,少数会插入全新的行。

我为每个项目访问数据库两次。首先是检查行是否存在的选择查询。接下来我根据选择查询的结果插入或更新一行。我在更新/插入后立即提交每个事务。

对于前几千个条目,我每秒处理大约 3 或 4 个条目,然后它开始变慢。到最后,每次迭代需要超过 1/2 秒。为什么可能会放缓?

我的平均时间是:整个运行 0.5 秒,每个选择查询 0.18 秒,每个插入/更新 0.31 秒。最后一个 0.01 是由于在进入数据库之前解析数据的几个未测量的过程。

更新

我已将所有提交注释为测试并且没有任何更改,所以不是这样(不过,欢迎更多关于最佳提交的想法)。

关于表结构: 每行有二十列。前 4 个是 TEXT 字段(都是用第一个 insert 设置的),16 个是 REAL 字段,其中一个是用初始 insert 语句输入的。

随着时间的推移,“优秀”的 REAL 字段将填充我在这里尝试优化的过程。

我没有明确的索引,尽管其中一个字段是每一行的唯一键。

我应该注意到,随着数据库变得越来越大,SELECT 和 UPDATE 查询都花费了越来越多的时间,其中 SELECT 操作的性能特别显着下降。

我最初认为这可能是 SQLITE 的某种结构问题(无论这意味着什么),但在任何地方都找不到任何表明该程序存在自然限制的文档。

数据库现在大约有 60 兆兆。

【问题讨论】:

您可以使用PRAGMAs、日志等调整 SQLite。 那些时间“先验”可怕,但我们需要更多的背景才能真正有一个想法。你能发布表格的结构,以及一些典型记录的示例吗? 你尝试过 WAL 日志吗? 你知道我实际上没有。你的回答让我意识到我没有明确的主键,所以我用主键重建了表。这对速度有很大帮助,但是当我将插入和更新分组以使用“executemany”而不是“execute”时,我真的赢了。现在整个过程大约需要 30 秒,而不是 2-3 小时。 【参考方案1】:

我认为你的瓶颈是你每次插入/更新都提交/avec:

我在更新/插入后立即提交每个事务。

要么停止这样做,要么至少切换到WAL journaling;请参阅我的这个答案,了解原因: SQL Server CE 4.0 performance comparison

如果你有一个主键,你可以通过使用带有 INSERT INTO 的 ON CONFLICT 子句来优化选择:

http://www.sqlite.org/lang_conflict.html

EDIT:之前我的意思是写“如果你有一个主键”而不是外键;我修好了。

【讨论】:

哇很时髦!我的蒙特利尔法语根今晚很强大!【参考方案2】:

编辑:真丢脸。我误读了这个问题,并以某种方式理解这是针对 mysql 而不是 SQLite... 哎呀。 请忽略此响应,而不是获取有关更新 DBMS 的一般想法。正如sixfeetsix' response 所指出的那样,OP 问题的可能解决方案是提交过于频繁。


一个似是而非的解释是表格碎片化。 您可以每隔一段时间通过defragmenting the table 验证这一事实,并检查性能是否恢复到每秒 3 或 4 个项目的速率。 (顺便说一句,先验相对较慢,但可能取决于硬件、数据架构和其他细节。)当然,您需要考虑碎片整理所花费的时间,并将其与缓慢更新所损失的时间进行平衡率以找到碎片整理的最佳频率。

如果减速实际上是由碎片造成的,至少部分是由碎片造成的,您还可以考虑按特定顺序执行更新。如果不了解整体架构和数据统计配置文件的详细信息,很难更具体,但碎片确实对数据库发生各种更改的顺序很敏感。

为了提高整体更新性能,最后的建议是(如果可能的话)在表上删除一些索引,执行更新,然后重新创建索引。这种违反直觉的方法适用于相对较大的更新,因为随着更新的进行,重新创建新索引的成本通常低于维护它们的累积成本。

【讨论】:

为什么这会得到支持? OP 询问有关 sqlite 的问题,你向他扔了一个 mysql 功能。 @sixfeetsix:天哪!你是对的......'一定是误读了标签/问题。 SQLite 还解释了每秒 3-4 个记录。您的回答更合理,我会立即+它。振作起来,你的回应。我希望很快就会达到顶峰。 虽然赞成票仍然是个谜 :) 但如果您还记得 VACUUM,这个答案仍然很有用。

以上是关于针对 20,000 多次更新优化 Sqlite3的主要内容,如果未能解决你的问题,请参考以下文章

将相同的记录多次添加到数据库而不是一次

优化求和 2 个字节数组

针对 REGEXP 的 Mysql 优化

优化超过 200,000 条记录的查询

接口优化的常见方案实战总结

MYSQL多次更新