Design do banco de dados - google app engine

Estou trabalhando com o Google App Engine e usando a API de baixo nível java para acessar a Big Table. Estou construindo um aplicativo SAAS com 4 camadas:

Navegador da Web do clienteCamada de recursos RESTfulCamada de negóciosCamada de acesso a dados

Estou criando um aplicativo para ajudar a gerenciar minha empresa de detalhamento automático de dispositivos móveis (e outras similares). Eu tenho que representar esses quatro conceitos separados, mas não tenho certeza se meu plano atual é bom:

CompromissosItens de linhaFaturasPagamentos

Compromisso: Um "Compromisso" é um local e horário em que os funcionários devem estar para prestar um serviço.

Item da linha: Um "Item de linha" é um serviço, taxa ou desconto e suas informações associadas. Um exemplo de itens de linha que podem entrar em um compromisso:

Name:                          Price: Commission: Time estimate   
Full Detail, Regular Size:        160       75       3.5 hours 
$10 Off Full Detail Coupon:       -10        0         0 hours 
Premium Detail:                   220      110       4.5 hours 
Derived totals(not a line item): $370     $185       8.0 hours

Fatura: Uma "Fatura" é um registro de um ou mais itens de linha pelos quais um cliente se comprometeu a pagar.

Forma de pagamento: Um "Pagamento" é um registro do recebimento dos pagamentos.

Em uma implementação anterior desse aplicativo, a vida era mais simples e eu tratei todos esses quatro conceitos como uma tabela em um banco de dados SQL: "Compromisso". Um "Compromisso" pode ter vários itens de linha, vários pagamentos e uma fatura. A fatura era apenas um e-mail ou impressão produzida a partir dos itens de linha e do registro do cliente.

9 em 10 vezes, isso funcionou bem. Quando um cliente marcou uma consulta para um ou alguns veículos e pagou por eles mesmos, tudo foi ótimo. Mas esse sistema não funcionou sob muitas condições. Por exemplo:

Quando um cliente marcou um horário, mas o horário foi marcado no meio do caminho, resultando no detalhamento h e anúncio para voltar no dia seguinte, eu precisava de dois compromissos, mas apenas um item de linha, uma fatura e um pagamento.Quando um grupo de clientes em um escritório decidiu fazer seus carros no mesmo dia para obter um desconto, eu precisava de um compromisso, mas várias faturas e vários pagamentos.Quando um cliente pagava dois compromissos com um cheque, eu precisava de dois compromissos, mas apenas uma fatura e um pagamento.

Eu era capaz de lidar com todos esses erros extraconjugais. Por exemplo, se um detalhista tivesse que voltar no dia seguinte, eu apenas marcaria outra consulta no segundo dia com um item de linha que dizia "Concluir" e o custo seria de US $ 0. Ou, se um cliente pagasse dois compromissos com um cheque, colocaria registros de pagamento divididos em cada compromisso. O problema disso é que ele cria uma enorme oportunidade para a congruência de dados. A congruência de dados pode ser um problema sério, especialmente nos casos que envolvem informações financeiras, como o terceiro exemplo em que o cliente pagou por dois compromissos com um cheque. Os pagamentos devem ser comparados diretamente com os bens e serviços prestados, a fim de acompanhar adequadamente as contas a receber.

Estrutura proposta:

Abaixo, há uma estrutura normalizada para organizar e armazenar esses dados. Talvez por causa da minha inexperiência, coloquei muita ênfase na normalização de dados, porque parece ser uma ótima maneira de evitar erros de incongruência de dados. Com essa estrutura, as alterações nos dados podem ser feitas com uma operação sem precisar se preocupar em atualizar outras tabelas. As leituras, no entanto, podem exigir várias leituras, juntamente com a organização dos dados na memória. Acho que mais tarde, se houver problemas de desempenho, posso adicionar alguns campos desnormalizados ao "Compromisso" para consultas mais rápidas, mantendo intacta a estrutura normalizada "segura". A desnormalização poderia diminuir a velocidade das gravações, mas eu estava pensando em poder fazer chamadas assíncronas para outros recursos ou adicionar à fila de tarefas, para que o cliente não precise esperar pelas gravações extras que atualizam as partes desnormalizadas dos dados .

