¿Cómo diseñar una base de datos para campos definidos por el usuario?

145

Mis requerimientos son:

  • Necesita poder agregar dinámicamente campos definidos por el usuario de cualquier tipo de datos
  • Necesita poder consultar UDF rápidamente
  • Necesita poder hacer cálculos en UDF basados ​​en el tipo de datos
  • Necesita poder ordenar UDF según el tipo de datos

Otra información:

  • Estoy buscando rendimiento principalmente
  • Hay algunos millones de registros maestros que pueden tener datos UDF adjuntos
  • La última vez que lo verifiqué, había más de 50 mil registros UDF en nuestra base de datos actual.
  • La mayoría de las veces, un UDF solo se adjunta a unos pocos miles de registros maestros, no a todos
  • Los UDF no se unen ni se usan como claves. Son solo datos utilizados para consultas o informes

Opciones:

  1. Cree una tabla grande con StringValue1, StringValue2 ... IntValue1, IntValue2, ... etc. Odio esta idea, pero consideraré si alguien me puede decir que es mejor que otras ideas y por qué.

  2. Cree una tabla dinámica que agregue una nueva columna a pedido según sea necesario. Tampoco me gusta esta idea, ya que siento que el rendimiento sería lento a menos que indices cada columna.

  3. Cree una sola tabla que contenga UDFName, UDFDataType y Value. Cuando se agrega un nuevo UDF, genere una Vista que extraiga solo esos datos y los analice en el tipo especificado. Los elementos que no cumplen los criterios de análisis devuelven NULL.

  4. Cree múltiples tablas UDF, una por tipo de datos. Entonces tendríamos tablas para UDFStrings, UDFDates, etc. Probablemente haría lo mismo que # 2 y generaría automáticamente una Vista cada vez que se agregue un nuevo campo

  5. Tipos de datos XML? No he trabajado con estos antes, pero los he visto mencionados. No estoy seguro de si me darían los resultados que quiero, especialmente con el rendimiento.

  6. ¿Algo más?

Rachel
fuente
77
Martin Fowler recomienda 2 (esquema actualizable por el usuario) o 5 (LOB XML indexado): martinfowler.com/bliki/UserDefinedField.html
Neil McGuigan
Consulte también la pregunta de StackOverflow sobre esquemas de bases de datos dinámicas .
FloverOwe

Respuestas:

49

Si el rendimiento es la principal preocupación, iría con el # 6 ... una tabla por UDF (realmente, esta es una variante del # 2). Esta respuesta está específicamente diseñada para esta situación y la descripción de la distribución de datos y los patrones de acceso descritos.

Pros:

  1. Debido a que indica que algunos UDF tienen valores para una pequeña porción del conjunto de datos general, una tabla separada le brindará el mejor rendimiento porque esa tabla será tan grande como sea necesario para admitir el UDF. Lo mismo es válido para los índices relacionados.

  2. También obtiene un aumento de velocidad al limitar la cantidad de datos que deben procesarse para agregaciones u otras transformaciones. Dividir los datos en varias tablas le permite realizar algunos de los análisis estadísticos agregados y de otro tipo en los datos UDF, luego unir ese resultado a la tabla maestra a través de una clave externa para obtener los atributos no agregados.

  3. Puede usar nombres de tabla / columna que reflejen cuáles son realmente los datos.

  4. Tiene control completo para usar tipos de datos, verificar restricciones, valores predeterminados, etc. para definir los dominios de datos. No subestimes el impacto en el rendimiento resultante de la conversión de tipos de datos sobre la marcha. Tales restricciones también ayudan a los optimizadores de consultas RDBMS a desarrollar planes más efectivos.

  5. Si alguna vez necesita utilizar claves foráneas, la integridad referencial declarativa incorporada rara vez se ve superada por la aplicación de restricciones basadas en disparadores o en el nivel de aplicación.

