2

我目前正在实现一些依赖于 SQLite 数据库的功能。在这样做的同时,我遇到了一个我没有预料到的限制。这让我想知道我是否以正确的方式解决我的问题。我希望有人可以提出一种考虑要求的不同方法。

目标

目标是尽可能快地将大量对象集合存储到数据库中。但是,如果在任何时候确定不应存储这些对象,则该操作不应对数据库产生任何影响。确切的存储查询(“插入”)取决于以前的插入。

用例

考虑一个非常大的“实例信息包”集合,每个包代表一些相应抽象实例的部分知识。因此,总集合代表了一个或多个抽象实例的完整知识。每个包裹的信息包括:

  1. 一个instance_id;用于唯一标识与此信息相关的抽象实例。
  2. 属性图;(attribute_uri, attribute_value)-pairs 其中attribute_uri 唯一标识一个属性,attribute_value 是对应的文本值。

instance_id 和attribute_id 都在表中找到,分别为TBL_INSTANCES 和TBL_ATTRIBUTES。这里使用的数据库模型是 EAV 模型。

插入后,表 TBL_ENTRIES 应包含以下形式的条目:

[ entry_id | instance_id | attribute_id | attribute_value ]

问题

实现似乎很简单:

  1. 设置保存点
  2. 开始交易
  3. 为 TBL_ENTRIES 中的许多插入准备语句
  4. 对于集合中的每个实例:
    • 4.1。在 TBL_INSTANCES 中查找 instance_id。如果不存在,将其添加到 TBL_INSTANCES
    • 4.2. 对于实例的属性映射中的每个属性:
      • 4.2.1。在 TBL_ATTRIBUTES 中查找 attribute_id。如果不存在,请将其添加到 TBL_ATTRIBUTES。
      • 4.2.2. 向 TBL_ENTRIES 添加条目
  5. 如果在任何时候发生错误,则回滚到保存点,否则提交。

不幸的是,在查找步骤(4.1 和 4.2.1)中,SQLite 报告“无法在事务中启动事务”错误。阅读文档,它似乎在于查找调用 sqlite3_exec 例程的事实,它(除非我弄错了)似乎在内部设置了一个事务。

问题

如果不允许嵌套事务,我应该如何执行查找步骤(基本上是“插入或替换”表达式,然后是“选择”查询)?有什么方法可以避免它们或在当前事务中使用 sqlite3_exec 吗?如果不是,我是否以错误的方式处理我的问题?也许我不应该使用单独的整数作为键,例如直接使用attribute_uri 作为键而不是查找相应的attribute_id。

在任何情况下,我仍然需要在事务期间做一些等效的事情,因为真正的速度增益在于准备针对实例集合而不是属性集合的语句:一个实例可能只有一个或两个属性,而实例的数量在实例集合中总是会很大。

我正在使用 C/C++,SQLite 3.7。

非常感谢对我的方法的任何建议或评论!

4

1 回答 1

5

来自BEGIN TRANSACTION 的 SQLite 文档

使用 BEGIN...COMMIT 创建的事务不会嵌套。对于嵌套事务,使用 SAVEPOINT 和 RELEASE 命令

我似乎记得任何 SQLite 3.7.* 都应该已经存在嵌套事务。

于 2013-01-21T18:19:32.823 回答