Ver Mensaje Individual
  #10 (permalink)  
Antiguo 04/12/2007, 06:23
Avatar de matanga
matanga
 
Fecha de Ingreso: octubre-2007
Ubicación: España
Mensajes: 1.091
Antigüedad: 16 años, 6 meses
Puntos: 85
Re: indices (avanzados)

Hola,

Estoy un poco fuera de mi area pero este thread se puso bueno.

A mi me gustaria separar las tareas en dos:

1. Buscar el ROWID de la fila en la base de datos.
2. Una vez completo el paso 1, obtener los datos de la fila.

El punto 1 es el que mas tiene que llevar horas de diseño y es el que mas nos va a afectar cuando falle, es decir, esta relacionado directamente con la cantidad de registros de la tabla y con las consultas SQL que hagamos para buscar datos.

Lo primero es saber que tipos de consultas se van a hacer sobre la tabla, por ejemplo

Código:
1. select * from usuarios where id = 100;
2. select * from usuarios where usuario = 'pepe';
3. select * from usuarios;
4. select * from usuarios where contraseña = md5(12345); ????
En principio lo logico para poder encontrar el ROWID es indexar el campo ID o el campo USUARIO, en mi opinion las consultas 1 y 2 son las mas comunes.

Ahora, una vez que tenemos el ROWID, la segunda tarea es, desde donde obtenemos los datos. Este segundo paso no tiene relacion con la cantidad de filas de la tabla, como ya tenemos el ROWID, no importa si la tabla tiene 1000000000 de registros, nosotros solo vamos a trabajar con 1 solo.

Hay dos opciones, o se los lee del indice o de la tabla, pero para que los lea del indice, hay que indexar todos los campos que contemplan la consulta SQL.

En este caso hay que hacer un indice compuesto con los campos ID, NOMBRE
Código:
select id, nombre from usuarios where id = 3;
En este caso hay que hacer un indice compuesto con los campos ID, NOMBRE, CONTRASEÑA
Código:
select id, nombre, contraseña where id = 3;
Un poco de ejemplos para ver como resuelve esto MySql.

Creo una tabla de usuarios y le cargo algunos registros.

Código:
mysql> create table t1 (id numeric, nombre varchar(30));
Query OK, 0 rows affected (0.08 sec)

mysql>
mysql>
mysql> insert into t1 values (1,'nombre1');
Query OK, 1 row affected (0.03 sec)

mysql> insert into t1 values (2,'nombre2');
Query OK, 1 row affected (0.02 sec)

mysql> insert into t1 values (3,'nombre3');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1 values (4,'nombre4');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t1 values (5,'nombre5');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1;
+------+---------+
| id   | nombre  |
+------+---------+
|    1 | nombre1 |
|    2 | nombre2 |
|    3 | nombre3 |
|    4 | nombre4 |
|    5 | nombre5 |
+------+---------+
5 rows in set (0.00 sec)
Creo un indice sobre la tabla en el campo ID y analizo la tabla para generar las estadisticas.

Código:
mysql> create unique index ind_t1_id on t1(id);
Query OK, 5 rows affected (0.06 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> analyze table t1;
+---------+---------+----------+----------+
| Table   | Op      | Msg_type | Msg_text |
+---------+---------+----------+----------+
| bugs.t1 | analyze | status   | OK       |
+---------+---------+----------+----------+
1 row in set (0.00 sec)
Ahora le pido el plan de ejecucion de las dos consultas, una obtiene los datos del indice y la otra de la tabla, esto lo pueden apreciar en el ultimo Texto, EXTRA

Código:
mysql> explain select id from t1 where id = 3;
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+-------------+
| id | select_type | table | type  | possible_keys | key       | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+-------------+
|  1 | SIMPLE      | t1    | const | ind_t1_id     | ind_t1_id | 6       | const |    1 | Using index |
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from t1 where id = 3;
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key       | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+-------+
|  1 | SIMPLE      | t1    | const | ind_t1_id     | ind_t1_id | 6       | const |    1 |       |
+----+-------------+-------+-------+---------------+-----------+---------+-------+------+-------+
1 row in set (0.00 sec)
Lo mas importante es que en las dos consultas se obtiene el ROWID a traves de un indice y no se hace un full-scan sobre la tabla, en esto es en lo que hay que gastar mas energias porque es lo que te va a afecar directamente cuando la tabla se haga grande.

Es practicamente imposoble de medir en tiempos la diferencia entre obtener los datos del indice y obtener los datos de la tabla.

En conclusion,

1. Con indexar el campo ID deberia ser suficiente, digo ID y no USUARIO porque seguro ID es el mas pequeño.
2. Si indexas los 3 campos, y la tabla realmente sera grande, entonces el indice tambien lo sera, y tendras que administrar el espacio de los dos objetos, desventaja mucho mayor que la velocidad de obtener los datos directamente del indice.

Para mas referencia esta este link

http://dev.mysql.com/doc/refman/5.0/en/explain.html


Saludos

Última edición por matanga; 04/12/2007 a las 06:53