我目前正在我的一个项目中使用Datomic,一个问题困扰着我。
以下是我的问题的简化版本:
为了简化插入过程,我很想多次写相同的数据(即不检查数据库中是否已存在记录)。但我担心性能影响。
是否值得检查在交易之前是否已添加数据?
有没有办法阻止Datomic覆盖以前的数据(即如果记录已存在,请跳过该事务)?
感谢您的帮助
答案 0 :(得分:2)
- 多次添加相同数据时,Datomic会发生什么?
- 是否值得检查在交易之前是否已添加数据?
逻辑上,Datomic数据库是一组有序的数据,因此多次添加相同的数据是幂等的。但是,当您使用tempid声明数据时,可以创建一个新数据来表示与旧数据相同的信息。这是:db/unique
的用武之地。
为确保实体不会多次存储,您需要将:db/unique
属性属性设置为:db.unique/identity
以获取正确的属性。例如,如果您的架构由3个属性:word/text
,:sentence/text
和:sentence/words
组成,则:word/text
和:sentence/text
应为:db.unique/identity
,其中产生以下架构安装事务:
[{:db/cardinality :db.cardinality/one,
:db/fulltext true,
:db/index true,
:db.install/_attribute :db.part/db,
:db/id #db/id[:db.part/db -1000777],
:db/ident :sentence/text,
:db/valueType :db.type/string,
:db/unique :db.unique/identity}
{:db/cardinality :db.cardinality/one,
:db/fulltext true,
:db/index true,
:db.install/_attribute :db.part/db,
:db/id #db/id[:db.part/db -1000778],
:db/ident :word/text,
:db/valueType :db.type/string,
:db/unique :db.unique/identity}
{:db/cardinality :db.cardinality/many,
:db/fulltext true,
:db/index true,
:db.install/_attribute :db.part/db,
:db/id #db/id[:db.part/db -1000779],
:db/ident :sentence/words,
:db/valueType :db.type/ref}]
然后插入插入的事务如下:
[{:sentence/text "Hello World!"
:sentence/words [{:word/text "hello"
:db/id (d/tempid :db.part/user)}
{:word/text "world"
:db/id (d/tempid :db.part/user)}]
:db/id (d/tempid :db.part/user)}]
您可能根本不需要进行优化,但在我看来,导入流程的潜在性能瓶颈是:
改进2.
:当您插入的数据被排序时,索引更快,因此可以插入单词和句子。您可以使用Unix工具对大文件进行排序,即使它们不适合内存。所以过程将是:
:sentence/text
):word/text
):sentence/words
)改进1.
:实际上,它可以减少交易者施加压力,使用实体ID来存储已经存储的单词而不是整个单词文本(这需要索引查找以确保唯一性)。一个想法可能是通过利用并行性和/或仅针对频繁的单词来对Peer执行查找(例如,您可以插入前1000个句子中的单词,然后检索它们的实体ID并将它们保存在哈希映射中)。
就个人而言,在经验表明它们是必要的之前,我不会经历这些优化。
答案 1 :(得分:1)
您不需要担心像这样的预优化。零售电脑商店以大约0.05美元/ GB的价格出售硬盘,所以你在这里谈论的是50美分的存储空间。使用Datomic的内置存储压缩,这将更小。指数&其他开销会增加总量,但它仍然太小而无法担心。
与任何问题一样,最好逐步建立解决方案。因此,也许用最前面1%的数据和时间进行实验,这是最简单的算法。如果这很快,请尝试10%。您现在可以很好地估计整个问题加载数据所需的时间。我打赌,查询数据会比加载更快。
如果您在前1%或10%之后遇到障碍,那么您可以考虑重新设计。既然你已经建造了具体的东西,你就不得不考虑这个问题。解决方案更详细。这比挥手的论点要好得多。白板设计。您现在对数据和可能的解决方案实施有了更多了解。
如果事实证明最简单的解决方案无法在更大范围内发挥作用,那么第二种解决方案将更容易设计和安装。具有第一解决方案经验的工具。最终的解决方案很少会从你的脑海中完全形成。计划重复改进解决方案对任何重大问题都非常重要。
这本开创性书籍中我最喜欢的章节之一 弗雷德布鲁克斯的 神话人月 的标题是“计划扔掉一个”。
答案 2 :(得分:1)
- 多次添加相同数据时,Datomic会发生什么?
如果要添加带有唯一标识的单词/句子(:db.unique / identity),那么Datomic将只在存储中保留一个副本(即单个实体)
- 是否值得检查在交易之前是否已添加数据?
- 有没有办法阻止Datomic覆盖以前的数据(即如果已存在记录,请跳过该事务)?*
再次使用:db.unique / identity,然后您不需要查询实体ID来检查它的存在。
有关详细信息,请参阅here