Base de données Messenger (partie 1) : conception du framework de base

Comment traduire les exigences de l'entreprise en structures de données spécifiques en utilisant l'exemple de la conception d'une base de données de messagerie à partir de zéro.

Base de données Messenger (partie 1) : conception du framework de base
Notre base ne sera pas aussi grande et distribuée, comme VKontakte ou Badoo, mais "pour que ce soit le cas", mais c'était bien - fonctionnel, rapide et tenir sur un serveur PostgreSQL - afin que vous puissiez déployer une instance distincte du service quelque part sur le côté, par exemple.

Par conséquent, nous n'aborderons pas les problèmes de sharding, de réplication et de systèmes géo-distribués, mais nous nous concentrerons sur les solutions de circuits à l'intérieur de la base de données.

Étape 1 : Quelques spécificités de l'entreprise

Nous ne concevrons pas notre message de manière abstraite, mais l'intégrerons dans l'environnement réseau social d'entreprise. Autrement dit, nos collaborateurs ne « se contentent pas de correspondre », mais communiquent entre eux dans le cadre de la résolution de certains problèmes commerciaux.

Et quelles sont les tâches d'une entreprise ?.. Regardons l'exemple de Vasily, le chef du département de développement.

  • "Nikolai, pour cette tâche, nous avons besoin d'un patch aujourd'hui !"
    Cela signifie que la correspondance peut être effectuée dans le cadre de certains Document.
  • "Kolya, tu vas à Dota ce soir ?"
    C'est-à-dire que même une paire d'interlocuteurs peut communiquer simultanément sur divers sujets.
  • "Peter, Nikolay, regardez dans la pièce jointe la liste de prix du nouveau serveur."
    Ainsi, un message peut avoir plusieurs destinataires. Dans ce cas, le message peut contenir Fichiers joints.
  • "Semyon, regarde aussi."
    Et il devrait y avoir la possibilité d'entrer dans la correspondance existante inviter un nouveau membre.

Attardons-nous pour l'instant sur cette liste de besoins « évidents ».

Sans comprendre les spécificités appliquées du problème et les limites qui lui sont données, la conception efficace schéma de base de données pour le résoudre est presque impossible.

Étape 2 : Circuit logique minimal

Jusqu'à présent, tout fonctionne de manière très similaire à la correspondance par courrier électronique - un outil commercial traditionnel. Oui, « algorithmiquement » de nombreux problèmes commerciaux sont similaires les uns aux autres, donc les outils pour les résoudre seront structurellement similaires.

Corrigeons le diagramme logique déjà obtenu des relations entre entités. Pour rendre notre modèle plus facile à comprendre, nous utiliserons l'option d'affichage la plus primitive Modèles ER sans les complications des notations UML ou IDEF :

Base de données Messenger (partie 1) : conception du framework de base

Dans notre exemple, la personne, le document et le « corps » binaire du fichier sont des entités « externes » qui existent indépendamment sans notre service. Par conséquent, nous les percevrons simplement dans le futur comme des liens « quelque part » par UUID.

Dessiner des schémas aussi simples que possible - la plupart des personnes à qui vous leur montrerez ne sont pas des experts en lecture d'UML/IDEF. Mais assurez-vous de dessiner.

Étape 3 : Esquisser la structure de la table

À propos des noms de tables et de champsLes noms « russes » des champs et des tables peuvent être traités différemment, mais c'est une question de goût. Parce que le ici chez Tensor il n'y a pas de développeurs étrangers, et PostgreSQL nous permet de donner des noms même en hiéroglyphes, s'ils entouré de guillemets, alors nous préférons nommer les objets sans ambiguïté et clairement afin qu'il n'y ait pas de divergences.
Étant donné que de nombreuses personnes nous écrivent des messages en même temps, certaines d'entre elles peuvent même le faire. hors ligne, alors l'option la plus simple est utiliser les UUID comme identifiants non seulement pour les entités externes, mais aussi pour tous les objets au sein de notre service. De plus, ils peuvent être générés même côté client - cela nous aidera à prendre en charge l'envoi de messages lorsque la base de données est temporairement indisponible et que la probabilité de collision est extrêmement faible.

Le projet de structure de table dans notre base de données ressemblera à ceci :
Tableaux : 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
);

Tableaux : FR

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

Le plus simple pour décrire un format est de commencer à « dérouler » le graphe de connexion à partir de tables non référencées eux-mêmes à personne.

Étape 4 : Découvrez les besoins non évidents

Ça y est, nous avons conçu une base de données dans laquelle vous pouvez parfaitement écrire et en quelque sorte lire.

Mettons-nous à la place de l'utilisateur de notre service : que voulons-nous en faire ?

  • messages récents
    Il triés chronologiquement un registre de « mes » messages selon différents critères. Où je suis l'un des destinataires, où je suis l'auteur, où ils m'ont écrit et je n'ai pas répondu, où ils ne m'ont pas répondu, ...
  • Participants à la correspondance
    Qui participe même à cette longue, longue conversation ?

Notre structure nous permet de résoudre ces deux problèmes « de manière générale », mais pas rapidement. Le problème est que pour trier dans la première tâche impossible de créer un index, adapté à chacun des participants (et vous devrez extraire tous les enregistrements), et pour résoudre le second dont vous avez besoin extraire tous les messages sur le sujet.

Les tâches utilisateur involontaires peuvent être mises en gras croix sur la productivité.

Étape 5 : Dénormalisation intelligente

Nos deux problèmes seront résolus par des tableaux supplémentaires dans lesquels nous dupliquer une partie des données, nécessaire pour former sur eux des indices adaptés à nos tâches.
Base de données Messenger (partie 1) : conception du framework de base

Tableaux : RU

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

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

Tableaux : FR

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

Ici, nous avons appliqué deux approches typiques utilisées lors de la création de tables auxiliaires :

  • Multiplication des enregistrements
    À l'aide d'un enregistrement de message initial, nous créons plusieurs enregistrements de suivi dans différents types de registres pour différents propriétaires - à la fois pour l'expéditeur et pour le destinataire. Mais chacun des registres tombe désormais sur l'index - après tout, dans un cas typique, nous voudrons voir uniquement la première page.
  • Enregistrements uniques
    Chaque fois que vous envoyez un message dans un sujet spécifique, il suffit de vérifier si une telle entrée existe déjà. Sinon, ajoutez-le à notre « dictionnaire ».

Dans la prochaine partie de l'article, nous parlerons de mise en œuvre du cloisonnement dans la structure de notre base de données.

Source: habr.com

Ajouter un commentaire