Vamos a hacer una aclaración centrándonos en qué es una clave primaria: Es un
campo o
conjunto de campos que identifica unívocamente un registro en una tabla.
Ahora bien, n
i en el paradigma relacional, ni en ninguna regla especifica que una PK deba ser numérica ni autoincremental. Sólo dice que debe ser
única y no nula.
Esto significa que una PK se crea sobre la base de campos de cuyos valores depende el resto, o que considerados en conjunto se puede establecer que no existen repeticiones en ningún caso.
Dicho esto, vamos a hacer una aclaración, extendiendo el tema: Es muy habitual que por facilidad de programación, se creen PK basados en campos autoincrementales. Son sencillos, fáciles de entender y más fáciles aún de programar... Pero son conflictivos.
Cuando usas este tipo de campos no se percibe que presentan problemas graves cuando se desea realizar consolidaciones de datos provenientes de diferentes bases. En estos casos, cada base instalada es un espejo en cuanto a su estructura, pero no en cuanto a sus datos; diferentes sucursales de una empresa que trabajen con bases aisladas una de otra, pueden tener el mismo número de cliente asignado a personas diferentes. ¿Cómo harías para diferenciarlos, si la PK coincide?
¿Se entiende el problema?
Son inconvenientes que surgen de expandir las bases de datos, o simplemente por crecimiento de la actividad comercial. En esos casos (mucho más habituales de lo que esperas), ese modelo de PK no sirve.
Por eso se necesita volver atrás y replantear la forma deu sar la PK... sólo que cuando una base está en producción no puedes hacer modificaciones estructurales de ese tipo sin tener enormes problemas de migración... que la Gerencia no va a estar contenta de tener que realizar.
Yendo a tu problema, la solución consiste en que debes establecer la clave candidata para cada tabla omitiendo las PK numéricas... es decir, volver atrás y ajustarte al paradigma sin "fabricar" claves. Simplemente analizando bien cada tabla.
En tu caso, describes las tablas implicadas de esta forma:
Cita: tblPlan (IDplan-PK-, NombrePlan-numeric-)
tblCarrera (IDcarrera-PK-, Nombre, IDplan-FK-)
tblMateria (IDmateria-PK-, NombreMateria, CursoMateria ,IDCarrera-FK-, IDPlan-FK-)
Lo que a primera instancia puede hacerse es no usar un campo numérico para identificar las tres tablas, sino usar uno que pueda identificar incluso hasta la institución. Y aunque no te parezca es sencillo: Un plan de estudios, una carrera del mismo y hasta una materia ya tienen una identidad dada por la autoridad que supervisa las instituciones educativas. Con eso sería suficiente para comenzar. Es posible incluso que esos identificadores no sean numéricos sino alfanumericos.
TE doy un ejemplo basado en tu propio modelo:
"UM2002FCIT007CM2004A" componen la clave de una materia que cursé al inicio de la carrera. Esa clave identifica incluso el horario en que la cursé y en qué grupo y con qué docente lo hice. Obviamente no es una clave que pueda repetirse.
Respondiendo a tus preguntas:
Cita: ¿Vale la pena armar ID de esa forma?
Si. La precisión, integración y consolidación de datos es mayor.
Cita: ¿Estaba bién armada anteriormente la tabla?
Técnicamente si, pero puedes tener problemas de consolidación de datos a futuro.
Cita: ¿Un ID de 9 0 10 digitos no es "malo"?
Es irrrelevante. Un campo numérico no se almacena como cifras sino como binarios, por lo que poner un número de 10 cifras o uno de 20 sólo se diferencia en 4 bytes (4 bytes contra 8).
Cita: Y las consultas, por ejemplo; obtener todas las materia del plan "2000"
Para mi seria facilisimo asi SELECT nombre FROM Materia WHERE id_plan=2000
Pero de con esta forma quitaria el idplan y tendria que buscar el 2000 en el idmateria y lo veo mucho mas complicado tampoco se si vale la pena.
¿Y crees que a nivel de consultas ese cambio representa una diferencia de performance?
Absolutamente ninguna. Vuelve a leer lo que dices... ¿Qué diferencia puede haber en hacer
Código SQL:
Ver originalSELECT nombre FROM Materia WHERE id_plan=2000;
o hacer?:
Código SQL:
Ver originalSELECT nombre FROM Materia WHERE idplan=8;
La diferencia es que el 8 no significa nada fuera de contexto, pero el 2000 si, si dices que quieres saber cuáles son los nombres de materias dictados en el año 2000.
Espero que tanto escrito sirva de algo...