2017-04-12 4 views
2

J'ai un schéma qui ressemble à ceci dans une base de données Datomic:améliorations Datomic de performances des requêtes

; --- 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}  

Les tâches sont assez statiques au fil du temps, mais les sous-tâches sont ajoutés et supprimés en moyenne environ une fois par 5 minutes par tâche . Je dirais que chaque tâche en moyenne a environ 40 sous-tâches à un moment donné contenant (presque toujours, mais il y a quelques exceptions) un participant. Mon seul objectif d'utiliser Datomic est de pouvoir voir comment les tâches ont évolué au fil du temps, c'est-à-dire que j'aimerais voir à quoi ressemblait une tâche à un moment donné. Pour atteindre je suis en train de faire quelque chose de similaire à ceci:

(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)) 

Malheureusement c'est extrêmement lent. Le retour de cette fonction peut prendre près de 60 secondes s'il y a beaucoup de tâches pour un locataire (disons 20) contenant chacune environ 40 sous-tâches. Est-ce que je fais quelque chose qui cloche mal ici? Est-il possible d'accélérer cela? L'ensemble de données est d'environ 2 Go et l'homologue a 3,5 Go de mémoire (mais cela ne semble pas faire de différence si je le diminue pour dire 1,5 Go) et le transcript a 1 Go de mémoire . J'utilise Datomic Free.

+0

Il serait plus facile de vous aider si vous aviez profilé votre code pour trouver les goulots d'étranglement. Vous pouvez utiliser la bibliothèque Tufte pour cela. –

+0

Vous pouvez obtenir de meilleurs résultats en utilisant l'API Pull plutôt que des entités (vous pouvez transformer les résultats retournés par la suite) –

+0

@ValentinWaeselynck merci pour le conseil, je vais essayer et revenir. – Johan

Répondre

2

Avant de commencer le profilage, etc., vous pouvez remplacer

[:find ?taskIds ...] 

par

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

pour réduire le nombre de voyages aller-retour au pair et ainsi se débarrasser de la déclaration de carte pour task-entities. Dans une seconde étape, remplacez [*] par l'ensemble de clés approprié que vous voulez vraiment extraire pour chaque entité.

+0

J'ai essayé cela et mon impression est que cela accélère un peu, mais il est encore en moyenne sur environ 20 secondes ou plus. Essentiellement, je veux tirer toutes les clés, donc je ne pense pas que remplacer [*] serait très important. Y at-il autre chose que je peux essayer? – Johan

+0

désolé, je ne sais pas; Les index doivent être définis correctement car: locataire/guid est unique. La seule chose que j'ai remarqué est la faute de frappe suivante dans le schéma: : db/ident: locataire/prend – fricke

+0

J'ai aussi essayé de tirer des attributs spécifiques maintenant, mais cela ne semble pas faire de différence. Pensez-vous qu'il serait utile d'essayer Datomic Pro et d'avoir SQL comme backend au lieu d'utiliser Datomic Free? – Johan