2011-08-24 8 views
6

Sé que esto es ultra básico, pero es una suposición que siempre he defendido y me gustaría validar que es cierta (en general, con los detalles específicos de varias implementaciones)Pregunta sobre cómo se almacenan los datos de claves externas en SQL

Digamos que tengo una tabla que tiene una columna de texto "Fruta". En esa columna, solo aparece uno de los cuatro valores: Pera, Manzana, Plátano y Fresa. Tengo un millón de filas.

En lugar de repetir esos datos (en promedio) un cuarto de millón de veces cada uno, si los extraigo en otra tabla que tiene una columna Fruit y solo esas cuatro filas, y luego hago de la columna original una clave externa, ¿ahorra espacio?

Supongo que los cuatro nombres de fruta se almacenan solo una vez, y que el millón de filas ahora tienen punteros o índices o algún tipo de referencia en la segunda tabla.

Si mis valores de fila son más largos que los nombres de fruta corta, supongo que el ahorro/optimización es aún mayor.

Respuesta

4

Los tipos de datos de los campos en ambos lados de una relación de clave externa deben ser idénticos.

Si el campo clave de la tabla principal es (por ejemplo) varchar(20), los campos de clave externa en la tabla dependiente también tendrán que ser varchar(20). Lo que significa, sí, tendrías que tener X millones de filas de 'Apple' y 'Pear' y 'Banana' repitiendo en cada tabla que tiene una clave externa apuntando hacia atrás en la mesa de frutas.

En general, es más eficiente usar campos numéricos como teclas (int, bigint), ya que pueden hacer comparaciones con muy pocas instrucciones de CPU (generalmente es posible una comparación directa de instrucciones de una CPU). Las cadenas, por otro lado, requieren bucles y configuraciones comparativamente caras. Entonces, sí, sería mejor que almacenaras los nombres de las frutas en una tabla en alguna parte, y usaras los campos de ID numéricos asociados como la clave externa.

Por supuesto, debe comparar ambas configuraciones. Estas son solo reglas generales, y sus requisitos/configuración específicos en realidad pueden funcionar más rápido con la versión de strings-as-key.

+0

Piense en una variable de tipo de referencia 3GL como C# .NET: su valor sale en una ubicación en la memoria pero puede tener muchas variables de referencia que son meramente punteros enteros (o lo que sea) a esa ubicación. El mismo principio se puede aplicar a DBMS: lógicamente ambas tablas en un FK almacenan la fruta como texto pero debajo de las cubiertas el texto se almacena una sola vez y cada tabla almacena físicamente solo un entero (o lo que sea) un puntero al mismo valor. ¿MySQL hace esto? Creo que eso es a lo que se dirige la persona que pregunta. – onedaywhen

+1

No compararía las prácticas de almacenamiento de datos de mysql con un lenguaje de programación. Tendría sentido almacenar solo una copia, pero las claves externas no son referencias. son solo un campo como cualquier otro que contiene información que coincide con el campo/datos equivalentes en otra tabla. Después de todo, dejar caer una llave foránea en una mesa grande es casi instantáneo. Si fuera una referencia, el DBMS tendría que copiar sobre los datos reales ahora que la referencia se ha ido. –

5

Eso es correcto.

Debe tener

table fruits 
id name 
1 Pear 
2 Apple 
3 Banana 
4 Strawberry 

donde ID es una clave principal. En su segunda tabla usará solo el id de esta tabla. Eso le ahorrará espacio físico y hará que sus declaraciones seleccionadas funcionen más rápido.
Además, esta estructura le facilitaría la tarea de agregar nuevas frutas.

2

En vez de repetir que los datos (en promedio) un cuarto de millón de veces cada uno, si puedo extraer en una otra tabla que tiene una columna de frutas y sólo esas cuatro filas, y luego hacer la columna original de una extranjera clave, ¿ahorra espacio?

No si el "fruto" es la clave primaria de la tabla de "búsqueda", por lo que también debe ser la clave externa de la tabla "grande".

Sin embargo, si crea una PRIMARY KEY pequeña (como "id" entero) en la tabla "lookup" y la usa como FOREIGN KEY en la tabla "grande", ahorrará espacio.

1

Al principio yes ahorrará espacio porque int - 4 bytes, TINYINT - 1 byte. En segundo lugar, buscar en este campo con TYPE INT será más rápido que con VARCHAR. Además de esto, puede usar ENUM si sus datos no cambian en el futuro. Con enum obtendrá el mismo resultado tal vez más rápido que con la tabla secundaria y evitará la unión adicional.

2

La normalización no se trata solo de espacio, a menudo se trata de redundancia y modelado del comportamiento de datos y también de actualizar solo una fila para un cambio y reducir el alcance de bloqueos actualizando solo la cantidad mínima de datos.

0

Entiendo que usted no realmente desea utilizar claves externas. Aaah, Marc B acaba de publicar las implicaciones en FK. Pero usar una segunda tabla como un "proveedor de nombre" externo definitivamente ahorraría espacio. Necesitará un índice adicional en fruit.fruit_id. Este será bastante pequeño y será NUMÉRICO. Más rápido que los índices en char o varchar.

1

Lamentablemente, se supone que está mal: los valores se almacenan físicamente de forma repetida para cada tabla de referencia. Algunos productos SQL almacenan el valor solo una vez, pero la mayoría no, especialmente los más populares que se basan en el almacenamiento contiguo en el disco.

Esta es la razón por la cual los usuarios finales sienten la necesidad de implementar sus propios puntos bajo el pretexto de usar 'claves sustitutas' enteras. Un sustituto del sistema sería preferible, p. no sería visible para los usuarios, del mismo modo que el sistema mantiene los 'valores' de un índice y los usuarios no pueden manipularlos directamente. El problema de enrollar el suyo es que se vuelven parte del modelo lógico.

Cuestiones relacionadas