我目前正在实现一些依赖于 SQLite 数据库的功能。在这样做的同时,我遇到了一个我没有预料到的限制。这让我想知道我是否以正确的方式解决我的问题。我希望有人可以提出一种考虑要求的不同方法。
目标
目标是尽可能快地将大量对象集合存储到数据库中。但是,如果在任何时候确定不应存储这些对象,则该操作不应对数据库产生任何影响。确切的存储查询(“插入”)取决于以前的插入。
用例
考虑一个非常大的“实例信息包”集合,每个包代表一些相应抽象实例的部分知识。因此,总集合代表了一个或多个抽象实例的完整知识。每个包裹的信息包括:
- 一个instance_id;用于唯一标识与此信息相关的抽象实例。
- 属性图;(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 ]
问题
实现似乎很简单:
- 设置保存点
- 开始交易
- 为 TBL_ENTRIES 中的许多插入准备语句
- 对于集合中的每个实例:
- 4.1。在 TBL_INSTANCES 中查找 instance_id。如果不存在,将其添加到 TBL_INSTANCES
- 4.2. 对于实例的属性映射中的每个属性:
- 4.2.1。在 TBL_ATTRIBUTES 中查找 attribute_id。如果不存在,请将其添加到 TBL_ATTRIBUTES。
- 4.2.2. 向 TBL_ENTRIES 添加条目
- 如果在任何时候发生错误,则回滚到保存点,否则提交。
不幸的是,在查找步骤(4.1 和 4.2.1)中,SQLite 报告“无法在事务中启动事务”错误。阅读文档,它似乎在于查找调用 sqlite3_exec 例程的事实,它(除非我弄错了)似乎在内部设置了一个事务。
问题
如果不允许嵌套事务,我应该如何执行查找步骤(基本上是“插入或替换”表达式,然后是“选择”查询)?有什么方法可以避免它们或在当前事务中使用 sqlite3_exec 吗?如果不是,我是否以错误的方式处理我的问题?也许我不应该使用单独的整数作为键,例如直接使用attribute_uri 作为键而不是查找相应的attribute_id。
在任何情况下,我仍然需要在事务期间做一些等效的事情,因为真正的速度增益在于准备针对实例集合而不是属性集合的语句:一个实例可能只有一个或两个属性,而实例的数量在实例集合中总是会很大。
我正在使用 C/C++,SQLite 3.7。
非常感谢对我的方法的任何建议或评论!