Meu projeto atual é essencialmente uma execução do sistema de gerenciamento de documentos do moinho.
Dito isto, existem algumas rugas (surpresa, surpresa). Embora algumas das rugas sejam bastante específicas para o projeto, acredito que surgiram algumas observações e perguntas gerais que não têm uma resposta canônica (que eu poderia encontrar de qualquer maneira) e que são aplicáveis a um domínio de problemas mais amplo . Há muita coisa aqui e não tenho certeza se é uma boa opção para o formato de perguntas e respostas do StackExchange, mas acho que a) é uma pergunta respondível eb) não é específica o suficiente para beneficiar a comunidade. Algumas de minhas considerações são específicas para mim, mas acho que a pergunta pode ser útil para qualquer pessoa que esteja enfrentando a decisão de SQL vs NoSQL vs ambos.
O fundo:
O aplicativo da web que estamos construindo contém dados claramente de natureza relacional, bem como dados orientados a documentos. Gostaríamos de ter o nosso bolo e comê-lo também.
TL; DR: Acho que o 5º abaixo passa no teste de olfato. Você? Alguém tem experiência com essa integração de SQL e NOSQL em um único aplicativo? Tentei listar todas as abordagens possíveis para essa classe de problema abaixo. Perdi uma alternativa promissora?
Complexidades:
- Existem muitas classes diferentes de documentos. Os requisitos já exigem dezenas de documentos diferentes. Esse número apenas aumentará. O melhor caso possível seria aquele em que poderíamos aproveitar uma linguagem simples específica de domínio, geração de código e um esquema flexível para que especialistas em domínio pudessem lidar com a adição de novas classes de documentos sem a intervenção de DBAs ou programadores. (Nota: já estamos cientes de que estamos vivendo a Décima Regra de Greenspun )
- A integridade de gravações bem-sucedidas anteriores é um requisito central do projeto. Os dados serão críticos para os negócios. A semântica completa do ACID nas gravações pode ser sacrificada, desde que as coisas que são gravadas com êxito permaneçam escritas.
- Os documentos são complexos. O protótipo de documento em nosso caso específico exigirá o armazenamento de mais de 150 partes distintas de dados por instância do documento. O caso patológico poderia ser uma ordem de magnitude pior, mas certamente não duas.
- Uma única classe de documentos é um destino em movimento sujeito a atualizações posteriormente.
- Gostamos do material gratuito que obtemos do Django quando o conectamos a um banco de dados relacional. Gostaríamos de manter os brindes sem precisar voltar duas versões do Django para usar o fork do django-nonrel. Despejar o ORM inteiramente é preferível a fazer o downgrade para 1.3.
Essencialmente, é uma mistura de dados relacionais (seus aplicativos típicos de aplicativos da Web, como usuários, grupos etc.), além de metadados de documentos que precisaremos ser capazes de dividir e cortar com consultas complexas em tempo real) e dados de documentos (por exemplo, as centenas de campos nos quais não temos interesse em ingressar ou consultar - nosso único caso de uso para os dados será mostrar o documento único no qual ele foi inserido).
Eu queria fazer uma verificação de sanidade (se você verificar meu histórico de postagens, sou bastante explícito sobre o fato de não ser um DBA) no meu método preferido, além de enumerar todas as opções que encontrei para outras pessoas resolverem problemas amplamente semelhantes envolvendo dados relacionais e não relacionais.
Soluções propostas:
1. Uma tabela por classe de documento
Cada classe de documento obtém sua própria tabela, com colunas para todos os metadados e dados.
Vantagens:
- O modelo de dados SQL padrão está em jogo.
- Os dados relacionais são tratados da melhor maneira possível. Desnormalizaremos mais tarde, se precisarmos.
- A interface administrativa interna do Django é confortável com a inspeção dessas tabelas e o ORM pode viver feliz com 100% dos dados prontos para uso.
Desvantagens:
- Pesadelo de manutenção. Dezenas (centenas?) De tabelas com (dezenas de?) Milhares de colunas.
- Lógica no nível do aplicativo responsável por decidir exatamente em qual tabela gravar. Tornar o nome da tabela um parâmetro para uma consulta fede.
- Basicamente, todas as alterações na lógica de negócios exigirão alterações no esquema.
- Casos patológicos podem exigir a distribuição de dados para formulários únicos em várias tabelas (consulte: Qual é o número máximo de colunas em uma tabela do PostgreSQL? ).
- Provavelmente precisaríamos encontrar um DBA real e honesto com Deus que, sem dúvida, acabaria odiando a vida e a nós.
2. Modelagem de EAV
Existe apenas uma tabela de campos. A modelagem de Entidade-Atributo-Valor já está bem compreendida. Eu o incluí por completo. Eu não acho que nenhum novo projeto que esteja sendo iniciado em 2013 iria com uma abordagem de EAV de propósito.
Vantagens:
- Fácil de modelar.
Desvantagens:
- Mais difícil de consultar.
- A camada do banco de dados não tem mais uma representação direta do que constitui um objeto no nível do aplicativo.
- Perderíamos a verificação de restrição no nível do banco de dados.
- O número de linhas em uma tabela aumentará de 100 a 1000 vezes mais rápido. Provável dor no futuro, em termos de desempenho.
- Possibilidade de indexação limitada.
- O esquema do banco de dados é absurdo no que diz respeito ao ORM. As baterias incluídas incluem itens de aplicativos da web, mas os modelos de dados personalizados exigirão consultas personalizadas.
3. Use os campos hstore ou json do PostgreSQL
Qualquer um desses tipos de campo faria o truque para armazenar dados sem esquema no contexto de um banco de dados relacional. A única razão que eu não saltar a esta solução imediatamente é que é relativamente novo (introduzido na versão 8.4, portanto, não que novo), eu tenho zero, exposição prévia a ele e eu sou suspeito. Parece-me errado pelas mesmas razões pelas quais eu me sentiria desconfortável jogando todos os meus dados legais e facilmente normalizados no Mongo - mesmo que o Mongo possa lidar com referências entre documentos.
Vantagens:
- Nós obtemos os benefícios do Django ORM e o gerenciamento de autenticação e sessão embutido.
- Tudo fica em um back-end que usamos anteriormente em outros projetos com sucesso.
Desvantagens:
- Nenhuma experiência com isso, pessoalmente.
- Não parece um recurso muito usado. Parece que eles são recomendados bastante para as pessoas que procuram soluções NOSQL, mas não vejo muitas evidências de que elas estejam sendo escolhidas. Isso me faz pensar que devo estar perdendo alguma coisa.
- Todos os valores armazenados são cadeias de caracteres. Perca a verificação de restrição no nível do banco de dados.
- Os dados no hstore nunca serão exibidos para o usuário, a menos que eles visualizem um documento especificamente, mas os metadados armazenados em mais colunas padrão serão. Nós estaremos superando esses metadados e eu me preocupo que os grandes hstores que criaremos possam ter desvantagens de desempenho.
4. Vá totalmente orientado para documentos
Faça todos os documentos de coisas (no sentido do MongoDB). Crie uma única coleção do tipo Document
e chame-a de dia. Traga todos os dados periféricos (incluindo dados de contas de usuários, grupos etc.) para o mongo também. Essa solução é obviamente melhor do que a modelagem EAV, mas parece errada para mim pela mesma razão que o número 3 parecia errado - eles também querem usar o martelo como chave de fenda.
Vantagens:
- Não há necessidade de modelar dados antecipadamente. Tenha uma coleção com documentos do tipo
Document
e termine o dia. - Boas características de escala conhecidas, caso a coleção precise crescer para abranger milhões ou até bilhões de documentos.
- O formato JSON (BSON) é intuitivo para desenvolvedores.
- Pelo que entendi (que é apenas vagamente neste momento), sendo paranóico em relação ao nível de preocupação com a gravação, mesmo uma única instância pode fornecer segurança de dados bastante forte no caso de qualquer coisa e tudo até uma falha no disco rígido.
Desvantagens:
- O ORM está fora da janela para o tronco do Django. Brindes que saem pela janela com ele: a estrutura de autenticação, a estrutura de sessões, a interface de administração, certamente muitas outras coisas.
- É necessário usar os recursos de referência do mongo (que exigem várias consultas) ou desnormalizar os dados. Não apenas perdemos brindes que obtivemos do Django, como também perdemos brindes como JOINs que tínhamos como certo no PostgreSQL.
- Segurança de dados. Quando se lê sobre o MongoDB, parece que sempre há pelo menos uma pessoa se referindo a como isso aumentará e perderá seus dados. Eles nunca citam uma ocorrência específica e tudo pode ser apenas besteira ou apenas relacionado ao antigo incêndio padrão e esquecer a preocupação com a gravação, mas isso ainda me preocupa. Obviamente, estaremos utilizando uma estratégia de backup bastante paranóica em qualquer caso (se os dados forem corrompidos silenciosamente, isso poderia ser irrelevante, é claro).
5. PostgreSQL e MongoDB
Os dados relacionais entram no banco de dados relacional e os dados do documento no banco de dados orientado a documentos. A documents
tabela no banco de dados relacional contém todos os dados que podemos precisar indexar ou fatiar e dividir, além de um MongoDB ObjectId que usaríamos quando precisássemos consultar os valores reais dos campos nos documentos. Não poderíamos usar o ORM ou o administrador interno para os valores dos próprios documentos, mas isso não é uma grande perda, já que todo o aplicativo é basicamente uma interface administrativa para os documentos e provavelmente teríamos que personalize essa parte específica do ORM em um grau inaceitável para fazê-lo funcionar da maneira que precisamos.
Vantagens:
- Cada back-end faz apenas o que é bom.
- As referências entre modelos são preservadas sem exigir várias consultas.
- Nós mantemos as baterias que o Django nos deu no que diz respeito a usuários, sessões etc.
- Precisa apenas de uma
documents
tabela, não importa quantas classes diferentes de documentos sejam criadas. - Os dados do documento menos frequentemente consultados são fortemente separados dos metadados mais frequentemente consultados.
Desvantagens:
- A recuperação de dados do documento exigirá 2 consultas seqüenciais, primeiro no SQL DB e depois no MongoDB (embora isso não seja pior do que se os mesmos dados tivessem sido armazenados no Mongo e não desnormalizados)
- A escrita não será mais atômica. Uma gravação em um único documento do Mongo é garantida como atômica e o PG obviamente pode garantir a atomicidade, mas garantir a atomicidade da gravação em ambos exigirá lógica do aplicativo, sem dúvida com uma penalidade de desempenho e complexidade.
- Dois back-end = duas linguagens de consulta = dois programas diferentes com requisitos de administração diferentes = dois bancos de dados disputando memória.
JSON
tipo de dados. Não tenha medo de usar novos recursos no Postgres - a equipe do Postgres não libera recursos que não são estáveis. E 9.2 não é tão novo assim). Além disso, você pode usar os novos recursos JSON na 9.3, uma vez lá. Se você estiver sempre processando totalmente os documentos no código do aplicativo (em vez de usar o SQL), também poderá armazenar o JSON em umatext
coluna regular .