c# - started - modelo de datos dinámico
entity framework sql server (5)
El motor de base de datos ESENT en Windows se usa mucho para este tipo de datos semiestructurados. Un ejemplo es Microsoft Exchange que, al igual que su aplicación, tiene miles de usuarios donde cada usuario puede definir su propio conjunto de propiedades (propiedades con nombre MAPI). Exchange utiliza una versión ligeramente modificada de ESENT.
ESENT tiene muchas características que permiten aplicaciones con grandes requisitos de metadatos: cada tabla de ESENT puede tener aproximadamente ~ 32K columnas definidas; Se pueden agregar tablas, índices y columnas en tiempo de ejecución; las columnas dispersas no ocupan espacio de registro cuando no están configuradas; y las tablas de plantillas pueden reducir el espacio utilizado por los metadatos en sí. Es común que las aplicaciones grandes tengan miles de tablas / índices.
En este caso, puede tener una tabla por usuario y crear las columnas por usuario en la tabla, creando índices en cualquier columna que desee consultar. Eso sería similar a la forma en que algunas versiones de Exchange almacenan sus datos. La desventaja de este enfoque es que ESENT no tiene un motor de consultas, por lo que tendrá que realizar sus consultas manualmente como llamadas MakeKey / Seek / MoveNext.
Un contenedor gestionado para ESENT está aquí:
Tengo un proyecto que requiere atributos definidos por el usuario para un objeto particular en tiempo de ejecución (digamos un objeto persona en este ejemplo). El proyecto tendrá muchos usuarios diferentes (1000 +), cada uno definiendo sus propios atributos únicos para sus propios conjuntos de objetos "Person".
(Por ejemplo, el usuario # 1 tendrá un conjunto de atributos definidos, que se aplicarán a todos los objetos de la persona que son propiedad de este usuario. Míralo por 1000 usuarios, y esa es la cantidad mínima de usuarios con los que la aplicación funcionará). Estos atributos se utilizarán para consultar el objeto de personas y devolver los resultados.
Creo que estos son los posibles enfoques que puedo usar. Usaré C # (y cualquier versión de .NET 3.5 o 4), y tendré un reinado gratuito: qué usar para un almacén de datos. (Tengo mysql y mssql disponibles, aunque tengo la libertad de usar cualquier software, siempre que se ajuste a la factura)
¿Me he perdido algo, o hecho alguna suposición incorrecta en mi evaluación?
Fuera de estas elecciones, ¿qué solución elegirías?
Modelo de objeto híbrido EAV. (Defina la base de datos utilizando el modelo relacional normal y tenga una tabla de ''bolsa de propiedades'' para la tabla de persona).
Desventajas: muchas uniones por / consulta. Bajo rendimiento. Puede alcanzar un límite del número de combinaciones / tablas utilizadas en una consulta.
He extraído una muestra rápida, que tiene una interfaz esqe de Subsonic 2.x:
Select().From().Where ... etc
Lo que genera las uniones correctas, luego filtra + gira los datos devueltos en c #, para devolver una configuración de datos configurable con el conjunto de datos correctamente escrito.
Todavía tengo que cargar prueba esta solución. Se basa en el asesoramiento de EA en este documento técnico de Microsoft: SQL Server 2008 RTM Documentos Mejores prácticas para el modelado semántico de datos para rendimiento y escalabilidad
Permite al usuario crear / alterar dinámicamente la tabla del objeto en tiempo de ejecución. Esta solución es lo que creo que NHibernate hace en segundo plano cuando se usan propiedades dinámicas, como se explica donde
http://bartreyserhove.blogspot.com/2008/02/dynamic-domain-mode-using-nhibernate.html
Desventajas:
A medida que el sistema crezca, el número de columnas definidas se volverá muy grande y puede alcanzar el número máximo de columnas. Si hay 1000 usuarios, cada uno con 10 atributos distintos para sus objetos ''Person'', entonces necesitaríamos una tabla que contenga 10k columnas. No escalable en este escenario.
Supongo que podría permitir una tabla de atributos de persona por usuario, pero si hay 1000 usuarios para comenzar, son 1000 tablas más las otras 10 impares en la aplicación.
No estoy seguro de si esto sería escalable, pero no lo parece. Alguien por favor me corrija si me equivoco!
Utilice un almacén de datos NoSQL, como CouchDb / MongoDb
Por lo que he leído, aún no están probadas en aplicaciones a gran escala, basadas en cadenas, y son muy tempranas en la fase de desarrollo. Si soy incorrecto en esta evaluación, ¿puede alguien avisarme?
Usando la columna XML en la tabla de personas para almacenar atributos
Inconvenientes: no hay indexación en las consultas, por lo que cada columna tendría que recuperarse y consultarse para devolver un conjunto de resultados, lo que daría como resultado un bajo rendimiento de las consultas.
Serialización de un gráfico de objetos a la base de datos.
Inconvenientes: no hay indexación en las consultas, por lo que cada columna tendría que recuperarse y consultarse para devolver un conjunto de resultados, lo que daría como resultado un rendimiento deficiente de las consultas.
C # enlaces para berkelyDB
De lo que leí aquí: http://www.dinosaurtech.com/2009/berkeley-db-c-bindings/
Berkeley Db definitivamente ha demostrado ser útil, pero como Robert señaló, no hay una interfaz fácil. Todo su envoltorio de wOO debe estar codificado a mano, y todos sus índices se deben mantener a mano. Es mucho más difícil que SQL / linq-to-sql, pero ese es el precio que pagas por una velocidad ridícula.
Parece una gran sobrecarga, sin embargo, si alguien puede proporcionar un enlace a un tutorial sobre cómo mantener los índices en C #, podría ser un obstáculo.
SQL / RDF híbrido. Raro no había pensado en esto antes. Similar a la opción 1, pero en lugar de una tabla de "bolsa de propiedades", ¿solo XREF a una tienda RDF? Las consultas implicarían 2 pasos: consulte en la tienda RDF las personas que tienen los atributos correctos, para devolver los objetos personales y use los ID para estos objetos personales en la consulta SQL para devolver los datos relacionales. Gastos adicionales, pero podría ser un goer.
En un modelo EAV no tiene que tener muchas uniones, ya que solo puede tener las uniones que necesita para el filtrado de consultas. Para el conjunto de resultados, devuelva las entradas de propiedades como un conjunto de filas separado. Eso es lo que estamos haciendo en nuestra implementación de EAV.
Por ejemplo, una consulta puede devolver personas con la propiedad extendida ''Edad''> 18:
Tabla de propiedades:
1 Age
2 NickName
Primer conjunto de resultados:
PersonID Name
1 John
2 Mary
segundo conjunto de resultados:
PersonID PropertyID Value
1 1 24
1 2 ''Neo''
2 1 32
2 2 ''Pocahontas''
Para el primer conjunto de resultados, necesita una unión interna para la propiedad extendida ''age'' para consultar la parte de entidad de objeto Person básica:
select p.ID, p.Name from Persons p
join PersonExtendedProperties pp
on p.ID = pp.PersonID
where pp.PropertyName = ''Age''
and pp.PropertyValue > 18 -- probably need to convert to integer here
Para el segundo conjunto de resultados, estamos haciendo una combinación externa del primer conjunto de resultados con la tabla PersonExtendedProperties para obtener el resto de las propiedades extendidas. Es un conjunto de resultados ''estrecho'', no giramos las propiedades en sql, por lo que no necesitamos varias uniones aquí.
En realidad, usamos tablas separadas para diferentes tipos para evitar la conversión de tipos de datos, para tener propiedades extendidas indexadas y fácilmente intercambiables.
Mi recomendación:
Permitir que las propiedades sean marcadas como indexables. Tenga un límite rígido pequeño en el número de propiedades indexables y en columnas por objeto. Tener un límite duro grande en los tipos de columnas totales en todos los objetos.
Implemente los índices como tablas separadas (una por índice) unidas con la tabla principal de datos (la tabla principal tiene una clave única grande para el objeto). (Las tablas de índice se pueden crear / eliminar según sea necesario).
Serialice los datos, incluidas las columnas de índice, y coloque las propiedades de índice en columnas relacionales de primera clase en sus tablas de índice dedicadas. Use JSON en lugar de XML para ahorrar espacio en la tabla. Aplique una política de nombres de columna cortos (o una política de nombres cortos y nombres cortos) para ahorrar espacio y aumentar el rendimiento.
Utilice los quarks para los identificadores de campo (pero solo en el motor principal para ahorrar RAM y acelerar algunas operaciones de lectura, no confíe en la comparación de punteros de quarks en todos los casos).
Mi pensamiento en sus opciones:
1 es un posible. El rendimiento claramente será menor que si no se almacenaran las columnas de ID de campo.
2 es un no en general. Los motores de base de datos no están contentos con los cambios de esquema dinámico. Pero un posible sí si su motor DB es bueno en esto.
3 posibles.
4 Sí, aunque usaría JSON.
5 Parece que 4 solo menos optimizado ??
6 suena bien; iría si estuviera contento de probar algo nuevo y también si estuviera contento con la confiabilidad y el rendimiento, pero generalmente querría ir con la tecnología más convencional. También me gustaría reducir la cantidad de motores involucrados en la coordinación de una transacción a menos de lo que sería cierto aquí.
Edición : Pero, por supuesto, aunque he recomendado algo, no puede haber una respuesta general correcta aquí: perfile varios modelos de datos y enfoques con sus datos para ver qué funciona mejor para su aplicación.
Editar: Se modificó la redacción de la última edición.
Para un problema similar a su problema, hemos utilizado el enfoque de "Columna XML" (el cuarto en su encuesta de métodos). Pero debe tener en cuenta que muchas bases de datos (DBMS) admiten el índice para valores xml.
Le recomiendo usar una tabla para Persona que contiene una columna xml junto con otras columnas comunes. En otras palabras, diseñe la tabla de Personas con columnas que son comunes para todos los registros de personas y agregue una sola columna xml para atributos dinámicos y diferentes.
Estamos utilizando Oracle. soporta índice para su tipo xml. Se admiten dos tipos de índices: 1- XMLIndex para indexar elementos y atributos dentro de un xml, 2- Oracle Text Index para habilitar la búsqueda de texto completo en los campos de texto del xml.
Por ejemplo, en Oracle puede crear un índice como:
CREATE INDEX index1 ON table_name (XMLCast(XMLQuery (''$p/PurchaseOrder/Reference''
PASSING XML_Column AS "p" RETURNING CONTENT) AS VARCHAR2(128)));
y consulta xml es compatible con consultas selectas:
SELECT count(*) FROM purchaseorder
WHERE XMLCast(XMLQuery(''$p/PurchaseOrder/Reference''
PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
AS INTEGER) = 25;
Como sé, otras bases de datos como PostgreSQL y MS SQL Server (pero no mysql) admiten dichos modelos de índice para el valor xml.
vea también: http://docs.oracle.com/cd/E11882_01/appdev.112/e23094/xdb_indexing.htm#CHDEADIH
Suponiendo que coloca un límite, N, en cuántos atributos personalizados puede definir cada usuario; solo agregue N columnas adicionales a la tabla Persona. Luego, tenga una tabla separada donde almacene los metadatos por usuario para describir cómo interpretar el contenido de esas columnas para cada usuario. Similar al # 1 una vez que haya leído los datos, pero no se necesitan combinaciones para extraer los atributos personalizados.