Contras:

  1. Esto podría crear muchas tablas. Hacer cumplir la separación de esquemas y / o una convención de nombres aliviaría esto.

  2. Se necesita más código de aplicación para operar la definición y gestión de UDF. Espero que esto sea aún menos código necesario que para las opciones originales 1, 3 y 4.

Otras Consideraciones:

  1. Si hay algo sobre la naturaleza de los datos que tenga sentido para que se agrupen los UDF, eso debería alentarse. De esa manera, esos elementos de datos se pueden combinar en una sola tabla. Por ejemplo, supongamos que tiene UDF para color, tamaño y costo. La tendencia en los datos es que la mayoría de las instancias de estos datos parecen

     'red', 'large', 45.03 

    más bien que

     NULL, 'medium', NULL

    En tal caso, no incurrirá en una penalización de velocidad notable al combinar las 3 columnas en 1 tabla porque pocos valores serían NULOS y evitará crear 2 tablas más, que son 2 uniones menos necesarias cuando necesita acceder a las 3 columnas .

  2. Si llega a un muro de rendimiento desde un UDF que está muy poblado y se usa con frecuencia, entonces se debe considerar su inclusión en la tabla maestra.

  3. El diseño lógico de la tabla puede llevarlo a un cierto punto, pero cuando los recuentos de registros se vuelven realmente masivos, también debe comenzar a ver qué opciones de partición de tabla proporciona su RDBMS de elección.

Phil Helmer
fuente
1
Listas de verificación! Broma interna entre Phil y yo, espero que eso no esté en contra de las reglas.
GunnerL3510
Gracias, creo que haré alguna variación de esto. La mayoría de nuestros datos UDF provienen de campos de importación no asignados que necesitan permanecer solo con fines de referencia, por lo que me gustaría ponerlos en una tabla. Otros UDF se definen según sea necesario (no puedo identificarlos de antemano ... generalmente se crean cuando cambiamos algún proceso o decidimos rastrear algo especial durante unos meses) y se usan comúnmente en consultas. Creo que haré una tabla separada para cada unidad lógica de estos valores.
Rachel
Estoy trabajando con una tabla que tiene UDF con fecha / versión, utilizo este método, stackoverflow.com/a/123481/328968 , para obtener los últimos valores.
Peter
22

He escrito sobre este problema mucho . La solución más común es el antipatrón Entity-Attribute-Value, que es similar a lo que usted describe en su opción # 3. Evita este diseño como la peste .

Lo que uso para esta solución cuando necesito campos personalizados verdaderamente dinámicos es almacenarlos en un blob de XML, para poder agregar nuevos campos en cualquier momento. Pero para hacerlo más rápido, también cree tablas adicionales para cada campo en el que necesite buscar u ordenar (no tiene una tabla por campo, solo una tabla por campo de búsqueda ). Esto a veces se denomina diseño de índice invertido.

Puede leer un artículo interesante de 2009 sobre esta solución aquí: http://backchannel.org/blog/friendfeed-schemaless-mysql

O puede usar una base de datos orientada a documentos, donde se espera que tenga campos personalizados por documento. Yo elegiría Solr .

