【问题标题】:SQLite vs serializing to diskSQLite vs 序列化到磁盘
【发布时间】:2011-10-26 08:34:10
【问题描述】:

我正在做一些性能比较,是对数据进行序列化还是将它们存储在数据库中。应用程序接收到大量数据 (x GB),需要以 18mb/s 的最低速度进行持久化(目前为止)

存储在 DB 中提供了更简单的功能,例如稍后搜索和访问数据、数据快照、数据迁移等,但我迄今为止的测试显示性能时间存在巨大差异。

测试保存了 1000 个对象(每个对象大约 700kb)。通过将它们保存为通用列表,将它们保存到表中的相应列或磁盘中。 (SQLite 最终得到更多数据)

  1. 保存到 SQLite v3,总大小 745mb:30.7 秒(~速度:24.3 mb/s)
  2. 序列化到磁盘,总大小 741mb:0.33 秒(~速度:2245 mb/s)

我没有对 SQLite 进行任何性能调整,只是将它与 Fluent nHibernate 和 SQLite.Data 适配器一起使用开箱即用(无事务),但起初认为这是一个巨大的差异。

显然,我知道通过 ORM 映射器和 DB 写入磁盘与序列化相比会产生开销,但这是很多。

还需要考虑的是在我收到数据时立即保存数据。如果出现电源故障,我需要最后收到的数据。

有什么想法吗?

-- 更新(我将继续研究解决方案)------

  • 在事务中包装 1000 次插入的时间现在约为 14s = 53mb/s,但是如果我在中途抛出异常,我会丢失所有数据。
  • 使用 IStatelessSession 似乎可以将时间缩短 0.5-1 秒
  • 通过将 ID 分配给实体而不是在表中自动分配 ID 并因此摆脱每个插入 sql 的 (select row_generatedid()),没有看到任何性能提升。 -> Id(x => x.Id).GeneratedBy.Assigned();
  • SQLite 中的 nosync() 替代方法不是替代方法,因为在电源故障的情况下数据库可能会损坏。

【问题讨论】:

  • 你用 SQLite 尝试过 dapper 吗? code.google.com/p/dapper-dot-net - 另外,请确保在开始插入之前在 SQLite 上启动事务,如果每个插入都在其自己的隐式事务中运行,您将彻底扼杀性能。
  • 至于开箱即用的解决方案,它运行隐含的是。不知道我是否可以以不同的方式运行它 - 数据需要立即保留,因为它被提供给我,如果我在电源故障期间丢失了等待提交的整个结果集,那将是很糟糕的。不过会测试它。
  • @Islandwind:然后考虑使用INSERT OR [IGNORE]
  • @AlixAxel 不太关注你?
  • @Islandwind:IGNORE 选项将导致 INSERT 不会失败,即使它实际上无法插入 - 可能是与事务结合使用的好解决方案,具体取决于您的错误处理策略。尽管如此,1000 个 INSERT 的 14 秒仍然是一个糟糕的性能......你确定瓶颈不是 ORM 吗?

标签: database performance sqlite serialization


【解决方案1】:

我有一次similar problem,我建议你走 SQLite 路线。

至于您的性能问题,我敢肯定,如果您:

  1. 在单个事务中执行所有 INSERT - 写入查询必须获取(并释放)对 SQLite 文件的锁定,这在磁盘 I/O 方面非常昂贵,您应该注意到huge boost***李>
  2. 考虑使用多插入(这可能对您不起作用,因为您依赖 ORM)
  3. 正如@user896756 所说,您还应该准备好您的陈述

测试 1:1000 次插入

CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));
INSERT INTO t1 VALUES(1,13153,'thirteen thousand one hundred fifty three');
INSERT INTO t1 VALUES(2,75560,'seventy five thousand five hundred sixty');
... 995 lines omitted
INSERT INTO t1 VALUES(998,66289,'sixty six thousand two hundred eighty nine');
INSERT INTO t1 VALUES(999,24322,'twenty four thousand three hundred twenty two');
INSERT INTO t1 VALUES(1000,94142,'ninety four thousand one hundred forty two');
  • PostgreSQL:4.373
  • MySQL:0.114
  • SQLite 2.7.6:13.061
  • SQLite 2.7.6(不同步):0.223

测试 2:事务中有 25000 个 INSERT

BEGIN;
CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));
INSERT INTO t2 VALUES(1,59672,'fifty nine thousand six hundred seventy two');
... 24997 lines omitted
INSERT INTO t2 VALUES(24999,89569,'eighty nine thousand five hundred sixty nine');
INSERT INTO t2 VALUES(25000,94666,'ninety four thousand six hundred sixty six');
COMMIT;
  • PostgreSQL:4.900
  • MySQL:2.184
  • SQLite 2.7.6:0.914
  • SQLite 2.7.6(不同步):0.757

*** 这些基准测试适用于 SQLite 2,SQLite 3 should be even faster

【讨论】:

  • +1:更重要的是,即使将 INSERT 分成 10 或 20 个一组也会得到很好的加速。
【解决方案2】:

您应该考虑对 sqlite 使用编译语句。

查看this

在插入/更新查询中,性能得到了巨大的提升,我设法使用编译语句将执行时间提高了 2 倍到 10 倍,尽管从 33 秒到 0.3 秒是很长的路要走。

另一方面,SQLite 的执行速度取决于您正在使用的表的架构,例如:如果您对大量数据建立索引,则会导致插入缓慢。

【讨论】:

  • 感谢您的链接。我会看看。该表是在运行测试之前从域模型创建的(使用 Fluent nHibernate BuildSchema()),据我所知没有创建索引。
【解决方案3】:

进一步调查后,答案在于初步结果有点混乱。

在用更大的数据测试结果时,我得到了一些其他结果。

磁盘传输速率被制造商限制为 126mb/s,我怎么能在瞬间写入 750MB?不知道为什么。但是当我增加数据量时,传输速率会快速下降到 ~136 mb/s。

至于数据库,使用 IStatelessSession 处理大量数据 (5-10GB) 时,我获得了高达 90mb/s 的速度。这对于我们的目的来说已经足够了,我相信它仍然可以通过编译的 SQL 语句和其他需要的时候进行调整。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-03
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-14
    • 2022-01-10
    • 1970-01-01
    相关资源
    最近更新 更多