¿Cómo puedo manejar diferentes tipos de datos en un diseño de Entidad-Atributo-Valor (por ejemplo, una sola tabla con varias columnas o varias tablas por tipo de datos)?


Quiero crear una tabla de metadatos de paciente/muestra utilizando un enfoque de entidad-atributo-valor (EAV).

Pregunta: ¿Cómo debo manejar el tipo de columna variable del valor (por ejemplo, cadena, numérico o clave externa a la tabla del diccionario) basado en el atributo ?

Nota: No estoy preguntando si usar o no un enfoque EAV. He mirado otras preguntas SO y referencias y creo que esta es la mejor enfoque para mi caso de uso (por ejemplo, no quiero crear una columna o tabla separada para cada atributo - que puede numerar en cientos). Sin embargo, sin duda reconsideraré otros diseños dado un ejemplo completo.

Datos representativos

Un paciente/muestra ( entidad) puede tener múltiples atributos de metadatos (por ejemplo, ubicación del laboratorio, supervivencia, tipo de tumor) cada uno con un valor tipo (por ejemplo.VARCHAR, NUMBER, FOREIGN_KEY*, respectivamente).

*FOREIGN_KEY significa que este valor tipo es un ID de clave externa (INTEGER) a una tabla de diccionario de valores (por ejemplo, una lista de los 10 posibles tipos de tumores). Así que la ubicación del laboratorio puede ser VARCHAR ya que no me importa normalizar esos valores. Pero el tipo de tumor debe tener algún grado de validación.

El diseño de mi tabla puede verse algo como esto:

CREATE TABLE patients (
  patient_id INTEGER CONSTRAINT pk_patients PRIMARY KEY,
  patient_name VARCHAR2(50) NOT NULL
);

CREATE TABLE metadata_attributes (
  attribute_id INTEGER CONSTRAINT pk_metadata_attributes PRIMARY KEY,
  attribute_name VARCHAR2(50) NOT NULL,
  attribute_value_type VARCHAR(50) NOT NULL -- e.g. VARCHAR, NUMBER, or ID
);

CREATE TABLE patient_metadata (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value ???
);

Creo que necesito un value type identifying column (attribute_value_type) en el metadata_attributes table para saber a qué columna / tabla mirar.

Posibles enfoques

Aquí hay dos enfoques posibles que se me ocurren.

Enfoque 1: Tabla EAV única con múltiples columnas

Cree tres columnas diferentes en la tabla patient_metadata, una para cada tipo value.

CREATE TABLE patient_metadata (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_varchar_value VARCHAR(50),
  attribute_number_value NUMBER,
  attribute_id_value CONSTRAINT fk_pm_values REFERENCES some_table_of_values(value_id)
);

Enfoque 2: Múltiples tablas EAV

Crear tres tablas patient_metadata diferentes-una para cada valor tipo.

CREATE TABLE patient_metadata_varchar (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value VARCHAR(50) NOT NULL
);

CREATE TABLE patient_metadata_number (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value NUMBER NOT NULL
);

CREATE TABLE patient_metadata_id (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value CONSTRAINT fk_pm_values REFERENCES some_table_of_values(value_id) NOT NULL
);

Otros Enfoques?

¿Hay otros enfoques por ahí?

En resumen, quiero respetar la integridad relacional tanto como sea posible y permitir que la base de datos conozca el tipo value para que pueda realizar una validación básica. Sin embargo, creo que ambos enfoques anteriores requerirán algún tipo de comprobación manual de integridad (el enfoque 1 requiere una comprobación de que solo se rellene una columna attribute_value, etc.).).

Los tipos de consultas que se llevará a cabo será típico (por ejemplo, recuperar una lista de valores para un determinado atributo de metadatos , recuperar una lista de valores para un determinado paciente (entidad) y metadatos atributo, etc.). Creo que necesitaré consultar el tipo value en la mayoría de los casos para saber qué columna o tabla consultar. Cualquier otra forma de evitar esto?

Cuáles son los pros y los contras de todos los enfoques (rendimiento, estructura de consulta, sucesivamente.)?

Cartel por primera vez, así que gracias de antemano y por favor no dude en comentar sobre el formato o más aclaraciones!

Author: Community, 2013-08-07

2 answers

Este es un problema bien conocido. El problema con el enfoque que mencionó es que necesita saber el tipo del atributo antes de consultarlo. no es el fin del mundo porque administras metadatos, pero aún así...

Dos soluciones posibles podrían ser

  1. usando un tipo de datos varchar2 para representar todos los tipos de datos en un formato. Los números y los caracteres no son un problema, los valores de fecha se pueden escribir de una manera predefinida (es como implementar to_String() en cualquier OO diseño).
  2. utilice el ANYDATA tipo de datos. personalmente jugué con él, pero decidí no usar se.
 4
Author: haki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-24 07:07:37

Lo más fácil, más eficiente, etc. es convertir todos los valores de la base de datos en Cadenas. Los problemas como los indicados generalmente serán obvios, e incluso las columnas bien escritas sufren exactamente el mismo tipo de problemas, que generalmente se expresan como problemas de rendimiento.

Con un poco de cuidado, puede mantener el orden de intercalación, si eso importa (por ejemplo, formateando las fechas como año/mes/día), y la validación de los tipos no debe ser realizada por la base de datos de todos modos, ya que es demasiado tarde. Números negativos son un dolor, al igual que los flotadores, pero es muy inusual indexar por un número que puede ser negativo o un flotador, y las clases en memoria son generalmente rápidas.

Cuando el tipo de los datos no es obvio, o necesita ser conocido por un procesador descendente, agregue una columna de tipo.

Generalmente, todas las restricciones de integridad contra los valores de columna se pueden verificar antes de escribir el registro, ya sea en código (bueno) o en disparadores (no tan bueno). Tratando de utilizar las características nativas con diferentes tipos solo le llevará hasta el momento, y probablemente no sea tan útil de todos modos, ya que los valores a menudo tienen muchas restricciones específicas del negocio de todos modos, por ejemplo, la fecha de nacimiento debe ser no nula y posterior a 1900.

Para el rendimiento, utilice índices compuestos que incluyan la entidad y el atributo como prefijos. Los índices pueden ser particionados por el prefijo entity-attribute, reduciendo cualquier impacto de la profundidad extra del índice, y se comprimen muy bien (el prefijo se comprimirá a uno o dos bytes), por lo que la diferencia de tamaño es mínima.

Las consultas desde tablas EAV a menudo se realizan mejor en vistas que desempaquetarán las entidades para que la estructura pueda devolverse a algo como lo esperaría, aunque esto puede ser irrelevante si está tratando con columnas variables, por ejemplo, en formas de pacientes que se caracterizan por un gran número de elementos variables dependiendo del historial. Entonces es probablemente más fácil de procesar en su lógica de negocio.

Finalmente, hoy en día este tipo de datos simplemente no se almacena en estilo de base de datos relacional orientado a columnas. Por lo general, se almacena como un documento XML (o JSON) (tipos XML en Oracle), y la mayoría de las bases de datos proporcionan alguna capacidad de procesamiento XML nativa para buscar y manipular dichos datos. Esto está bien para el almacenamiento y recuperación de formularios normales, pero tiende a hacer consultas arbitrarias como "dame a todos los pacientes mayores de 60 que han tenido neumonía en el último año" bastante lento, o un poco más involucrado ya que se necesita indexación inversa etiquetada. Sin embargo, tiene que ver si un enfoque orientado a documento/texto es una mejor solución.

¡Buena suerte!

 2
Author: emperorz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-04 15:54:41