Bill Karwin
fuente
1
¿Puede explicar por qué debería evitar la opción 3? Miré algunos de sus ejemplos, pero en realidad no son lo mismo que estoy tratando de hacer. Simplemente quiero un lugar para almacenar datos adicionales, no un lugar para almacenar todos los atributos.
Rachel
2
Para empezar, ¿a quién le asignarías un atributo NOT NULL? ¿Cómo haría un atributo ÚNICO sin hacer que todos los atributos sean ÚNICOS? Continúa desde allí. Termina escribiendo el código de la aplicación para proporcionar características que el RDBMS ya le proporciona, incluso hasta el punto de tener que escribir algún tipo de clase de mapeo simplemente insertando un registro de entidad lógica y recuperándolo.
Bill Karwin
2
La respuesta corta es "no mezcle datos y metadatos". Crear columnas varchar para fieldnameo tablenamees almacenar identificadores de metadatos como cadenas de datos, y ese es el comienzo de muchos de los problemas. Ver también en.wikipedia.org/wiki/Inner-platform_effect
Bill Karwin
2
@Thomas: en el diseño de índice invertido, puede usar soluciones de esquema estándar para tipos de datos y restricciones como UNIQUE y FOREIGN KEY. Esos no funcionan en absoluto cuando usa EAV. Estoy de acuerdo en que el índice invertido comparte con EAV el rasgo de no ser relacional simplemente porque admite atributos diferentes por fila, pero es un punto de compromiso.
Bill Karwin
2
@thitami, lo que he aprendido a lo largo de los años es que cualquier solución podría ser la adecuada para su aplicación. Incluso EAV podría ser la solución menos mala para alguna aplicación específica. No puede elegir una estrategia de optimización sin conocer sus consultas. Cada tipo de optimización mejora ciertas consultas a expensas de otras consultas.
Bill Karwin
10

Lo más probable es que cree una tabla con la siguiente estructura:

  • Nombre varchar
  • Tipo varchar
  • Valor decimal de número
  • varchar StringValue
  • date DateValue

Los tipos exactos de curso dependen de sus necesidades (y, por supuesto, de los dbms que está utilizando). También puede usar el campo NumberValue (decimal) para int's y booleans. Es posible que también necesite otros tipos.

Necesita algún enlace a los registros maestros que poseen el valor. Probablemente sea más fácil y rápido crear una tabla de campos de usuario para cada tabla maestra y agregar una clave foránea simple. De esta forma, puede filtrar registros maestros por campos de usuario de forma fácil y rápida.

Es posible que desee tener algún tipo de información de metadatos. Entonces terminas con lo siguiente:

Tabla UdfMetaData

  • int id
  • Nombre varchar
  • Tipo varchar

Table MasterUdfValues

  • int Master_FK
  • int MetaData_FK
  • Valor decimal de número
  • varchar StringValue
  • date DateValue

Hagas lo que hagas, no cambiaría la estructura de la tabla dinámicamente. Es una pesadilla de mantenimiento. También me no utilizo estructuras XML, son demasiado lentos.

Stefan Steinegger
fuente
Me gusta su estrategia, y tal vez opte por ella, pero en 2017, ¿optará por algo diferente? como json
maztt
En nuestro proyecto, implementamos nuestras propias estructuras de datos que se serializan en algo similar a json. Cuenta con una interfaz typesave para leer y escribir datos sin conversión y con una excelente integración del lenguaje de programación. Eso es realmente genial. Tiene el mismo problema que todo este tipo de "documentos" en las bases de datos. Es difícil consultar valores específicos y no puede hacer referencia fácilmente a datos fuera del "documento". Dependiendo del uso, ambos ni siquiera son un problema.
Stefan Steinegger
Además de eso, lo que propuse en 2011 es, en mi humilde opinión, una solución válida.
Stefan Steinegger
10

Esto suena como un problema que podría resolverse mejor con una solución no relacional, como MongoDB o CouchDB.

Ambos permiten la expansión del esquema dinámico al tiempo que le permiten mantener la integridad de tupla que busca.

Estoy de acuerdo con Bill Karwin, el modelo EAV no es un enfoque eficaz para usted. Usar pares de nombre-valor en un sistema relacional no es intrínsecamente malo, pero solo funciona bien cuando el par de nombre-valor forma una tupla completa de información. Cuando lo usa, lo obliga a reconstruir dinámicamente una tabla en tiempo de ejecución, todo tipo de cosas comienzan a ponerse difíciles. La consulta se convierte en un ejercicio de mantenimiento de pivote o lo obliga a empujar la reconstrucción de la tupla hacia la capa del objeto.

