Banco de dados do Messenger (parte 1): projetando a estrutura base

Como você pode traduzir requisitos de negócios em estruturas de dados específicas usando o exemplo de criação de um banco de dados de mensageiro do zero.

Banco de dados do Messenger (parte 1): projetando a estrutura base
Nossa base não será tão grande e distribuída, como VKontakte ou Badoo, mas “para que fosse”, mas foi bom - funcional, rápido e caber em um servidor PostgreSQL - para que você possa implantar uma instância separada do serviço em algum lugar paralelo, por exemplo.

Portanto, não abordaremos questões de sharding, replicação e sistemas geodistribuídos, mas focaremos em soluções de circuitos dentro do banco de dados.

Etapa 1: algumas especificidades do negócio

Não projetaremos nossas mensagens de forma abstrata, mas iremos integrá-las ao ambiente rede social corporativa. Ou seja, nosso pessoal não “apenas se corresponde”, mas se comunica entre si no contexto da solução de determinados problemas de negócios.

E quais são as tarefas de uma empresa? Vejamos o exemplo de Vasily, chefe do departamento de desenvolvimento.

  • “Nikolai, para esta tarefa precisamos de um patch hoje!”
    Isto significa que a correspondência pode ser conduzida no contexto de algum documento.
  • "Kolya, você vai ao Dota esta noite?"
    Ou seja, até mesmo um par de interlocutores pode se comunicar simultaneamente sobre vários temas.
  • “Peter, Nikolay, procurem no anexo a lista de preços do novo servidor.”
    Então, uma mensagem pode ter vários destinatários. Neste caso, a mensagem pode conter Arquivos anexados.
  • “Semyon, dê uma olhada também.”
    E deve haver uma oportunidade de entrar em correspondência existente convidar um novo membro.

Vamos nos concentrar nesta lista de necessidades “óbvias” por enquanto.

Sem compreender as especificidades aplicadas do problema e as limitações dadas a ele, projete eficaz esquema de banco de dados para resolver isso é quase impossível.

Etapa 2: Circuito Lógico Mínimo

Até agora, tudo funciona de forma muito semelhante à correspondência por e-mail - uma ferramenta de negócios tradicional. Sim, “algoritmicamente” muitos problemas de negócios são semelhantes entre si, portanto as ferramentas para resolvê-los serão estruturalmente semelhantes.

Vamos corrigir o diagrama lógico de relacionamento entre entidades já obtido. Para tornar nosso modelo mais fácil de entender, usaremos a opção de exibição mais primitiva Modelos de pronto-socorro sem as complicações das notações UML ou IDEF:

Banco de dados do Messenger (parte 1): projetando a estrutura base

No 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, iremos simplesmente percebê-los no futuro como alguns links “em algum lugar” por UUID.

Empate diagramas o mais simples possível - a maioria das pessoas para quem você os mostrará não são especialistas em leitura de UML/IDEF. Mas não se esqueça de desenhar.

Etapa 3: esboçar a estrutura da tabela

Sobre nomes de tabelas e camposOs nomes “russos” de campos e tabelas podem ser tratados de forma diferente, mas isso é uma questão de gosto. Porque o aqui no Tensor não há desenvolvedores estrangeiros, e o PostgreSQL nos permite dar nomes até mesmo em hieróglifos, se eles entre aspas, então preferimos nomear os objetos de forma inequívoca e clara para que não haja discrepâncias.
Como muitas pessoas nos escrevem mensagens ao mesmo tempo, algumas delas podem até fazer isso desligada, então a opção mais simples é use UUIDs como identificadores não apenas para entidades externas, mas também para todos os objetos dentro do nosso serviço. Além disso, eles podem ser gerados até mesmo no lado do cliente - isso nos ajudará a suportar o envio de mensagens quando o banco de dados estiver temporariamente indisponível e a probabilidade de colisão for extremamente baixa.

O rascunho da estrutura da tabela em nosso banco de dados ficará assim:
Tabelas: RU

CREATE 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
);

Tabelas: PT

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 coisa mais simples ao descrever um formato é começar a “desenrolar” o gráfico de conexão de tabelas que não são referenciadas eles mesmos para ninguém.

Etapa 4: Descubra necessidades não óbvias

É isso, projetamos um banco de dados no qual você pode escrever perfeitamente e de alguma forma ler.

Vamos nos colocar no lugar do usuário do nosso serviço – o que queremos fazer com ele?

  • Последние сообщения
    Ele ordenado cronologicamente um registro de “minhas” mensagens com base em vários critérios. Onde sou um dos destinatários, onde sou o autor, onde me escreveram e eu não respondi, onde não me responderam, ...
  • Participantes da correspondência
    Quem está participando desse longo, longo bate-papo?

Nossa estrutura nos permite resolver esses dois problemas “em geral”, mas não rapidamente. O problema é que para classificar na primeira tarefa não é possível criar índice, adequado para cada um dos participantes (e você terá que extrair todos os registros), e para resolver o segundo você precisa extrair todas as mensagens neste tópico.

Tarefas não intencionais do usuário podem colocar negrito cruzar a produtividade.

Etapa 5: Desnormalização Inteligente

Ambos os nossos problemas serão resolvidos por tabelas adicionais nas quais iremos duplicar parte dos dados, necessário formar sobre eles índices adequados às nossas tarefas.
Banco de dados do Messenger (parte 1): projetando a estrutura base

Tabelas: RU

CREATE TABLE "РеестрСообщений"(
  "Владелец"
    uuid
, "ТипРеестра"
    smallint
, "ДатаВремя"
    timestamp
, "Сообщение"
    uuid
, PRIMARY KEY("Владелец", "ТипРеестра", "Сообщение")
);
CREATE INDEX ON "РеестрСообщений"("Владелец", "ТипРеестра", "ДатаВремя" DESC);

CREATE TABLE "УчастникТемы"(
  "Тема"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Тема", "Персона")
);

Tabelas: PT

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 aplicamos duas abordagens típicas usadas na criação de tabelas auxiliares:

  • Multiplicando registros
    Usando um registro de mensagem inicial, criamos vários registros de acompanhamento em diferentes tipos de registros para diferentes proprietários - tanto para o remetente quanto para o destinatário. Mas cada um dos registros agora cai no índice - afinal, num caso típico, queremos ver apenas a primeira página.
  • Registros únicos
    Cada vez que você envia uma mensagem dentro de um tópico específico, basta verificar se tal entrada já existe. Caso contrário, adicione-o ao nosso “dicionário”.

Na próxima parte do artigo falaremos sobre implementação de particionamento na estrutura do nosso banco de dados.

Fonte: habr.com

Adicionar um comentário