2009-02-05 26 views
10

Necesito diseñar una tabla de clave/valor en mi base de datos y estoy buscando orientación sobre la mejor manera de hacerlo. Básicamente, necesito poder asociar valores a un conjunto dinámico de propiedades con nombre y aplicarlas a una clave externa.Pares clave/valor en una tabla de base de datos

Las operaciones que necesito para ser capaz de soportar son:

  • Aplicar un par clave/valor a un grupo de elementos
  • Enumerar todas las claves actualmente activas
  • determinar todos los elementos que tienen un valor para una clave determinada
  • Determine todos los elementos en los que el valor asociado con una tecla determinada concuerde con algunos criterios.

Parece que la forma más sencilla de hacer esto es definir una tabla:

CREATE TABLE KeyValue (
    id int, 
    Key varchar..., 
    Value varchar... 
); 

Parece que estoy probable que sea la duplicación de una gran cantidad de datos en la columna de clave porque cualquier tecla dado es probable que se defina para una gran cantidad de documentos. Reemplazar la clave varchar con una búsqueda de enteros en otra tabla parece aliviar este problema (y hacer que sea significativamente más eficiente enumerar todas las claves activas), pero me limita el problema de mantener esa tabla de búsqueda (insistiendo en ella siempre que quiera) para definir una propiedad y potencialmente eliminar la entrada cada vez que se borre una clave/valor).

¿Cuál es la mejor manera de hacerlo?

Respuesta

1

Una opción que vale la pena explorar es digerir la clave con SHA1 o MD5 antes de insertarla en la tabla.

Eso le permitirá deshacerse de la tabla de búsqueda, pero no podrá repetir las teclas porque solo va en una dirección.

1

Me parece que podría tener un par de opciones de diseño.

Opción 1: Un diseño de dos mesas que insinúa en su respuesta

Keys (
id int not null auto_increment 
key string/int 
) 
values (
id int not null auto_increment 
key_id int 
value string/varchar/int 
) 

Opción 2: tal vez como sambo99 señaló que podría modificar esta:

keys (
id int not null auto_increment 
key string/int 
hash_code int -- this would be computed by the inserting code, so that lookups would effectively have the id, and you can look them up directly 
) 

values (
id int not null auto_increment -- this column might be nice since your hash_codes might colide, and this will make deletes/updates easier 
key_id int -- this column becomes optional 
hash_code int 
value string/varchar/int... 
) 

-

+0

posibilidades de que SHA1 colisionen son más o menos 0 en realidad, debe ser super malvado para causar colisiones, si está súper preocupado podría usar SHA256 –

+2

personalmente he visto una colisión hash (TTH) en DC++, entonces es no imposible. – erikkallen

5

No optimices esto a menos que tengas que hacerlo. ¿Cuál es la longitud promedio de una clave? ¿Esta mesa será tan grande que no cabe en la memoria de su servidor si la implementa de forma ingenua? Sugeriría implementarlo de la manera más simple, medir el rendimiento y luego volver a implementar solo si el rendimiento es un problema.

Si el rendimiento es un problema, usar una clave entera y una tabla separada es probablemente el camino a seguir (las UNIONES en columnas enteras suelen ser más rápidas que las UNIONES utilizando columnas de longitud variable). Pero la primera regla de optimización es MEDIR PRIMERO: asegúrese de que su código supuestamente optimizado haga que la cosa se ejecute más rápido.

+1

+1 simplicidad. A menos que el impacto en el rendimiento sea obvio y severo, siempre opte por lo que es más fácil para trabajar, luego pruebe y optimice según sea necesario. –

30

Está utilizando un modelo de base de datos llamado Entity-Attribute-Value.Esta es una forma común de almacenar pares clave/valor en una base de datos relacional, pero tiene una serie de debilidades con respecto a la normalización y eficiencia de la base de datos.

Sí, el diseño de la mesa que mostró es la forma más común de hacerlo. En este diseño, cada atributo de cada entidad obtiene una fila distinta en su tabla KeyValue.

Aplicar un par de clave/valor a un grupo de elementos: Debe agregar una fila para cada elemento del grupo.

INSERT INTO KeyValue (id, key, value) VALUES (101, 'color', 'green'); 
INSERT INTO KeyValue (id, key, value) VALUES (102, 'color', 'green'); 
INSERT INTO KeyValue (id, key, value) VALUES (103, 'color', 'green'); 

También puede preparar la sentencia INSERT con parámetros y ejecutar a través de un número de pieza de identificación en un bucle, o lo que sea.

Enumerar todas las claves actualmente activas:

SELECT DISTINCT Key FROM KeyValue; 

determinar todos los elementos que tienen un valor para una clave dada:

SELECT id FROM KeyValue WHERE Key = 'color'; 

determinar todos los elementos donde el valor asociado con una tecla determinada coincide con algunos criterios:

SELECT id FROM KeyValue WHERE Value = 'green'; 

Algunos de los problemas con la Entidad-Atributo-Valor son:

  • hay manera de hacer llaves seguro se escriben igual para todos los elementos
  • hay manera de hacer algunas claves obligatorio para todos los artículos (es decir NOT NULL en un diseño de mesa convencional).
  • Todas las claves deben usar VARCHAR para el valor; no puede almacenar diferentes tipos de datos por clave.
  • No hay forma de usar integridad referencial; no se puede hacer una CLAVE EXTRAÑA que se aplique a los valores de algunas teclas y otras no.

Básicamente, Entity-Attribute-Value no es un diseño de base de datos normalizado.

Cuestiones relacionadas