【问题标题】:SQLITE delete taking very long timeSQLITE 删除需要很长时间
【发布时间】:2020-06-26 00:19:46
【问题描述】:

我有一个如下所示的表格:

CREATE TABLE records (
    batchID TEXT,
    A       TEXT,
    A_id    REAL,
    B       TEXT,
    B_id    REAL,
    C       REAL,
    D       REAL,
    E       REAL,
    F       REAL,
    G       REAL,
    H       REAL,
    color   REAL,
    repair  REAL,
    data    BLOB,
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT
)

我在某些列的表格上有一个索引。 由于诚信不是问题,我有:

PRAGMA synchronous = "0"
PRAGMA journal_mode = "OFF"

数据库经常插入,我的记录表中​​有大约 200 万行,数据库文件大小约为 2GB。 每隔几个小时,我需要从记录表中删除 200K 行。我正在使用节点 js orm:

db.driver.execQuery('DELETE FROM records WHERE A IN ? AND batchID = ?',
    [['a1', 'a2'], 'batch123'],
    function(err) {
    // do stuff here    
    });

一开始删除大约需要 10 秒,但是,运行一个月后,删除语句可能需要一个多小时 (!)(请参阅我记录删除时间的日志中的附加性能图 - 橙色圆圈,蓝色圆圈是节点的内存)。 这是一个问题,因为在删除时节点中会生成新的写入请求。这些写请求在内存中排队到一个点节点使用大量内存。 (因为删除会锁定表并阻止写入)

我怀疑这是因为数据库变得支离破碎。 真空对我来说不是一个选项,因为这是一个无法停止的产品,当我在 sqlite db 文件的副本上测试真空时间时,它需要 15 到 30 分钟。 据我了解,自动清理不会有帮助,因为它不会压缩页面中的数据,并且会加剧碎片化。 我还尝试将页面大小设置为 4096,这也没有帮助。performance graph

【问题讨论】:

  • 你确定删除是在第二个发生的吗?
  • 抱歉,我不得不编辑我的问题,如果您的评论看起来不相关,请见谅。
  • 现在真的是一个不同的问题:-)。我对其进行了编辑,仅更改了表格的格式。你提到你有一些索引。哪个?知道这一点很重要。也可以看看stackoverflow.com/help/how-to-ask,它为如何写一个问题提供了很好的建议。

标签: sqlite orm


【解决方案1】:

默认情况下,SQLite 插入或删除在隐式事务中执行,因此速度很慢。

来自https://www.sqlite.org/lang_transaction.html

读取事务由 SELECT 语句启动,写入事务由 CREATE、DELETE、DROP、INSERT 或 UPDATE 等语句启动(统称为“写入语句”)。

来自常见问题解答 19 https://www.sqlite.org/faq.html

INSERT 真的很慢 - 我每秒只能执行几十次 INSERT

默认情况下,每个 INSERT 语句都是它自己的事务。但是如果你用 BEGIN...COMMIT 包围多个 INSERT 语句,那么所有的插入都会被分组到一个事务中。提交事务所需的时间在所有包含的插入语句中分摊,因此每个插入语句的时间大大减少。

编辑:在我写完这个答案后问题已经改变,所以它似乎没有意义。

通常您不应将 AUTOINCREMENT 与 SQLite 一起使用,它不是必需的,并且会对性能产生不利影响,请参阅https://sqlite.org/autoinc.html

AUTOINCREMENT 关键字会带来额外的 CPU、内存、磁盘空间和磁盘 I/O 开销,如果不是严格需要,应避免使用。通常不需要。

在 SQLite 中,类型为 INTEGER PRIMARY KEY 的列是 ROWID 的别名(除了 WITHOUT ROWID 表),它始终是 64 位有符号整数。

在 INSERT 中,如果 ROWID 或 INTEGER PRIMARY KEY 列没有显式地给定一个值,那么它将用一个未使用的整数自动填充,通常比当前使用的最大 ROWID 多一个。无论是否使用 AUTOINCREMENT 关键字都是如此。

如果 AUTOINCREMENT 关键字出现在 INTEGER PRIMARY KEY 之后,则会更改自动 ROWID 分配算法,以防止在数据库的生命周期内重复使用 ROWID。换句话说,AUTOINCREMENT 的目的是防止重复使用以前删除的行中的 ROWID。

【讨论】:

  • 对不起,我不明白 - 那么,如果它已经在隐式事务中执行,如何在删除周围添加事务使其更快?
  • 如果你在一个循环中有N个删除(我理解你的情况),如果你在显式事务中执行它们,当执行单个删除时,它会检测到它正在运行在现有事务中,并且不会创建另一个事务。因此,将只有 1 个事务而不是 N。提交事务时,默认情况下数据库会同步到磁盘,因此速度很慢。是不是更清楚了?
  • 对不起,我不得不编辑我的问题,我并没有在循环中删除,只是在“删除”位置'
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-07
  • 2015-03-31
  • 2019-09-24
  • 2021-07-24
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多