No puede determinar si un valor nulo o faltante es una entrada válida o falta de entrada sin incrustar reglas de esquema en su capa de objeto.

Pierde la capacidad de administrar eficientemente su esquema. ¿Es un varchar de 100 caracteres el tipo correcto para el campo "valor"? 200 caracteres? ¿Debería ser nvarchar en su lugar? Puede ser un compromiso difícil y uno que termina con la necesidad de establecer límites artificiales en la naturaleza dinámica de su conjunto. Algo así como "solo puede tener x campos definidos por el usuario y cada uno solo puede tener y caracteres de longitud.

Con una solución orientada a documentos, como MongoDB o CouchDB, mantiene todos los atributos asociados con un usuario dentro de una sola tupla. Dado que las uniones no son un problema, la vida es feliz, ya que a ninguno de estos dos les va bien a pesar de la exageración. Sus usuarios pueden definir tantos atributos como quieran (o lo permitirá) en longitudes que no serán difíciles de administrar hasta que alcance aproximadamente 4 MB.

Si tiene datos que requieren integridad de nivel ACID, podría considerar dividir la solución, con los datos de alta integridad que viven en su base de datos relacional y los datos dinámicos que viven en un almacén no relacional.

Monje de datos
fuente
6

Incluso si proporciona un usuario que agrega columnas personalizadas, no será necesariamente el caso que las consultas en esas columnas funcionen bien. Hay muchos aspectos que intervienen en el diseño de consultas que les permiten tener un buen desempeño, el más importante de los cuales es la especificación adecuada de lo que debe almacenarse en primer lugar. Por lo tanto, fundamentalmente, ¿es que desea permitir a los usuarios crear esquemas sin pensar en las especificaciones y poder obtener rápidamente información de ese esquema? Si es así, es poco probable que cualquier solución de este tipo se adapte bien, especialmente si desea permitir que el usuario realice un análisis numérico de los datos.

Opción 1

En mi opinión, este enfoque le brinda un esquema sin conocimiento de lo que significa el esquema, que es una receta para el desastre y una pesadilla para los diseñadores de informes. Es decir, debe tener los metadatos para saber qué columna almacena qué datos. Si esos metadatos se confunden, tiene el potencial de manipular sus datos. Además, facilita colocar los datos incorrectos en la columna incorrecta. ("¿Qué? String1 contiene el nombre de conventos? Pensé que eran las drogas favoritas de Chalie Sheen")

Opción 3,4,5

OMI, los requisitos 2, 3 y 4 eliminan cualquier variación de un EAV. Si necesita consultar, ordenar o hacer cálculos sobre estos datos, un EAV es el sueño de Cthulhu y la pesadilla de su equipo de desarrollo y DBA. Los EAV crearán un cuello de botella en términos de rendimiento y no le brindarán la integridad de los datos que necesita para obtener rápidamente la información que desea. Las consultas se convertirán rápidamente en nudos cruzados de Gordian.

Opción 2,6

Eso realmente deja una opción: reunir especificaciones y luego construir el esquema.

Si el cliente desea el mejor rendimiento en los datos que desea almacenar, debe pasar por el proceso de trabajar con un desarrollador para comprender sus necesidades de modo que se almacene de la manera más eficiente posible. Todavía podría almacenarse en una tabla separada del resto de las tablas con código que crea dinámicamente un formulario basado en el esquema de la tabla. Si tiene una base de datos que permite propiedades extendidas en columnas, incluso podría usarlas para ayudar al creador de formularios a usar etiquetas agradables, información sobre herramientas, etc., de modo que todo lo que se necesita es agregar el esquema. De cualquier manera, para crear y ejecutar informes de manera eficiente, los datos deben almacenarse correctamente. Si los datos en cuestión tendrán muchos nulos, algunas bases de datos tienen la capacidad de almacenar ese tipo de información. Por ejemplo,

