Datomic查询性能改进

时间:2017-04-12 05:44:54

标签: clojure datomic datalog

我在Datomic数据库中有一个与此类似的模式:

; --- tenant
{:db/id                 #db/id[:db.part/db]
 :db/ident              :tenant/guid
 :db/unique             :db.unique/identity
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :tenant/name
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :tenant/taks
 :db/valueType          :db.type/ref
 :db/cardinality        :db.cardinality/many
 :db.install/_attribute :db.part/db}

; --- task
{:db/id                 #db/id[:db.part/db]
 :db/ident              :task/guid
 :db/unique             :db.unique/identity
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :task/createdAt
 :db/valueType          :db.type/instant
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :task/name
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :task/subtasks
 :db/valueType          :db.type/ref
 :db/cardinality        :db.cardinality/many
 :db.install/_attribute :db.part/db}

; --- subtask
{:db/id                 #db/id[:db.part/db]
 :db/ident              :subtask/guid
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db/unique             :db.unique/identity
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :subtask/type
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :subtask/startedAt
 :db/valueType          :db.type/instant
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :subtask/completedAt
 :db/valueType          :db.type/instant
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :subtask/participants
 :db/valueType          :db.type/ref
 :db/cardinality        :db.cardinality/many
 :db.install/_attribute :db.part/db}

 ; --- participant
{:db/id                 #db/id[:db.part/db]
 :db/ident              :participant/guid
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db/unique             :db.unique/identity
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :participant/name
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}     

随着时间的推移,任务非常静态,但每个任务每5分钟平均增加和删除子任务一次。我会说,每个任务在任何给定时间平均有大约40个子任务包含(几乎总是但有一些例外)一个参与者。我使用Datomic的唯一目的是能够看到任务随着时间的推移如何演变,即我希望看到在给定时间任务的样子。为了实现我目前正在做类似的事情:

(defn find-tasks-by-tenant-at-time 
    [conn tenant-guid ^long time-epoch]
    (let [db-conn (-> conn d/db (d/as-of (Date. time-epoch)))
          task-ids (->> (d/q '[:find ?taskIds
                              :in $ ?tenantGuid
                              :where
                              [?tenantId :tenant/guid ?tenantGuid]
                              [?tenantId :tenant/tasks ?taskIds]]
                            db-conn tenant-guid)
                       vec flatten)
          task-entities (map #(d/entity db-conn %) task-ids)
          dtos (map (fn [task]
                (letfn [(participant-dto [participant]
                          {:id   (:participant/guid participant)
                           :name (:participant/name participant)})
                        (subtask-dto [subtask]
                          {:id           (:subtask/guid subtask)
                           :type         (:subtask/type subtask)
                           :participants (map participant-dto (:subtask/participants subtask))})]
                  {:id       (:task/guid task)
                   :name     (:task/name task)
                   :subtasks (map subtask-dto (:task/subtasks task))})) task-entities)]
          dtos))

不幸的是,这非常慢。如果租户(比如说20个)有很多任务,每个包含大约40个子任务,则从此功能返回可能需要将近60秒。我在做一些明显不对的事吗?是否有可能加快速度?

更新: 整个数据集大约是2 Gb而对等方有3.5Gb的内存(但是如果我把它减少到1.5 Gb似乎没有任何区别)并且交易者有1 Gb的内存。我正在使用Datomic Free。

1 个答案:

答案 0 :(得分:2)

在开始分析之前,您可以替换

[:find ?taskIds ...]

通过

[:find (pull ?task-entity [*]) ...]

减少到对等点的往返次数,从而摆脱task-entities的map语句。在第二步中,将[*]替换为您真正想要为每个实体提取的适当密钥集。