2009-09-05 49 views
18

Estoy trabajando en el diseño de una base de datos que se utilizará para almacenar datos que provienen de una serie de fuentes diferentes. Las instancias que estoy almacenando tienen identificadores únicos asignados por las fuentes originales. Cada instancia que almaceno debe contener información sobre la fuente de donde proviene, junto con la ID a la que estuvo asociada esta fuente.clave primaria compuesta

Como ejemplo, considere la siguiente tabla que ilustra el problema:

---------------------------------------------------------------- 
| source_id | id_on_source | data        | 
---------------------------------------------------------------- 
| 1   | 17600  | ...        | 
| 1   | 17601  | ...        | 
| 2   | 1   | ...        | 
| 3   | 1   | ...        | 
---------------------------------------------------------------- 

Tenga en cuenta que mientras que el id_on_source es único para cada fuente, es posible que el mismo id_on_source a encontrar por diferentes fuentes.

Tengo una comprensión decente de las bases de datos relacionales, pero estoy lejos de ser un experto o incluso un usuario experimentado. El problema que enfrento con este diseño es lo que debería usar como clave principal. Los datos parecen dictar el uso de una clave primaria compuesta de (source_id, id_on_source). Después de un poco de google encontré algunos acalorados debates sobre los pros y los contras de las claves primarias compuestas, sin embargo, dejándome un poco confundido.

La tabla tendrá una relación uno a muchos con otras tablas, y así se hará referencia en las claves externas de otras tablas.

yo no estoy atado a una específica RDBMS y no estoy seguro si importa por el bien del argumento, pero digamos que prefiero trabajar con SQLite y MySQL.

¿Cuáles son los pros y los contras de utilizar una clave foránea compuesta en este caso? ¿Cual preferirías?

Respuesta

26

Encuentro que las claves primarias compuestas son dolorosas. Para cada tabla que desee unir a su tabla de "fuentes" deberá agregar el campo source_id y id_on_source.

Crearía una clave primaria de autoevaluo estándar en su tabla de fuentes y agregaría un índice único en las columnas source_id e id_on_source.

Esto le permite agregar simplemente el ID de la tabla de fuentes como una clave externa en otras tablas.

general I también han encontrado apoyo para las claves primarias compuestas dentro de muchos marcos y productos de herramientas para ser "parches" en el mejor e inexistente en otros

+0

Piensa en un PK compuesto para almacenar Era y Timestamp (1, 1970 ~ 2106) (2, 2106 ~ 2242). Debido a que INT8, INT16, INT32, INT64 son binarios y basados ​​en bits, entonces no tenemos el tamaño INT adecuado para el año 9999. INT no es suficiente y BIG INT es demasiado grande. – Alix

12

claves compuestas son difíciles de manejar y lento para unirse. Como está creando una tabla de resumen, use una clave sustituta (es decir, una columna de autoincremento/identidad). Deje sus columnas clave naturales allí.

Esto tiene muchos otros beneficios, también. Principalmente, si se fusiona con una empresa y tienen una de las mismas fuentes, pero con claves reutilizadas, usted se meterá en problemas si no son usando una clave sustituta.

Esta es la mejor práctica ampliamente reconocida en el almacenamiento de datos (una empresa mucho más grande que lo que está haciendo, pero que sigue siendo relevante), y por una buena razón. Los sustitutos proporcionan integridad de datos y combinaciones rápidas. Puede quemarse rápidamente con claves naturales, así que aléjese de ellos como un identificador y solo utilícelos en el proceso de importación.

+3

¿De qué problema estás hablando exactamente? Si tiene conflictos en una combinación, ¿no es probable que desee un error en lugar de datos duplicados? –

+2

@JeffDavis Exactamente, las claves sustitutas invitan a la redundancia AFAIK. – nottinhill

+0

¿Puedes explicar por qué las claves compuestas tardan en unirse? Estoy tratando de entender por qué no usaría claves compuestas en realidad. Si tengo una tabla que hace referencia a otra con una clave compuesta (A, B), en realidad no tengo que unirme a todo el pk. También podría escribir 'ON (a.A = another.A)', ¿verdad? Entonces, ¿qué hace que esto sea más lento? – displayname

1

Algunas personas recomiendan que utilice una ID global única (GUID): merge replication and transactional replication with updating subscriptions use uniqueidentifier columns to guarantee that rows are uniquely identified across multiple copies of the table. Si el valor es globalmente único cuando se crea, no es necesario que agregue el source_id para hacerlo único.


Aunque un uniqueid es una buena clave principal, acepto que por lo general es mejor utilizar una clave diferente, natural (no necesariamente único) como su índice agrupado. Por ejemplo, si un uniqueid es el PK que identifica a los empleados, es posible que desee que el índice agrupado sea el departamento (si sus declaraciones seleccionadas generalmente recuperan a todos los empleados dentro de un departamento determinado). Si desea utilizar un unqiqueid como índice agrupado, consulte la función NEWSEQUENTIALID(): esto crea valores secuenciales únicos, que (al ser secuenciales) tienen un mejor rendimiento de clúster.

+0

solo tenga cuidado (en SQL Server) ** NO ** para hacer que su clave principal GUID sea la clave agrupada de la tabla (que es, de manera predeterminada) - vea el excelente artículo de Kim Tripp sobre por qué no: http: // www. sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx –

+0

agregué a mi respuesta a la dirección ese comentario – ChrisW

+0