Si esto fuera solo una bolsa de datos en la que no se realizaría ningún análisis, filtrado u ordenación, diría que alguna variación de un EAV podría ser el truco. Sin embargo, dados sus requisitos, la solución más eficiente será obtener las especificaciones adecuadas, incluso si almacena estas nuevas columnas en tablas separadas y crea formularios dinámicamente a partir de esas tablas.

Columnas dispersas

Thomas
fuente
5
  1. Cree múltiples tablas UDF, una por tipo de datos. Entonces tendríamos tablas para UDFStrings, UDFDates, etc. Probablemente haría lo mismo que # 2 y generaría automáticamente una Vista cada vez que se agregue un nuevo campo

Según mi investigación, varias tablas basadas en el tipo de datos no te ayudarán en el rendimiento. Especialmente si tiene datos masivos, como 20K o 25K registros con más de 50 UDF. El rendimiento fue lo peor.

Debe ir con una sola tabla con varias columnas como:

varchar Name
varchar Type
decimal NumberValue
varchar StringValue
date DateValue
Contratista Amit
fuente
Esto debería ser correcto y votado. La respuesta anterior de Phil en 2011 ya no es un buen consejo hoy 2016.
Yap Kai Lun Leon
¿Puedo obtener un ejemplo simple de cómo hacer tal proceso en sql.?
Niroj
Perdón por la respuesta tardía, pero desea la estructura de la base de datos para lo mismo. No te entendí @Niroj. ¿Puede explicar en detalle como lo que quiere?
Contratista Amit
4

Esta es una situación problemática, y ninguna de las soluciones parece "correcta". Sin embargo, la opción 1 es probablemente la mejor tanto en términos de simplicidad como de rendimiento.

Esta es también la solución utilizada en algunas aplicaciones empresariales comerciales.

EDITAR

Otra opción que está disponible ahora, pero no existía (o al menos no estaba madura) cuando la pregunta original se hizo es utilizar campos json en la base de datos.

muchos DB relacionales ahora admiten campos basados ​​en json (que pueden incluir una lista dinámica de subcampos) y permiten consultarlos

postgreso

mysql

Ophir Yoktan
fuente
1
Odio la idea de crear posiblemente cientos de columnas no utilizadas. Va en contra de lo que he aprendido y leído sobre el diseño de bases de datos SQL. En este momento, tenemos más de 1300 valores diferentes definidos por el usuario, aunque muchos de ellos son simplemente duplicados de elementos existentes que se nombran de manera diferente.
Rachel
¿1300 UDF diferentes para una sola mesa? ¿Cada usuario tiene la opción de agregar UDF, o solo algún tipo de usuario avanzado?
Ophir Yoktan
Es parte del proceso de importación ... agrega datos no asignados a un campo definido por el usuario. Como nadie se toma el tiempo de asignar datos no asignados a campos UDF existentes, solo crea otros nuevos y con los años se han agregado muchos.
Rachel
2

He tenido experiencia con 1, 3 y 4 y todos terminan siendo desordenados, ya que no está claro cuáles son los datos o realmente complicado con algún tipo de categorización suave para dividir los datos en tipos dinámicos de registro.

