Mi proyecto actual es esencialmente una ejecución del sistema de gestión de documentos de fábrica.
Dicho esto, hay algunas arrugas (sorpresa, sorpresa). Si bien algunas de las arrugas son bastante específicas del proyecto, creo que han surgido algunas observaciones generales y preguntas que no tienen una respuesta canónica (que pude encontrar, de todos modos) y que son aplicables a un dominio de problemas más amplio . Hay mucho aquí y no estoy seguro de que sea una buena opción para el formato de preguntas y respuestas de StackExchange, pero creo que es a) una pregunta que se debe responder yb) lo suficientemente inespecífica como para que pueda beneficiar a la comunidad. Algunas de mis consideraciones son específicas para mí, pero creo que la pregunta podría ser útil para cualquiera que tenga que decidir SQL vs NoSQL frente a ambos.
El fondo:
La aplicación web que estamos creando contiene datos que son claramente de naturaleza relacional, así como datos orientados a documentos. Nos gustaría tener nuestro pastel y comerlo también.
TL; DR: Creo que # 5 a continuación pasa la prueba de olor. ¿Vos si? ¿Alguien tiene experiencia con tal integración de SQL y NOSQL en una sola aplicación? Intenté enumerar todos los enfoques posibles para esta clase de problema a continuación. ¿Me he perdido una alternativa prometedora?
Complejidades
- Hay muchas clases diferentes de documentos. Los requisitos ya requieren docenas de documentos diferentes. Este número solo aumentará alguna vez. El mejor caso posible sería uno en el que podríamos aprovechar un lenguaje específico de dominio simple, generación de código y un esquema flexible para que los expertos en dominio pudieran manejar la adición de nuevas clases de documentos sin la intervención de DBA o programadores. (Nota: ya somos conscientes de que estamos viviendo la Décima Regla de Greenspun )
- La integridad de las escrituras exitosas anteriores es un requisito central del proyecto. Los datos serán críticos para el negocio. La semántica completa de ACID en las escrituras se puede sacrificar siempre que las cosas que se escriben con éxito permanezcan escritas.
- Los documentos son en sí mismos complejos. El documento prototipo en nuestro caso específico requerirá el almacenamiento de más de 150 datos distintos por instancia de documento. El caso patológico podría ser un orden de magnitud peor, pero ciertamente no dos.
- Una sola clase de documentos es un objetivo móvil sujeto a actualizaciones en un momento posterior.
- Nos gustan las cosas gratuitas que obtenemos de Django cuando las conectamos a una base de datos relacional. Nos gustaría mantener los obsequios sin tener que retroceder dos versiones de Django para usar la bifurcación django-nonrel. Volcar el ORM por completo es preferible a degradar a 1.3.
Esencialmente, es una mezcla de datos relacionales (las cosas típicas de su aplicación web, como usuarios, grupos, etc.), así como metadatos de documentos que necesitaremos para poder dividir y cortar con consultas complejas en tiempo real) y datos de documentos (p. Ej. los cientos de campos en los que no tenemos interés en unirnos o consultarlos: nuestro único caso de uso para los datos será mostrar el documento único en el que se ingresó).
Quería hacer una verificación de cordura (si revisas mi historial de publicaciones, soy bastante explícito sobre el hecho de que no soy un DBA) en mi método preferido, así como enumerar todas las opciones que he encontrado para que otros resuelvan problemas ampliamente similares que involucran tanto datos relacionales como no relacionales.
Soluciones propuestas:
1. Una tabla por clase de documento
Cada clase de documento obtiene su propia tabla, con columnas para todos los metadatos y datos.
Ventajas:
- El modelo de datos SQL estándar está en juego.
- Los datos relacionales se manejan de la mejor manera posible. Nos desnormalizaremos más tarde si es necesario.
- La interfaz de administración incorporada de Django se siente cómoda con la introspección de estas tablas y el ORM puede vivir feliz con el 100% de los datos listos para usar.
Desventajas
- Pesadilla de mantenimiento. Docenas (¿cientos?) De tablas con (¿decenas?) Miles de columnas.
- Lógica a nivel de aplicación responsable de decidir exactamente en qué tabla escribir. Hacer que el nombre de la tabla sea un parámetro para una consulta apesta.
- Básicamente, todos los cambios de lógica de negocios requerirán cambios de esquema.
- Los casos patológicos pueden requerir la división de datos para formularios individuales en varias tablas (consulte: ¿Cuál es el número máximo de columnas en una tabla PostgreSQL? ).
- Probablemente tendríamos que buscar un DBA real y honesto que sin duda terminaría odiando la vida y a nosotros.
2. Modelado EAV
Solo hay una tabla de campos. El modelado de Entidad-Atributo-Valor ya se entiende bien. Lo he incluido para completar. No creo que ningún proyecto nuevo que se inicie en 2013 vaya con un enfoque EAV a propósito.
Ventajas:
- Fácil de modelar.
Desventajas
- Más difícil de consultar.
- La capa de base de datos ya no tiene una representación directa de lo que constituye un objeto de nivel de aplicación.
- Perderíamos la comprobación de restricciones de nivel DB.
- El número de filas en una tabla crecerá entre 100 y 1000 veces más rápido. Probable punto de dolor futuro, en cuanto al rendimiento.
- Indización limitada posible.
- El esquema de base de datos no tiene sentido en lo que respecta a ORM. Las baterías incluidas en la aplicación web se conservan, pero los modelos de datos personalizados requerirán consultas personalizadas.
3. Utilice los campos hstore o json de PostgreSQL
Cualquiera de estos tipos de campo haría el truco para almacenar datos sin esquema dentro del contexto de una base de datos relacional. La única razón por la que no salto a esta solución de inmediato es que es relativamente nueva (introducida en la versión 8.4, por lo que no es tan nueva), no tengo exposición previa y sospecho. Me parece erróneo precisamente por las mismas razones por las que me sentiría incómodo al arrojar todos mis datos agradables y fácilmente normalizados a Mongo, a pesar de que Mongo puede manejar referencias entre documentos.
Ventajas:
- Obtenemos los beneficios de Django ORM y la gestión integrada de autenticación y sesión.
- Todo se queda en un backend que hemos utilizado anteriormente en otros proyectos con éxito.
Desventajas
- No hay experiencia con esto, personalmente.
- No parece una característica muy utilizada. Parece que se recomiendan bastante a las personas que buscan soluciones NOSQL, pero no veo mucha evidencia de que estén siendo elegidos. Esto me hace pensar que me falta algo.
- Todos los valores almacenados son cadenas. Pierda la comprobación de restricciones de nivel DB.
- Los datos en hstore nunca se mostrarán al usuario a menos que vean específicamente un documento, pero los metadatos almacenados en columnas más estándar sí lo serán. Estaremos superando esos metadatos y me preocupa que los almacenes bastante grandes que crearemos puedan tener inconvenientes de rendimiento.
4. Ir a todo el documento orientado a documentos
Haga todos los documentos de las cosas (en el sentido de MongoDB). Cree una sola colección de tipo Document
y llámela un día. Traiga también todos los datos periféricos (incluidos los datos de cuentas de usuarios, grupos, etc.) a mongo. Obviamente, esta solución es mejor que el modelado EAV, pero me parece mal por la misma razón que el # 3 se sintió mal: ambos tienen ganas de usar su martillo como destornillador también.
Ventajas:
- No es necesario modelar datos por adelantado. Tenga una colección con documentos de tipo
Document
y llámela al día. - Buenas características de escala conocidas, en caso de que la colección necesite crecer para abarcar millones o incluso miles de millones de documentos.
- El formato JSON (BSON) es intuitivo para los desarrolladores.
- Según tengo entendido (que es solo vagamente en este punto), al ser paranoico con respecto al nivel de preocupación de escritura, incluso una sola instancia puede proporcionar seguridad de datos bastante fuerte en caso de cualquier cosa y todo hasta un bloqueo del disco duro.
Desventajas
- El ORM está fuera de la ventana para el tronco Django. Regalos que salen por la ventana: el marco de autenticación, el marco de sesiones, la interfaz de administración, seguramente muchas otras cosas.
- Debe usar las capacidades de referencia de mongo (que requieren múltiples consultas) o desnormalizar los datos. No solo perdemos regalos que recibimos de Django, también perdemos regalos como JOIN que damos por sentado en PostgreSQL.
- Seguridad de los datos. Cuando uno lee sobre MongoDB, parece que siempre hay al menos una persona que se refiere a cómo aumentará y perderá sus datos. Nunca citan una ocurrencia en particular y todo podría ser solo lavado de tontos o simplemente relacionado con el antiguo fuego predeterminado y olvidar la preocupación de escritura, pero todavía me preocupa. Por supuesto, utilizaremos una estrategia de copia de seguridad bastante paranoica en cualquier caso (si los datos se corrompen silenciosamente, eso podría ser irrelevante, por supuesto ...).
5. PostgreSQL y MongoDB
Los datos relacionales van en la base de datos relacional y los datos del documento van en la base de datos orientada a documentos. La documents
tabla en la base de datos relacional contiene todos los datos que podríamos necesitar para indexar o dividir, así como un ObjectId MongoDB que usaríamos cuando necesitáramos consultar los valores reales de los campos en los documentos. No podríamos usar el ORM o el administrador incorporado para los valores de los documentos en sí, pero eso no es una gran pérdida ya que toda la aplicación es básicamente una interfaz de administración para los documentos y probablemente habríamos tenido que personalizar esa parte específica del ORM en un grado inaceptable para que funcione de la manera que necesitamos.
Ventajas:
- Cada backend solo hace lo que es bueno.
- Las referencias entre modelos se conservan sin requerir múltiples consultas.
- Podemos mantener las baterías que Django nos dio en lo que respecta a los usuarios, sesiones, etc.
- Solo necesita una
documents
tabla, sin importar cuántas clases diferentes de documentos se creen. - Los datos de documentos consultados con menos frecuencia están fuertemente separados de los metadatos que se consultan con mucha más frecuencia.
Desventajas
- La recuperación de datos del documento requerirá 2 consultas secuenciales, primero contra el DB de SQL y luego contra el MongoDB (aunque esto no es peor que si los mismos datos hubieran sido almacenados en Mongo y no desnormalizados)
- Escribir ya no será atómico. Se garantiza que una escritura en un solo documento de Mongo será atómica y PG obviamente puede garantizar la atomicidad, pero garantizar la atomicidad de la escritura en ambos requerirá lógica de aplicación, sin duda con una penalización de rendimiento y complejidad.
- Dos backends = dos idiomas de consulta = dos programas diferentes con requisitos de administración diferentes = dos bases de datos que compiten por la memoria.
JSON
tipo de datos. No tenga miedo de usar nuevas funciones en Postgres: el equipo de Postgres no lanza funciones que no sean estables. Y 9.2 no es tan nuevo en realidad). Además, puede utilizar las nuevas funciones JSON en 9.3 una vez que esté allí. Si siempre está procesando completamente los documentos en el código de su aplicación (en lugar de usar SQL), también puede almacenar JSON en unatext
columna normal .