Tabelas:

Appointment
 start_time
 etc...

Invoice
 due_date
 etc...

Payment
 invoice_Key_List
 amount_paid
 etc...

Line_Item
 appointment_Key_List
 invoice_Key
 name
 price
 etc...

A seguir, são apresentadas as séries de consultas e operações necessárias para vincular todas as quatro entidades (tabelas) para uma determinada lista de compromissos. Isso incluiria informações sobre quais serviços foram agendados para cada compromisso, o custo total de cada compromisso e o tempo ou o pagamento não recebido como recebido para cada compromisso. Essa seria uma consulta comum ao carregar o calendário para agendamento de compromissos ou para um gerente obter uma visão geral das operações.

QUERY para a lista de "Compromissos", que é o campo "start_time", fica entre o intervalo especificado.Adicione cada chave dos compromissos retornados a uma lista.QUERY para todos os campos "Line_Items" que possuem compromisso_key_List inclui qualquer um dos compromissos de devoluçãoAdicione cada invoice_key de todos os itens de linha em uma coleção de conjuntos.QUERY para todas as "Faturas" no conjunto de notas fiscais (isso pode ser feito em uma operação assíncrona usando o App Engine)Adicione cada chave das faturas retornadas a uma ListaQUERY para todos os campos "Payments" quem é invoice_key_list contém uma chave que corresponde a qualquer uma das faturas retornadasReorganize na memória para que cada compromisso reflita os itens de linha que estão agendados para ele, o preço total, o tempo total estimado e o tempo pelo qual foi pago ou não.

... Como você pode ver, esta operação requer 4 consultas ao armazenamento de dados e alguma organização na memória (espero que a memória seja muito rápida)

Alguém pode comentar sobre este design? Este é o melhor que pude apresentar, mas suspeito que possa haver opções melhores ou designs completamente diferentes nos quais não estou pensando que possam funcionar melhor em geral ou especificamente nos pontos fortes, fracos e recursos do GAE (Google App Engine) .

Obrigado!

Esclarecimento de uso

A maioria dos aplicativos é mais intensiva em leitura, alguns são mais intensivos em gravação. Abaixo, descrevo um caso de uso típico e operações de detalhamento que o usuário deseja executar:

O gerente recebe uma chamada de um cliente:

Ler - O gerente carrega o calendário e procura um horário disponívelEscreva - O gerente consulta as informações do cliente, imaginei que fosse uma sucessão de leituras assíncronas à medida que o gerente insere cada informação, como número de telefone, nome, email, endereço, etc ... Ou, se necessário, talvez uma gravação no final, depois que o aplicativo cliente reunir todas as informações e depois enviar.Escreva - O gerente retira as informações do cartão de crédito do cliente e as adiciona ao registro como uma operação separadaEscreva - O gerente cobra um cartão de crédito e verifica se o pagamento foi realizado

O gerente faz uma chamada telefônica:

Ler O gerente carrega o calendárioLer O gerente carrega o compromisso para o cliente para o qual deseja ligarEscreva O gerente clica no botão "Ligar", uma chamada é iniciada e uma nova entidade CallReacord é gravadaLer O servidor de chamada responde à solicitação de chamada e lê CallRecord para descobrir como lidar com a chamadaEscreva O servidor de chamadas grava informações atualizadas no CallRecordEscreva quando a chamada é fechada, o servidor de chamada faz outra solicitação ao servidor para atualizar o recurso CallRecord (nota: essa solicitação não é de tempo crítico)

Resposta aceita :: As duas respostas principais foram muito atenciosas e apreciadas. Aceitei aquele com poucos votos, a fim de igualar imperfeitamente sua exposição, tanto quanto possível.

questionAnswers(3)

yourAnswerToTheQuestion