Me sentiría tentado a probar XML, debería poder aplicar esquemas contra el contenido del xml para verificar la escritura de datos, etc., lo que ayudará a mantener conjuntos de datos UDF diferentes. En las versiones más recientes del servidor SQL, puede indexar en campos XML, lo que debería ayudar en el rendimiento. (ver http://blogs.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx ) por ejemplo

Jon Egerton
fuente
Honestamente, no he investigado XML en absoluto. El principal inconveniente de eso es que tendría que aprender cómo funcionaba y cómo consultarlo, y he oído que el rendimiento puede ser peor que las otras opciones
Rachel
1
Evitaría usar xml para esto: puede hacer el trabajo, y he implementado algo como esto en xml en el pasado, pero el rendimiento se volvió bastante malo a medida que crecieron las estructuras de datos y la complejidad del código fue alta.
Kell
2

Si está utilizando SQL Server, no pase por alto el tipo sqlvariant. Es bastante rápido y debería hacer tu trabajo. Otras bases de datos pueden tener algo similar.

Los tipos de datos XML no son tan buenos por razones de rendimiento. Si está haciendo cálculos en el servidor, tendrá que deserializarlos constantemente.

La opción 1 suena mal y se ve cruda, pero en cuanto al rendimiento puede ser su mejor opción. He creado tablas con columnas llamadas Field00-Field99 antes porque simplemente no puedes superar el rendimiento. Es posible que también deba considerar su rendimiento INSERT, en cuyo caso este también es el indicado. ¡Siempre puede crear Vistas en esta tabla si desea que se vea ordenada!

Tim Rogers
fuente
Gracias, echaré otro vistazo a las variantes de SQL. Mi mayor preocupación es el rendimiento y no estoy seguro de cómo manejaría eso, especialmente si estamos hablando de más de 50mil filas
Rachel
Acabo de descubrir que sql_varients no se puede usar con la cláusula LIKE ... eso es un gran inconveniente para mí. Por supuesto, si creo una vista para cada UDF, podría convertirlo al tipo de datos apropiado basado en SQL_VARIANT_PROPERTY (valor, 'BaseType') ... aún así, parece que es malo para el rendimiento
Rachel
Puede usar LIKE, pero primero debe emitir el valor. LIKE solo funciona en varchars, por lo que debe convertir su sql_variant en un varchar. Siempre que sepa si su UDF es un varchar (por ejemplo, porque el tipo está almacenado en otro lugar), puede filtrar todas sus filas a varchars y luego lanzar y ejecutar su consulta LIKE: por ejemplo. seleccione * FROM MyTable donde variant_type = 'v' Cast (variant_value as varchar (max)) LIKE 'Blah%' De esta manera, no está convirtiendo ints y así sucesivamente en cadenas que lo retrasarían.
Tim Rogers
Necesitaría ejecutar algunas pruebas para ver cómo es el rendimiento en eso, especialmente con millones de filas. ¿Conoces algún artículo en línea sobre rendimiento usando sql_varients? ¿Especialmente con casting y un gran número de registros?
Rachel
1

SharePoint usa la opción 1 y tiene un rendimiento razonable.

Nathan DeWitt
fuente
1

He logrado esto con mucho éxito en el pasado sin usar ninguna de estas opciones (opción 6? :)).

Creo un modelo para que jueguen los usuarios (almacenar como xml y exponer a través de una herramienta de modelado personalizada) y de las tablas y vistas generadas por el modelo para unir las tablas base con las tablas de datos definidas por el usuario. Por lo tanto, cada tipo tendría una tabla base con datos básicos y una tabla de usuario con campos definidos por el usuario.

Tome un documento como ejemplo: los campos típicos serían nombre, tipo, fecha, autor, etc. Esto iría en la tabla principal. Luego, los usuarios definirían sus propios tipos de documentos especiales con sus propios campos, como contract_end_date, renewal_clause, blah blah blah. Para ese documento definido por el usuario, habría la tabla de documentos principales, la tabla xcontract, unida en una clave primaria común (por lo que la clave primaria xcontracts también es ajena a la clave principal de la tabla principal). Entonces generaría una vista para envolver estas dos tablas. El rendimiento cuando las consultas fueron rápidas. También se pueden incrustar reglas comerciales adicionales en las vistas. Esto funcionó muy bien para mí.

Kell
fuente
1

Nuestra base de datos utiliza una aplicación SaaS (software de servicio de asistencia) donde los usuarios tienen más de 7k "campos personalizados". Utilizamos un enfoque combinado:

  1. (EntityID, FieldID, Value)mesa para buscar los datos
  2. un campo JSON en la entitiestabla, que contiene todos los valores de entidad, utilizados para mostrar los datos. (de esta manera no necesita un millón de JOIN para obtener los valores de los valores).

