2017-04-12 4 views
2

나는 Datomic 데이터베이스에이와 비슷한 스키마가 있습니다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 초가 걸릴 수 있습니다. 나는 여기서 분명히 잘못된 것을하고 있습니까? 이 속도를 높일 수 있습니까?

업데이트 : 전체 데이터 세트는 대략 2GB이고 피어는 3.5GB의 메모리를 가지고 있습니다 (하지만 1.5Gb로 줄이면 아무런 차이가없는 것 같습니다). 트랜잭션 처리기에 1GB의 메모리가 있습니다. . 나는 Datomic Free를 사용하고 있습니다. 당신이 등 프로파일 링을 시작하기 전에

+0

병목 현상을 찾기 위해 코드의 프로파일을 작성했다면 도움이 될 것입니다. Tufte 라이브러리를 사용하여이를 수행 할 수 있습니다. –

+0

엔티티가 아닌 끌어 오기 API를 사용하면 더 나은 결과를 얻을 수 있습니다 (나중에 반환 된 결과를 변환 할 수 있음). –

+0

@ValentinWaeselynck는 팁을 주셔서 감사 드리며, 다시 시도하겠습니다. – Johan

답변

2

당신은 피어 라운드 트립의 수를 줄일 수있어 task-entities에 대한지도 문을 제거

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

에 의해

[:find ?taskIds ...] 

을 대체 할 수있다. 두 번째 단계에서 [*]을 각 엔티티에 대해 실제로 가져 오려는 적절한 키 세트로 바꿉니다.

+0

저는 이것을 시도해 보았습니다. 저의 인상은 조금 더 빨라지지만 약 20 초 정도는 평균을 내고 있다는 것입니다. 본질적으로 나는 모든 키를 가져 와서 [*] 대체하는 것이별로 중요하지 않다고 생각합니다. 내가 할 수있는 다른 것이 있습니까? – Johan

+0

죄송합니다. 잘 모르겠습니다. tenant/guid는 고유하므로 인덱스를 올바르게 설정해야합니다. 내가 알아챈 유일한 점은 스키마에서 다음과 같은 오타가 있다는 것입니다. : db/ident : tenant/taks – fricke

+0

또한 특정 속성을 가져 오려고했으나 아무런 차이가없는 것 같습니다. Datomic Pro를 사용하고 Datomic Free를 사용하는 대신 SQL을 백엔드로 사용할 가치가 있다고 생각하십니까? – Johan