Como os requisitos de negócios podem ser traduzidos em estruturas de dados específicas usando o exemplo de design de uma base "do zero" para um messenger?

Nosso banco de dados não será tão grande e distribuído
como o do VKontakte ou
Badoo , mas "estar", mas é bom - funcional, rápido e
se encaixa em um único servidor PostgreSQL - para que você possa implantar uma instância separada do serviço em algum lugar do lado, por exemplo.
Portanto, não abordaremos os problemas de sharding, replicação e sistemas de distribuição geográfica, mas focaremos nas soluções de circuitos dentro do banco de dados.
Etapa 1: um pouco de especificidade comercial
Não projetaremos nossas mensagens em abstrato, mas as incorporaremos no ambiente de
rede social corporativa . Ou seja, as pessoas aqui não estão apenas “enviando mensagens de texto”, mas se comunicando entre si no contexto de resolver certos problemas de negócios.
E quais são os desafios de negócios? ... Vejamos o exemplo de Vasily, chefe do departamento de desenvolvimento.
- "Nikolai, esse patch precisa desse patch hoje!"
Portanto, a correspondência pode ser conduzida no contexto de um documento . - "Kolya, vá para DotA à noite?"
Ou seja, mesmo com um par de interlocutores, a comunicação ao mesmo tempo pode ser conduzida em diferentes tópicos . - "Peter, Nikolai, veja o anexo de preços no novo servidor."
Portanto, uma mensagem pode ter vários destinatários . Nesse caso, a mensagem pode conter arquivos anexados . - "Semyon, e você também está."
E deve ser possível convidar um novo membro para uma correspondência existente.
Vamos nos debruçar sobre esta lista de necessidades "óbvias".
Sem uma compreensão das especificidades aplicadas da tarefa e das restrições definidas por ela, é praticamente impossível projetar um esquema de banco de dados eficaz para resolvê-la.
Etapa 2: Lógica Mínima
Até agora, tudo se parece muito com a correspondência por email - uma ferramenta comercial tradicional. Portanto, sim, “algoritmicamente”, muitas tarefas de negócios são semelhantes entre si e, portanto, as ferramentas para resolvê-las serão estruturalmente semelhantes.
Vamos corrigir o diagrama lógico resultante das relações das entidades. Para simplificar a compreensão de nosso modelo, usaremos a opção mais primitiva para exibir um
modelo de ER sem as complicações das notações UML ou IDEF:

Em nosso exemplo, a pessoa, o documento e o "corpo" binário do arquivo são entidades "externas" que existem independentemente sem o nosso serviço. Portanto, nós simplesmente os perceberemos no futuro como alguns links "em algum lugar" do UUID.
Desenhe os diagramas da maneira mais simples possível - a maioria daqueles a quem você os mostrará não são especialistas em ler UML / IDEF. Mas - não se esqueça de desenhar.
Etapa 3: esboçar a estrutura da tabela
Sobre nomes de tabela e campoOs nomes "russos" de campos e tabelas podem ser tratados de maneira diferente, mas isso é uma questão de gosto. Como não temos desenvolvedores estrangeiros
no “Tensor” , o PostgreSQL nos permite dar nomes mesmo com hieróglifos, se eles estiverem
entre aspas , preferimos nomear objetos de forma clara e sem ambiguidade, para que não haja mal-entendidos.
Como muitas pessoas escrevem mensagens ao mesmo tempo, algumas delas podem fazer isso
offline , a opção mais fácil é
usar UUIDs como identificadores, não apenas para entidades externas, mas para todos os objetos dentro de nosso serviço. Além disso, eles podem ser gerados mesmo no lado do cliente - isso nos ajudará a suportar o envio de mensagens com inacessibilidade a curto prazo do banco de dados, e a probabilidade de uma colisão é extremamente pequena.
A estrutura aproximada das tabelas em nosso banco de dados terá a seguinte aparência:
Mesas: RUCREATE TABLE ""( "" uuid PRIMARY KEY , "" uuid , "" text ); CREATE TABLE ""( "" uuid PRIMARY KEY , "" uuid , "" uuid , "" timestamp , "" text ); CREATE TABLE ""( "" uuid , "" uuid , PRIMARY KEY("", "") ); CREATE TABLE ""( "" uuid PRIMARY KEY , "" uuid , "BLOB" uuid , "" text );
Mesas: EN CREATE TABLE theme( theme uuid PRIMARY KEY , document uuid , title text ); CREATE TABLE message( message uuid PRIMARY KEY , theme uuid , author uuid , dt timestamp , body text ); CREATE TABLE message_addressee( message uuid , person uuid , PRIMARY KEY(message, person) ); CREATE TABLE message_file( file uuid PRIMARY KEY , message uuid , content uuid , filename text );
A maneira mais fácil de descrever o formato é começar a "desvendar" o gráfico dos links das tabelas que não se referem a ninguém.
Etapa 4: Descobrindo requisitos não óbvios
É isso, criamos uma base na qual você pode escrever e ler de
alguma forma .
Vamos nos colocar no lugar do usuário do nosso serviço - o que queremos fazer com ele?
- Posts recentes
Este é um registro de "minhas" mensagens ordenadas cronologicamente por várias características. Onde eu sou um dos destinatários, onde eu sou o autor, onde eles me escreveram, mas eu não respondi, onde eles não me responderam ... - Correspondentes
Quem está envolvido nesse longo e longo bate-papo?
Nossa estrutura nos permite resolver esses dois problemas "em geral", mas rapidamente - não. O problema é que, para classificar como parte da primeira tarefa,
é impossível criar um índice adequado para cada um dos participantes (e você precisará recuperar todos os registros) e, para resolver o segundo, é necessário
recuperar todas as mensagens sobre o tópico.
Tarefas imprevistas do usuário podem acabar com a produtividade .
Etapa 5: Desnormalização razoável
Ambos os nossos problemas ajudarão a resolver tabelas adicionais, nas quais
duplicaremos parte dos dados necessários para formar índices adequados para nossos problemas neles.

Mesas: RU CREATE TABLE ""( "" uuid , "" smallint , "" timestamp , "" uuid , PRIMARY KEY("", "", "") ); CREATE INDEX ON ""("", "", "" DESC); CREATE TABLE ""( "" uuid , "" uuid , PRIMARY KEY("", "") );
Mesas: EN CREATE TABLE message_registry( owner uuid , registry smallint , dt timestamp , message uuid , PRIMARY KEY(owner, registry, message) ); CREATE INDEX ON message_registry(owner, registry, dt DESC); CREATE TABLE theme_participant( theme uuid , person uuid , PRIMARY KEY(theme, person) );
Aqui nós aplicamos duas abordagens típicas usadas para criar tabelas auxiliares:
- Registros de multiplicação
Formamos vários registros de origem de uma vez a partir de um registro de origem da mensagem em diferentes tipos de registros para proprietários diferentes - tanto para o remetente quanto para o destinatário. Mas cada um dos registros agora está no índice - porque, no caso típico, queremos ver apenas a primeira página. - Exclusão de registro
Cada vez que você envia uma mensagem em um tópico específico, basta verificar se essa entrada já existe. Caso contrário, adicione-o ao nosso "dicionário".
Na próxima parte do artigo, discutiremos a
implementação de seções na estrutura de nosso banco de dados.