Con respecto al GUID: Si el requisito es solo tener un único id para cada registro, sí, esto funcionará. Pero si necesita saber cuál era la fuente, entonces debe publicar el ID de origen en el registro de todos modos, o tiene que tener una tabla de búsqueda en otro lugar (puaj), o tiene que buscar todas las fuentes posibles buscando ese GUID (double yuck) Si tiene que conservar el ID de origen de todos modos, un GUID no agrega ningún valor. – Jay

6

Creo que las claves compuestas crean un modelo de datos muy natural y descriptivo. Mi experiencia proviene de Oracle y no creo que haya ningún problema técnico al crear un PK compuesto. De hecho, cualquiera que analice el diccionario de datos comprenderá inmediatamente algo sobre la tabla. En su caso, sería obvio que cada source_id debe tener id_on_source único.

El uso de claves naturales a menudo crea un debate candente, pero las personas con las que trabajo como claves naturales desde una buena perspectiva del modelo de datos.

+1

sí, pero unir desde una tabla secundaria a una clave principal tiende a complicarse si tiene que unir dos, tres, cuatro condiciones, y aumenta la clave principal y, por lo tanto, todos sus índices. Puede parecer natural, pero en realidad, no es una buena idea tomar –

+1

punto. Usualmente encontrará que las entidades primarias tendrán una clave única generada por la BD. p.ej. Tabla de clientes con CustomerId. Generalmente son tablas secundarias relacionadas que tienen claves compuestas y la mayoría de ellas no tiene FK que las haga referencia. p.ej. si almacena el historial de los números de teléfono de los clientes, en una tabla Customer_contact_history las columnas CustomerId, phone, changedate pueden ser PK compuestas ya que estas 3 cosas son naturalmente únicas. – softveda

+0

Te doy una votación positiva porque estoy de acuerdo en principio. ¡Pero no creo que sea la mejor solución en este ejemplo en particular! – Jay

1

Al agregar una columna de ID adicional, tendrá que aplicar DOS restricciones de exclusividad en lugar de una.

Usar esa columna de ID adicional como clave externa en otras tablas de referencia, en lugar de la clave que se presenta de forma natural, hará que tenga que hacer MÁS uniones, es decir, en todos los casos donde necesite el ID de fuente original más ID_on_source junto con los datos de la tabla de referencia.

+0

¿Necesita exigir exclusividad en esta aplicación? Si obtiene los datos de estos otros sistemas, presumiblemente es su problema imponer la singularidad. Vuelve a lo que necesitas lograr. – Jay

+0

En cuanto a la unión extra: mantendría la fuente y id_on_source en la misma tabla, ya sea la clave principal o no. No veo ningún motivo aquí para tener una segunda tabla de búsqueda para hacer traducciones. Mantenlo todo junto. – Jay

8

Tiene un requisito empresarial que la combinación de esos dos atributos sea única. Por lo tanto, debe tener una restricción UNIQUE en esos dos atributos. Si llama a esa restricción UNIQUE "primaria" es realmente solo una preferencia, no tiene mucho impacto aparte de la documentación.

La única pregunta es si luego agrega una columna adicional y la marca UNIQUE. La única razón por la que puedo ver para hacerlo es el rendimiento, que es una razón legítima.

Personalmente, no me gusta el enfoque de convertir cada base de datos en esencialmente un gráfico, donde las columnas generadas son esencialmente punteros y usted está simplemente atravesando de uno a otro. Creo que eso elimina toda la grandeza de un sistema relacional. Si das un paso atrás y lo piensas, estás presentando un montón de columnas que no tienen ningún significado para tu negocio, en absoluto. Puede que le interese mi related blog post.

3

Casi la única vez que uso una clave primaria compuesta es cuando la parte de orden superior de la clave es la clave de otra tabla. Por ejemplo, podría crear una tabla OrderLineItem con una clave principal de OrderId + LineNumber. Como muchos accesos contra la tabla OrderLineItem serán "order order orderlineitem using (orderid)" o alguna variación de eso, esto a menudo es útil. También hace que sea fácil cuando se buscan los volcados de la base de datos para averiguar qué líneas de pedido están conectadas a qué orden.

Como han notado otros, las teclas compuestas son un problema en la mayoría de las otras circunstancias porque sus uniones tienen que involucrar a todas las piezas. Es más para escribir, lo que significa más posibilidades de errores, las consultas son más lentas, etc.

Las llaves de dos partes no están mal; Los hago con bastante frecuencia. Soy reacio a usar una clave de tres partes. Más de tres partes, yo diría que lo olviden.

En su ejemplo, sospecho que hay poco que ganar usando la clave compuesta. Solo invente un nuevo número de secuencia y permita que la fuente y la clave fuente sean atributos comunes.

2

Tuve problemas al utilizar muchas teclas compuestas, así que no lo recomendaría (más abajo), también descubrí que hay beneficios en una clave independiente/sustituta (en lugar de natural) cuando intento Revertir los errores del usuario. El problema era que a través de un conjunto de relaciones, una tabla se unía a dos tablas donde para cada fila parte del compuesto era la misma (esto era apropiado en la 3ra forma normal: una comparación entre dos partes de un padre). Desduplicaba esa parte de la relación compuesta en la tabla de unión (así que en lugar de parent1ID, other1ID, parent2ID, other2ID había parentID, other1ID, other2ID) pero ahora la relación no podía actualizar los cambios en la clave principal, porque intentaba hacerlo dos veces por cada ruta y falló en el medio.

Cuestiones relacionadas