2011-09-29 4 views
0

Je construis un système de comptabilité distribuée. Pour ce qui est de la structure et des exigences de la base de données, il est probablement plus facile de décrire l'application comme une application semblable à Twitter, mais avec une structure de base de données hiérarchique de 14 tables. Une entreprise qui utilise l'application peut avoir 1 utilisateur et plus, tous partageant les informations de l'entreprise.Conseil de conception de magasin de données AppEngine requis

Actuellement, chaque entité représente un type d'enregistrement, à savoir les clients, les factures, etc. Toutes les entités ont un parent qui est l'utilisateur de l'application. (pour des raisons de cohérence des requêtes HRD)

Chaque requête sur la base de données comprend 14 requêtes AppEngine. Un pour chaque table. La requête implique le filtrage des propriétés.

Une nouvelle exigence est qu'une requête d'un utilisateur peut nécessiter des valeurs de propriété différentes en fonction de chacun des autres utilisateurs. Cela signifie que nous avons besoin de 14 requêtes AppEngine (14 fois le nombre d'entreprises-utilisateurs). Cela semble beaucoup trop.

kind Ancêtre requêtes qui peuvent filtrer par des propriétés serait vraiment bien, hélas, ne peut faire :)

Mes options sont:

  1. Set type d'entité à l'utilisateur. Pas de parent. Cela signifie que tous les types d'enregistrements sont mixés. (Les champs filtrés existent dans tous les types d'enregistrement). Ce n'est pas joli. Mais le considèreriez-vous? Vous avez un type d'entité fixe et une requête par filtre uniquement.

  2. Le résultat est l'équivalent des requêtes Ancêtres sans kind. Cependant, je crains que ce soit lent dans une utilisation multi-utilisateur.

Quelques chiffres: Nous prévoyons de 10.000 entreprises, moyenne de 5 utilisateurs par entreprise et 1 à 5 millions d'enregistrements par type d'enregistrement. (X 14 pour un total)

Merci de patienter jusqu'à présent .. :)

+0

Pourquoi chaque requête nécessite-t-elle d'interroger toutes les tables? Cela semble être une exigence très étrange. –

+0

@Nick, l'application a un DB distribué. Chaque client dispose d'une copie locale de la base de données avec des informations pertinentes pour ce client. Chaque requête doit trouver toutes les informations nouvelles/modifiées dans l'ensemble de la base de données et transférer les données au client pour un usage local. (chaque requête trouvera des changements dans presque toutes les tables) – OferR

Répondre

1

Honnêtement, je trouve qu'il est difficile de suivre votre description, donc cela peut être hors de la base. Voir votre code existant pourrait vous aider. Mais je comprends que vous voulez une alternative efficace aux requêtes des ancêtres sans gentils, alors commençons là.

Tenir compte dénormaliser votre modèle de données pour inclure une méta-entité simplement pour effectuer des requêtes:

class User(db.Model): 
    pass 

class OwnedObject(db.Expando): 
    object_key = db.StringProperty() 

class Customer(db.Model): 
    name = db.StringProperty() 
    created_on = db.DateProperty() 

class Invoice(db.Model): 
    amount = db.IntegerProperty() 
    created_on = db.DateProperty() 

# on write 
customer = Customer() 
customer.name = name 
customer.created_on = date.today() 
customer.put() 

user = User(key_name=users.get_current_user().user_id()) 

owned_object = OwnedObject(parent=user) 
owned_object.object_key = customer.key() 
owned_object.created_on = customer.created_on 
owned_object.put() 

# on read 
query = OwnedObject.all() 
query.ancestor(user) 
query.filter('created_on =', date.today()) 

entities = db.get([x.object_key for x in query]) 

donc ici que vous faites plus de travail d'écriture et de moins en lecture.

Chaque entité réelle est couplée à une entité OwnedObject qui descend de l'ancêtre approprié et pointe vers la clé de l'entité réelle. OwnedObject est un expando, vous allez donc assigner toutes les propriétés sur lesquelles vous voulez interroger (dans cet exemple, created_on). En lecture, vous pouvez rechercher les propriétés que vous avez copiées dans la méta-entité expando, et vous pouvez récupérer tous les objets d'un utilisateur avec un temps système fixe d'une requête et d'un batch.

Modifier: Vous pouvez accomplir quelque chose de similaire sans la méta-entité en utilisant PolyModel.

+0

Merci @Drew. Vous avez compris ma question à 100%. Par rapport à l'option de solution 1 (dans le corps de la question), votre solution présente l'avantage de garder les entités de base dans une «Entité par type d'enregistrement» gérable. L'inconvénient est d'ajouter le surcoût de la maintenance de la méta-entité et de la lecture en deux étapes. Croyez-vous que ça vaut le coup? Est-ce qu'une entité désordonnée comme dans l'option 1 est un grand non-non? Qu'en penses-tu? – OferR

+0

Je suppose que votre exemple en utilisant JDO que je ne connais pas, mais je crois que j'ai eu l'idée. Comment jdo implémente-t-il la dernière ligne (db.get ([...]) Je suppose que jdo lance plusieurs db.get() sous le capot puisque la plateforme IN() est limitée à 30 éléments (va lire PolyModel) – OferR

+0

Je suppose que ma première supposition était fausse, c'est Python :) (J'utilise java + classes AppEngine natives). PolyModel ne semble pas correspondre à mon design DB. Il gère naturellement les données d'un type similaire (héritage). Expando, d'un autre côté, est un moyen d'implémenter l'option 1 de ma solution. – OferR

Questions connexes