Podría dividir aún más el # 1 para tener una "tabla por tipo de datos" como esta respuesta sugiere , de esta manera incluso puede indexar sus UDF.

PD: Un par de palabras para defender el enfoque de "Entidad-Atributo-Valor" que todos siguen criticando. Hemos usado # 1 sin # 2 durante décadas y funcionó bien. A veces es una decisión comercial. ¿Tiene tiempo para reescribir su aplicación y rediseñar el db o puede gastar un par de dólares en servidores en la nube, que son realmente baratos en estos días? Por cierto, cuando estábamos usando el enfoque n. ° 1, nuestra base de datos tenía millones de entidades, a las que accedían cientos de miles de usuarios, y un servidor db de doble núcleo de 16 GB funcionaba bien

Alex
fuente
Hola @ Alex, me encontré con un problema similar. Si entiendo bien, tiene: 1) una custom_fieldstabla que almacena valores como 1 => last_concert_year, 2 => band, 3 => musicy luego una custom_fields_valuestabla con valores 001, 1, 1976 002, 1, 1977 003, 2, Iron Maiden003, 3 ¡ Metal Espero que el ejemplo tenga sentido para ti y perdón por el formato!
thitami
@thitami no exactamente. Siguiendo su ejemplo: Tengo una bandstabla con una fila, 1,'Iron Maiden'luego custom_fieldscon filas y 1,'concert_year' | 2,'music'luego custom_fields_valuescon filas1,1,'1977'|1,2,'metal'
Alex
0

En los comentarios, lo vi decir que los campos UDF son para volcar datos importados que el usuario no ha asignado correctamente.

Quizás otra opción es rastrear la cantidad de UDF hechas por cada usuario y obligarlos a reutilizar campos diciendo que pueden usar 6 (o algún otro límite igualmente aleatorio) de campos personalizados.

Cuando se enfrenta a un problema de estructuración de la base de datos como este, a menudo es mejor volver al diseño básico de la aplicación (sistema de importación en su caso) y ponerle algunas restricciones más.

Ahora lo que haría es la opción 4 (EDITAR) con la adición de un enlace a los usuarios:

general_data_table
id
...


udfs_linked_table
id
general_data_id
udf_id


udfs_table
id
name
type
owner_id --> Use this to filter for the current user and limit their UDFs
string_link_id --> link table for string fields
int_link_id
type_link_id

Ahora asegúrese de hacer vistas para optimizar el rendimiento y obtener sus índices correctos. Este nivel de normalización reduce el tamaño de la base de datos, pero su aplicación es más compleja.

Wouter Simons
fuente
0

Recomendaría # 4 ya que este tipo de sistema se usó en Magento, que es una plataforma CMS de comercio electrónico altamente acreditada. Use una sola tabla para definir sus campos personalizados usando fieldId y columnas de etiquetas . Luego, tenga tablas separadas para cada tipo de datos y dentro de cada una de esas tablas tenga un índice que indexe por fieldId y las columnas de valor de tipo de datos . Luego, en sus consultas, use algo como:

SELECT *
FROM FieldValues_Text
WHERE fieldId IN (
    SELECT fieldId FROM Fields WHERE userId=@userId
)
AND value LIKE '%' + @search + '%'

Esto garantizará el mejor rendimiento posible para los tipos definidos por el usuario en mi opinión.

En mi experiencia, he trabajado en varios sitios web de Magento que atienden a millones de usuarios por mes, alojan miles de productos con atributos de producto personalizados y la base de datos maneja la carga de trabajo fácilmente, incluso para generar informes.

Para generar informes, puede utilizar PIVOTpara convertir los valores de etiqueta de la tabla Campos en nombres de columna, luego pivotar los resultados de su consulta de cada tabla de tipo de datos en esas columnas pivotadas.

Mark Entingh
fuente