【问题标题】:Configure SQLite for real time operations为实时操作配置 SQLite
【发布时间】:2014-04-02 13:26:25
【问题描述】:

简而言之,这篇文章想回答以下问题:我们如何(如果可能)配置 SQLite 数据库以绝对确保任何 INSERT 命令将在 8 毫秒内返回?

通过配置,我的意思是:编译选项、数据库编译选项和运行时选项。

为了提供一些背景知识,我们希望以 120 fps 的速度应用相同的 INSERT 语句。 (1000 毫秒/120 fps ≃ 8 毫秒)

使用以下字符串创建数据库:

"CREATE TABLE IF NOT EXISTS MYTABLE ("
      "int1 INTEGER PRIMARY KEY AUTOINCREMENT, "
      "int2 INTEGER, "
      "int3 INTEGER, "
      "int4 INTEGER, "
      "fileName TEXT);

和选项:

"PRAGMA SYNCHRONOUS=NORMAL;"
"PRAGMA JOURNAL_MODE=WAL;"

INSERT 语句如下:

INSERT INTO MYTABLE VALUES (NULL, ?, ?, ?, ?)

最后一个? (for fileName) 是文件的名称,所以它是一个小字符串。因此,每个 INSERT 都很小。

当然,我使用预编译语句来加速这个过程。

我有一个小程序,每 8 毫秒插入一次,并测量执行此插入所需的时间。更准确地说,程序进行一次插入,然后等待 8 毫秒,然后进行另一次插入,等等……最后,推送了 7200 次插入,因此程序运行了大约 1 分钟。

这里有两个显示两个图表的链接:

此图显示了插入所花费的毫秒数与以分钟表示的时间的函数关系。如您所见,大多数情况下,插入时间为 0,但也有超过 100 毫秒的尖峰。

此图像是相同数据的直方图表示。所有低于 5 毫秒的值都没有表示出来,但我可以告诉你,从 7200 次插入来看,7161 低于 5 毫秒(并且会在 0 处产生一个巨大的峰值,这会使图表的可读性降低)。

总节目时间为 实际 1m2.286s 用户 0m1.228s 系统 0m0.320s。

假设是 1 分 4 秒。别忘了我们花了 7200 次 8 毫秒来等待。所以 7200 次插入需要 4 秒 ---> 我们有每秒 1800 次插入的速率,因此每次插入的平均时间为 0.55 毫秒。 这真的很棒,除了在我的情况下,我希望所有插入都低于 8 毫秒,并且图表显示显然不是这种情况。

那么这些峰从何而来?

当 WAL 文件达到给定的大小(在我们的例子中为 1MB)时,SQLite 会创建一个检查点(WAL 文件应用于真实的数据库文件)。并且因为我们通过了 PRAGMA SYNCHRONOUS=NORMAL,所以此时,SQLite 在硬盘上执行 fsync。 我们假设正是这种 fsync 使相应的插入变得非常慢。 这个长插入时间不依赖于 WAL 文件的大小。我们使用了链接到 WAL 文件的 pragma WAL_AUTOCHECKPOINT(默认为 1000),但我们无法降低峰的高度。

我们还尝试了 PRAGMA SYNCHRONOUS=OFF。性能更好,但仍然不够。 作为参考,我电脑上的dirty_background_ratio(/proc/sys/vm/dirty_background_ratio)设置为0,这意味着缓存中的所有脏页必须立即刷新到硬盘上。

有没有人知道如何“平滑”图表,这意味着所有插入时间都不会超过 8 毫秒?

【问题讨论】:

  • 为什么需要这样的时机?从在 RS485 通信需要 40 毫秒时间片的系统上工作的角度来看,我认为您不会在非实时操作系统上达到目标。您使用的是什么操作系统?
  • 我一般不喜欢多线程,但这似乎是你的 INSERT 语句的执行应该在一个单独的线程中的情况,两个线程安全地共享一个 std::deque 记录插入。
  • @Steger:这正是我们在上述项目中所做的,并赋予了我们快速线程实时优先级,但我们仍然无法始终达到所需的时序。不过,我们到达了“足够好”的地方。
  • 您可以尝试其中一些stackoverflow.com/questions/1711631/… 优化。

标签: c++ sqlite optimization real-time


【解决方案1】:

默认情况下,SQLite 中的几乎所有内容都针对吞吐量而非延迟进行了优化。

WAL 模式将大部分延迟转移到检查点中,但如果您不想要这些大延迟,则必须使用更频繁的检查点,即在每次事务后执行检查点。 在这种情况下,WAL 模式没有意义;最好试试journal_mode=persist。 (这不会有太大帮助,因为延迟主要来自同步,而不是数据量。)

如果 WAL/journal 操作太慢,甚至synchronous=off 不够快,那么你唯一的选择就是禁用事务安全并尝试journal_mode=memory 甚至=off

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-24
    • 1970-01-01
    • 1970-01-01
    • 2020-01-28
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多