Base de données Messenger (partie 1): nous concevons le cadre de base

Comment traduire les besoins de l'entreprise en structures de données spécifiques en utilisant l'exemple de la conception d'une base «à partir de zéro» pour un messager?



Notre base de données ne sera pas aussi volumineuse et distribuée que celle de VKontakte ou Badoo , mais «à être», mais elle est bonne - fonctionnelle, rapide et tient sur un seul 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 partage, de réplication et de systèmes géo-distribués, mais nous nous concentrerons plutôt sur les solutions de circuits à l'intérieur de la base de données.

Étape 1: Un peu de spécificité métier


Nous ne concevrons pas notre messagerie dans l'abstrait, mais l'intégrerons dans l'environnement de réseau social d'entreprise . Autrement dit, les gens chez nous ne sont pas «simplement des textos», mais communiquent entre eux dans le contexte de la résolution de certains problèmes commerciaux.

Et quels sont les défis commerciaux? .. Prenons l'exemple de Vasily, le chef du département de développement.
  • "Nikolai, ce patch a besoin de ce patch aujourd'hui!"
    Ainsi, la correspondance peut être conduite dans le cadre d'un document .
  • "Kolya, tu vas à DotA le soir?"
    Autrement dit, même avec une paire d'interlocuteurs, la communication peut en même temps être menée sur différents sujets .
  • "Peter, Nikolai, regardez l'attachement de prix sur le nouveau serveur."
    Ainsi, un message peut avoir plusieurs destinataires . Dans ce cas, le message peut contenir des fichiers joints .
  • "Semyon, et tu regardes aussi."
    Et il devrait être possible d' inviter un nouveau membre dans une correspondance existante.

Arrêtons-nous sur cette liste de besoins "évidents".
Sans une compréhension des spécificités appliquées à la tâche et des contraintes qu'elle impose, il est pratiquement impossible de concevoir un schéma de base de données efficace pour la résoudre.

Étape 2: Logique minimale


Jusqu'à présent, tout se révèle très similaire à la correspondance par e-mail - un outil commercial traditionnel. Alors oui, «algorithmiquement», de nombreuses tâches métier sont similaires les unes aux autres, et donc les outils pour les résoudre seront structurellement similaires.

Fixons le diagramme logique résultant des relations d'entités. Pour simplifier la compréhension de notre modèle, nous utiliserons l'option la plus primitive pour afficher un modèle ER sans les complications des notations UML ou IDEF:



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 à l'avenir comme des liens «quelque part» par UUID.
Dessinez les diagrammes aussi simplement que possible - la plupart de ceux à qui vous les montrerez ne sont pas des experts en lecture UML / IDEF. Mais - assurez-vous de dessiner.

Étape 3: esquisser la structure de la table


À propos des noms de table et de champ
Les noms «russes» des champs et des tables peuvent être traités différemment, mais c'est une question de goût. Comme nous n'avons pas de développeurs étrangers dans «Tensor» , et PostgreSQL nous permet de donner des noms même avec des hiéroglyphes, s'ils sont placés entre guillemets , nous préférons nommer les objets sans ambiguïté, clairement, afin qu'il n'y ait pas de malentendus.

Étant donné que de nombreuses personnes écrivent des messages en même temps, certaines d'entre elles peuvent le faire hors ligne , l'option la plus simple consiste à utiliser les UUID comme identificateurs non seulement pour les entités externes, mais pour tous les objets à l'intérieur 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 avec une inaccessibilité à court terme de la base de données, et la probabilité d'une collision est extrêmement faible.

La structure approximative des tables de 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: 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 ); 

La façon la plus simple de décrire le format est de commencer à «détordre» le graphique des liens des tableaux qui ne font référence à personne eux-mêmes.

Étape 4: Recherche d'exigences non évidentes


Voilà, nous avons conçu une base dans laquelle vous pouvez écrire et lire en quelque sorte .

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

  • Messages récents
    Il s'agit d'un registre de «mes» messages classés par ordre chronologique selon diverses caractéristiques. Où je suis l'un des destinataires, où je suis l'auteur, où ils m'ont écrit, mais je n'ai pas répondu, où ils ne m'ont pas répondu ...
  • Correspondants
    Qui est impliqué dans ce long, long chat?

Notre structure nous permet de résoudre ces deux problèmes «en général», mais rapidement - non. Le problème est que pour le tri dans le cadre de la première tâche, il est impossible de créer un index adapté à chacun des participants (et vous devrez récupérer tous les enregistrements), et pour résoudre le second, vous devez récupérer tous les messages sur le sujet.
Les tâches utilisateur imprévues peuvent mettre un terme à la productivité .

Étape 5: dénormalisation raisonnable


Nos deux problèmes aideront à résoudre des tableaux supplémentaires, dans lesquels nous dupliquerons une partie des données nécessaires pour former des index adaptés à nos problèmes.


Tableaux: RU
 CREATE TABLE ""( "" uuid , "" smallint , "" timestamp , "" uuid , PRIMARY KEY("", "", "") ); CREATE INDEX ON ""("", "", "" DESC); CREATE TABLE ""( "" uuid , "" uuid , PRIMARY KEY("", "") ); 

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

Ici, nous avons appliqué deux approches typiques utilisées pour créer des tables auxiliaires:

  • Enregistrements de multiplication
    Nous formons plusieurs enregistrements source à la fois à partir d'un enregistrement source du message dans différents types de registres pour différents propriétaires - à la fois pour l'expéditeur et le destinataire. Mais chacun des registres repose maintenant sur l'index - parce que dans le cas typique, nous voulons voir uniquement la première page.
  • Unique enregistrement
    Chaque fois que vous envoyez un message dans une rubrique 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 discuterons de l' implémentation du découpage dans la structure de notre base de données.

Source: https://habr.com/ru/post/fr483176/


All Articles