Duda con estructura BBDD MySQL
3 seguidores
Imaginad una base de datos con 10 tablas y 1.000 registros en cada una de ellas. Todos esos registros son de un mismo cliente, el #1.
Al introducir datos de más clientes, hasta llegar a 1.000 por ejemplo, hay dos opciones, y esa es la duda, ¿que opción es mejor?:
a) Mantener las 10 tablas y meter todos los datos con un "id_cliente", con lo que quedaría:
10 tablas y 1.000.000 registros en cada tabla (1.000 registros por cliente x 1.000 clientes).
b) Separar los datos de cada cliente en tablas individuales:
10.000 tablas (10 tablas x 1.000 clientes) y 1.000 registros por tabla.
Kr0n
a) Sí.
b) Locura!
pepevi
1 millón no es nada en una tabla bien indexada (indizada es que me suena fatal :S).
Se encuentra una fila en 21 pasos.
2^(n-1) ~ 1000000
Deck1
Gracias por las respuestas.
Cuando escribí lo de las 20.000 tablas ya me di cuenta de que esa opción no era muy lógica.
Una última duda, esta vez un poco más "equilibrada" la comparación.
Una base de datos, con una o dos tablas, y 1.000.000 de registros por tabla y 1.000 clientes como antes:
a) 2 tablas y 1.000.000.000 registros por tabla
b) 2.000 tablas y 1.000.000 registros por tabla
Kr0n
Más que pensarlo como una cuestión numérica, como estás planteando los ejemplos, piénsalo como una cuestión de diseño relacional.
Es decir, piensa en qué concepto del mundo real representa cada tabla y como se relaciona con el resto de tablas de tu modelo.
Imagínate que en tus ejemplos estamos hablando de tablas de Productos por poner: ¿Qué tiene más sentido, tener una tabla por cada lista de productos que tenga un cliente o bien que en la misma tabla de Productos, un campo indique a que cliente esta asociado dicho producto?
Siguiendo con el ejemplo, un cliente puede tener varios productos y tu sistema puede tener varios clientes. Vale, pues la lógica te indica que vas a tener una entidad Clientes que represente la información de los clientes en el sistema y otra tabla Productos con la informacion de los productos que ha comprado un cliente, y como la relación es de Uno a Muchos (Un cliente tiene Muchos productos) pues la Foreign Key que relaciona ambas tablas irá en la tabla Productos (es decir que la tabla Productos tendrá un campo que asociará el producto con un cliente).
Si quieres o necesitas profundizar, en Mysql-Hispano tienen muchos artículos interesantes. Como este de principios de diseño o este de integridad referencial.
pepevi
Imagina que quieres buscar un registro en una tabla de mil millones de registros y los tienes ordenados por idCliente y dentro de eso idOperacion.
Si haces un índice primario con esos dos campos, por ese orden, (los índices no tienen que ir a un solo campo), la tabla se irá creando como si se tratase de una tabla para cada cliente.
Otra posibilidad es crear un índice idOperacion e indexar aparte idCliente. Tener un índice primario y otro "Non-clustered". No sé cuál sería más rápido de los dos pero todo es hacer pruebas.
Por cierto, estoy hablando de Sql Server. Supongo que en MySQL también habrá índices y podrás meter varios campos en uno. Si quieres que explique un poco mejor lo de los índices, dentro de lo que he podido aprender, te hago un tuto-post.
Kr0n
pepevi
Si quieres que explique un poco mejor lo de los índices, dentro de lo que he podido aprender, te hago un tuto-post.
Pues no se Deck1, pero yo soy todo orejas ;)
pepevi
ok!
Hay que imaginar una tabla como una lista de punteros a registros. Un registro sería un puntero a cada dato (uno por columna).
Un índice es una tabla "oculta" que contiene una lista de punteros a la tabla original pero en otro orden.
[Ejemplo1]
Imaginemos una tabla con los siguientes campos:
- nombre
- apellido
Y queremos buscar todos los "García".
<code>
SELECT nombre, apellido FROM Users WHERE apellido = 'García';</code>
El motor de BD tendrá que ir registro por registro buscando cuáles devolver.
1 millón de registros = 1 millón de búsquedas
[ejemplo2]
Tenemos indexado el campo apellido. Es decir, hay por algún lado una lista de punteros a los registros ordenado según el apellido en orden alfabético.
<code>SELECT nombre, apellido FROM Users WHERE apellido = 'García';</code>
En vez de usar nuestra tabla original, el motor de base de datos deduce que va a ir más rápido si usa el índice que hay creado para apellido
Ahora lo único que tiene que hacer el motor es buscar el primer García seguir devolviendo los registros contiguos hasta que apellido sea distinto de García.
Para la búsqueda del primer García cada motor de base de datos tendrá sus algoritmos ultra-rápidos y ultra-complejos así que ni idea de cuánto tardará, pero desde luego mucho menos que en el primer ejemplo!
[Ejemplo3]
Vamos a hacer algo que casi todas las tablas deben tener, un índice primario único (id) que por comodidad vamos a poner autoincremental. Es decir, cada vez que se añada un registro a la tabla este índice se creará automáticamente y será del valor del último registro + 1. Y, algo muy importante, es único. No hay dos registros con el mismo índice.
Si estamos en una web editando un perfil de usuario, por ejemplo, y hacemos una modificación y lo queremos guardar, mandamos el siguiente comando:
<code>UPDATE Usuarios SET nombre = 'aitor', apellido = 'tilla' WHERE idUsuario = 162;</code>
Sólo habrá que buscar el registro 162, que al estar ordenado es fácil y como es un índice único el motor sabe que sólo tiene que actualizar uno.
La búsqueda del registro número 162 sí que la puedo explicar: Si tenemos 1000 registros se coge el 500, de ahí el 250, de ahí el 125, de ahí el 187, el 155, el 170, y el 162. Si no lo habéis pillado da igual xDD
El número de pasos máximo es 2^(n-1) ~ número de registros.
2^10 = 1024. Para 1024 registros necesitaríamos, como mucho, 11 pasos.
2^20 = 1048576. Para 1048576 registros sólo necesitamos 21 pasos.
[Disclaimer]Todo lo que sé lo he aprendido a la fuerza. Es decir, me pasaron una enorme base de datos en SQL Server en el curro y he tenido que aprender qué era cada cosa, por lo que probablemente algún concepto esté equivocado.
Voy a desayunar. Ahora termino xD
pepevi
Índice primario (Clustered): Es el índice por el que se rige la tabla original. La propia tabla se irá creando de acuerdo a éste índice. Es decir: Al insertar un registro no se va a poner el último, se pondrá donde le toque según el índice.
Índice Non-Clustered: Este crea una tabla de punteros auxiliar, se usa cuando se necesite.
Índice Único: Asegura que no habrá dos registros con el mismo valor en los campos indexados. Dará un error al intentar hacerlo. Muy útil para asegurarnos de que la tabla tiene consistencia.
Índices de múltiples campos: Puedes ordenar una tabla por un campo, o por varios.
Id: Campo útil, normalmente primario, único y autoincremental que se usa en la mayoría de las tablas para mejorar las búsquedas.
Sobre los índices de múltiples campos, son muy útiles en algunos casos:
[ejemplo4]
En una tabla de Links que relacione por ejemplo Usuarios con Proyectos. Esta tabla define qué usuarios tienen acceso a proyectos. Puede haber un proyecto con varios usuarios y un usuario con varios proyectos:
Campos:
- idUsuario
- idProyecto
- Rango
1. Para sacar el rango (usuario, administrador...) que tiene un usuario en un proyecto podríamos crear un índice con dos campos: idUsuario e idProyecto, por este orden. Además, podemos hacerlo único ya que no tiene sentido que se repitan registros con estos dos campos iguales (ser usuario y administrador a la vez no tiene mucho sentido en este caso).
<code>SELECT Rango FROM LinkUsuariosProyectos WHERE idUsuario = 2 and idProyecto = 522;</code>
Con un sólo índice encontramos de la forma más rápida el rango.
<code>Usuario Proyecto Rango
1 522 1
1 523 2
1 524 2
2 250 1
2 522 2
2 524 1
3 525 2</code>
Así estaría ordenada la tabla. En esta tabla yo no pondría campo id, ya que el par usuario-proyecto es un índice perfecto.
[Ejemplo5]
Queremos insertar una nueva línea en la tabla.
<code>INSERT INTO LinkUsuariosProyectos (idUsuario, idProyecto, Rango) VALUES (2, 523, 1)</code>
La tabla quedaría así:
<code>Usuario Proyecto Rango
1 522 1
1 523 2
1 524 2
2 250 1
2 522 2
2 523 1 ---- esta es la nueva
2 524 1
3 525 2
</code>
NOTA: El uso de índices hace que Insertar registros sea mucho más lento. Ojo con no abusar de ellos!
[ejemplo6]
Queremos sacar una lista de usuarios que pertenecen a un proyecto.
<code>SELECT idUsuario, Rango FROM LinkUsuariosProyectos WHERE idProyecto = 523;</code>
Para esto podemos poner otro índice en la tabla, coexistiendo con el de idUsuario-idProyecto, que indexe sólo idProyecto. El motor de SQL vería la tabla de esta forma:
<code>Usuario Proyecto Rango
2 250 1
1 522 1
2 522 2
1 523 2
2 523 1
1 524 2
2 524 1
3 525 2</code>
Ahora al insertar un nuevo registro el motor de BD tendrá que calcular dónde insertarlo en la tabla original y dónde insertarlo en el segundo índice non-clustered que hemos hecho. Doble de trabajo.
Kr0n
Ole, gracias por el tutopost! ;)
Deck1
guau, mil gracias!