Hemos diseñado con éxito la estructura de nuestra base de datos PostgreSQL para almacenar correspondencia, ha pasado un año, los usuarios la están llenando activamente, ahora tiene
millones de registros y ... algo comenzó a disminuir.

El hecho es que
con el crecimiento del volumen de la tabla, la "profundidad" de los índices también crece , aunque logarítmicamente. Pero con el tiempo, esto obliga al servidor a
procesar muchas páginas de datos para realizar las mismas tareas de lectura / escritura que al principio.
Aquí es donde la
partición viene al rescate.
Observo que no se tratará de fragmentación, es decir, la distribución de datos entre diferentes bases de datos o servidores. Porque, incluso dividiendo los datos en
varios servidores, no puede deshacerse del problema de la "hinchazón" de los índices con el tiempo. Está claro que si puede permitirse poner en marcha un nuevo servidor todos los días, sus problemas ya no se encontrarán en el plano de una base de datos específica.
Consideraremos no scripts específicos para implementar la partición "en hardware", sino el enfoque en sí mismo: qué y cómo "cortar en segmentos", y a qué conduce ese deseo.
Concepto
Una vez más, definimos nuestro objetivo: queremos asegurarnos de que hoy, mañana y después de un año, el número de datos de PostgreSQL leídos durante cualquier operación de lectura / escritura permanezca aproximadamente igual.
Para cualquier
dato acumulado cronológicamente (mensajes, documentos, registros, archivos, ...), la elección natural como clave de partición es la
fecha / hora del evento . En nuestro caso, tal evento es el
momento en que se envió el mensaje .
Tenga en cuenta que los usuarios casi siempre
trabajan solo con los datos "más recientes" : leen los mensajes más recientes, analizan los registros más recientes ... No, por supuesto, pueden desplazarse más atrás en el tiempo, solo lo hacen muy raramente.
A partir de estas restricciones, resulta obvio que las
secciones "diarias" serán la mejor solución para los mensajes; después de todo, nuestro usuario casi siempre leerá lo que le llegó "hoy" o "ayer".
Si escribimos y leemos casi solo una sección durante el día, esto nos da
un uso aún
más eficiente de la memoria y el disco , ya que todos los índices de sección caben fácilmente en la RAM, a diferencia de las secciones "grandes y en negrita" de toda la tabla.
paso a paso
En general, todo lo anterior suena como un beneficio sólido. Y es posible, pero por el bien de esto tendremos que esforzarnos mucho, porque la
decisión de dividir una de las entidades lleva a la necesidad de "cortar" y asociarlo .
Mensaje, sus propiedades y proyecciones.
Dado que decidimos cortar los mensajes por fechas, es razonable dividir las propiedades de las entidades (archivos adjuntos, listas de correo) y
también por la fecha del mensaje , dependiendo de ellas.
Dado que una de nuestras tareas típicas es solo ver registros de mensajes (no leídos, entrantes, todos), también es lógico "dibujarlos" en la partición por fechas de mensaje.

Agregue la clave de partición (fecha del mensaje) a todas las tablas: destinatarios, archivo, registros. No puede agregar al mensaje en sí, pero use el DateTime existente.
Temas
Como el tema es uno en varios mensajes, no será posible "cortarlo" en el mismo modelo; uno debe confiar en otra cosa. En nuestro caso, la
fecha del primer mensaje en correspondencia es ideal, es decir, el momento de creación del tema en sí.

Agregue la clave de partición (fecha del tema) a todas las tablas: tema, participante.
Pero ahora tenemos dos problemas a la vez:
- en qué sección buscar publicaciones sobre el tema?
- en qué sección buscar un tema de un mensaje?
Puede, por supuesto, continuar buscando en todas las secciones, pero será muy triste y negará todas nuestras ganancias. Por lo tanto, para saber exactamente dónde buscar, haremos enlaces / punteros lógicos a las secciones:
- en el mensaje, agregue un campo con la fecha del tema
- agregue al tema un conjunto de fechas de mensajes para esta correspondencia (puede usar una tabla separada, o puede usar una matriz de fechas)

Dado que habrá pocas modificaciones en la lista de fechas de mensajes para cada correspondencia individual (después de todo, casi todos los mensajes caen en los próximos 1-2 días), me detendré en esta opción.
Total, la estructura de nuestra base tomó la siguiente forma, teniendo en cuenta la partición:
Tablas: RU, si no te gusta cirílico, es mejor no mirar los nombres de tablas / campos Ahorre un centavo bonito
Bueno, si no utilizamos la
opción clásica de particionamiento basada en la distribución de valores de campo (a través de activadores y herencia o PARTICIÓN POR), sino "manualmente" a nivel de aplicación, podemos ver que el valor de la clave de particionamiento ya está almacenado en el nombre de la tabla misma.
Por lo tanto, si está tan
preocupado por la cantidad de datos almacenados , puede deshacerse de estos campos "adicionales" y consultar tablas específicas. Es cierto que todas las muestras de varias secciones en este caso deberán enviarse al lado de la solicitud.