¿Cómo se pueden traducir los requisitos comerciales en estructuras de datos específicas utilizando el ejemplo de diseño de una base "desde cero" para un mensajero?

Nuestra base de datos no será tan grande y distribuida
como la de VKontakte o
Badoo , sino "para ser", pero es buena, funcional, rápida y
cabe en un único servidor PostgreSQL, por lo que puede implementar una instancia separada del servicio en algún lado, por ejemplo.
Por lo tanto, no abordaremos los problemas de fragmentación, replicación y sistemas geodistribuidos, sino que nos centraremos en soluciones de circuitos dentro de la base de datos.
Paso 1: un poco de especificidad comercial
No diseñaremos nuestros mensajes en abstracto, sino que los integraremos en el entorno de
redes sociales corporativas . Es decir, las personas en nuestro lugar no solo "envían mensajes de texto", sino que se comunican entre sí en el contexto de la resolución de ciertos problemas comerciales.
¿Y cuáles son los desafíos comerciales? Veamos el ejemplo de Vasily, el jefe del departamento de desarrollo.
- "Nikolai, ¡este parche necesita este parche hoy!"
Por lo tanto, la correspondencia puede realizarse en el contexto de un documento . - "Kolya, ¿vas a Dota por la noche?"
Es decir, incluso con un par de interlocutores, la comunicación al mismo tiempo puede realizarse sobre diferentes temas . - "Peter, Nikolai, mira el archivo adjunto de precios en el nuevo servidor".
Entonces, un mensaje puede tener varios destinatarios . En este caso, el mensaje puede contener archivos adjuntos . - "Semyon, y tú también te ves".
Y debería ser posible invitar a un nuevo miembro a una correspondencia existente.
Detengámonos en esta lista de necesidades "obvias".
Sin una comprensión de los detalles aplicados de la tarea y las restricciones establecidas por ella, es prácticamente imposible diseñar un esquema de base de datos eficaz para resolverlo.
Paso 2: lógica mínima
Hasta ahora, todo resulta muy similar a la correspondencia por correo electrónico, una herramienta comercial tradicional. Entonces sí, "algorítmicamente", muchas tareas de negocios son similares entre sí y, por lo tanto, las herramientas para resolverlas serán estructuralmente similares.
Arreglemos el diagrama lógico resultante de las relaciones de las entidades. Para simplificar la comprensión de nuestro modelo, utilizaremos la opción más primitiva para mostrar un
modelo ER sin las complicaciones de las anotaciones UML o IDEF:

En nuestro ejemplo, la persona, el documento y el "cuerpo" binario del archivo son entidades "externas" que existen independientemente sin nuestro servicio. Por lo tanto, simplemente los percibiremos en el futuro como algunos enlaces "en algún lugar" de UUID.
Dibuje los diagramas de la manera más simple posible : la mayoría de aquellos a quienes les mostrará no son expertos en leer UML / IDEF. Pero, asegúrese de dibujar.
Paso 3: dibuja la estructura de la tabla
Acerca de los nombres de tablas y camposLos nombres "rusos" de campos y tablas se pueden tratar de manera diferente, pero esto es cuestión de gustos. Dado
que no tenemos desarrolladores extranjeros
en "Tensor" , y PostgreSQL nos permite dar nombres incluso con jeroglíficos, si están
entre comillas , preferimos nombrar objetos de forma inequívoca, clara, para que no haya malentendidos.
Dado que muchas personas escriben mensajes a la vez, algunos de ellos pueden hacerlo
sin conexión , la opción más fácil es
usar UUID como identificadores no solo para entidades externas, sino también para todos los objetos dentro de nuestro servicio. Además, se pueden generar incluso en el lado del cliente; esto nos ayudará a admitir el envío de mensajes con inaccesibilidad a corto plazo de la base de datos, y la probabilidad de una colisión es extremadamente pequeña.
La estructura aproximada de las tablas en nuestra base de datos se verá así:
Tablas: 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 );
Tablas: 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 forma más fácil de describir el formato es comenzar a "desenredar" el gráfico de enlaces de las tablas que no se refieren a nadie.
Paso 4: descubrir requisitos no obvios
Eso es todo, hemos diseñado una base en la que puedes escribir y leer de
alguna manera .
Pongámonos en el lugar del usuario de nuestro servicio: ¿qué queremos hacer con él?
- Publicaciones recientes
Este es un registro de "mis" mensajes ordenados cronológicamente por varias características. Donde soy uno de los destinatarios, donde soy el autor, donde me escribieron, pero no respondí, donde no me respondieron ... - Corresponsales
¿Quién está involucrado en este largo, largo chat?
Nuestra estructura nos permite resolver ambos problemas "en general", pero rápidamente, no. El problema es que para ordenar como parte de la primera tarea,
es imposible crear un índice adecuado para cada uno de los participantes (y tendrá que recuperar todos los registros), y para resolver la segunda, debe
recuperar todos los mensajes sobre el tema.
Las tareas de usuario no anticipadas pueden poner fin a la productividad .
Paso 5: desnormalización razonable
Ambos problemas ayudarán a resolver tablas adicionales, en las cuales
duplicaremos parte de los datos necesarios para formar índices adecuados para nuestros problemas.

Tablas: RU CREATE TABLE ""( "" uuid , "" smallint , "" timestamp , "" uuid , PRIMARY KEY("", "", "") ); CREATE INDEX ON ""("", "", "" DESC); CREATE TABLE ""( "" uuid , "" uuid , PRIMARY KEY("", "") );
Tablas: 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) );
Aquí hemos aplicado dos enfoques típicos utilizados para crear tablas auxiliares:
- Registros de multiplicación
Formamos varios registros fuente a la vez a partir de un registro fuente del mensaje en diferentes tipos de registros para diferentes propietarios, tanto para el remitente como para el destinatario. Pero cada uno de los registros ahora se encuentra en el índice, porque en el caso típico solo queremos ver la primera página. - Record Uniqueization
Cada vez que envía un mensaje dentro de un tema específico, es suficiente para verificar si dicha entrada ya existe. Si no, agréguelo a nuestro "diccionario".
En la siguiente parte del artículo, discutiremos la
implementación del seccionamiento en la estructura de nuestra base de datos.