Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » Mysql »

como puedo optimizar una tabla con mucho registros

Estas en el tema de como puedo optimizar una tabla con mucho registros en el foro de Mysql en Foros del Web. Hola resulta que tengo una tabla con 16M de registros la tabla esta indezada por el campo c_id la distribucion de datos esta en 4 ...
  #1 (permalink)  
Antiguo 09/09/2012, 09:50
 
Fecha de Ingreso: julio-2012
Mensajes: 25
Antigüedad: 11 años, 9 meses
Puntos: 3
como puedo optimizar una tabla con mucho registros

Hola resulta que tengo una tabla con 16M de registros la tabla esta indezada por el campo c_id

la distribucion de datos esta en 4 c_id que son (1,2,3,4)

si realizo una consulta de este tipo

Código SQL:
Ver original
  1. SELECT item1 FROM myTabla WHERE c_id = 4;

El resultado que obtengo es este
500000 rows in set (1.00 sec)

Le hago un EXPLAIN a la consulta para ver como mysql esta operando

Código SQL:
Ver original
  1. mysql> EXPLAIN SELECT item1 FROM myTabla WHERE cp_id = 4;
  2. +----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+
  3. | id | select_type | TABLE    | TYPE | possible_keys | KEY   | key_len | REF   | ROWS    | Extra |
  4. +----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+
  5. |  1 | SIMPLE      | myTabla  | REF  | INDEX         | INDEX | 2       | const | 1061072 |       |
  6. +----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+
Aquí veo que el msyql recorre 1061072 para poder recuperrar los 500.000

Mi pregunta es, esto es normal por la cantidad de registro que tiene la tabla si es normal entonces quesería lo mas ideal dividir la tabla o sea segregar los 500.000 registros de c_id = 4 y colocarlo en otra tabla aparte o ustedes entienden que tengo algun problema en como estoy optimizando mi consulta.

Se aceptan cualquier criticas, cualquier experiencia que hayan tenido cualquier cosas por favor no se cohiban en responder.

Saludos.
  #2 (permalink)  
Antiguo 09/09/2012, 10:14
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: como puedo optimizar una tabla con mucho registros

Por empezar, necesitaríamos ver la estructura de la tabla y un ejemplo de datos, para tener claro lo que tienes en ella.
Postea el CREATE TABLE y al menos el resultado de un
Código MySQL:
Ver original
  1. SELECT * FROM mytabla LIMT 20
como para ver el tipo de datos y su distribución de valores.
Luego veremos qué mejoras se pueden hacer, pero en principio lo que sucede es que ese indice tiene poca selectividad. El inconveniente es que no queda claro lo que quieres decir con esto:
Cita:
la distribucion de datos esta en 4 c_id que son (1,2,3,4)
Porque se campo pareciera ser una PK, pero no es el caso, o de lo contrario no tendrías el problema.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #3 (permalink)  
Antiguo 09/09/2012, 10:41
 
Fecha de Ingreso: julio-2012
Mensajes: 25
Antigüedad: 11 años, 9 meses
Puntos: 3
Respuesta: como puedo optimizar una tabla con mucho registros

Gracias gnzsoloyo por responder muy amable,

Código SQL:
Ver original
  1. mysql> SELECT item1, c_id FROM myTabla GROUP BY c_id  LIMIT 4;
  2. +---------+-------+------------+
  3. | item1   | c_id  | totalRow   |
  4. +---------+-------+------------+
  5. | 1201001 |     1 | 8000000    |
  6. | 1201002 |     2 | 7000000    |
  7. | 1201003 |     3 | 500000     |
  8. | 1201004 |     4 | 500000     |
  9. +---------+-------+------------+
  10. 4 ROWS IN SET (1 MIN 0.69 sec)
Si se fijan agrege una columna llamada totalRow que especifica la cantidad de item que tiene cada c_id esto es para aclarar mas el escenario

Código SQL:
Ver original
  1. CREATE TABLE  `myTabla` (
  2.   `c_id`  tinyInt UNSIGNED NOT NULL,
  3.   `item1` INT(7) UNSIGNED NOT NULL
  4.   KEY `Index` (`c_id`) USING BTREE
  5. ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;

Saludos!
  #4 (permalink)  
Antiguo 09/09/2012, 11:23
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: como puedo optimizar una tabla con mucho registros

La tabla está mal definida. Ese campo debería ser PRIMARY KEY y no INDEX. Son cosas completamente diferentes.
Código MySQL:
Ver original
  1. CREATE TABLE  `myTabla` (
  2.   `item1` int(7) UNSIGNED NOT NULL
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #5 (permalink)  
Antiguo 09/09/2012, 12:05
 
Fecha de Ingreso: julio-2012
Mensajes: 25
Antigüedad: 11 años, 9 meses
Puntos: 3
Respuesta: como puedo optimizar una tabla con mucho registros

El problema es que c_id tiene duplicidad de contenido es la naturaleza de esta tabla.
Código SQL:
Ver original
  1. mysql> SELECT Last_Status, Hora, Fecha, Item1, c_id FROM myTabla WHERE c_id = 1  LIMIT 4;
  2. +-------------+----------+------------+---------+-------+
  3. | Last_Status | Hora     | Fecha      | Item1   | c_id  |
  4. +-------------+----------+------------+---------+-------+
  5. |           3 | 10:10:00 | 2012-09-01 | 1201001 |     1 |
  6. |           2 | 11:30:20 | 2012-09-02 | 1202009 |     1 |
  7. |           5 | 12:20:10 | 2012-09-05 | 1201001 |     1 |
  8. |           3 | 13:10:40 | 2012-09-07 | 1206002 |     1 |
  9. +-------------+----------+------------+---------+-------+
  10. 4 ROWS IN SET (0.00 sec)
En esta tabla por su naturaleza no puedo utilizar llave primaria, esta tabla alberga informacion repetitivas es una tabla que guarda reportes del estado de los items el campo c_id lo utilizo para poder agrupar los items que tiene asignado y conocer su diferentes estados que tuvieron en un fecha y hora determinada.

En la consulta anterior agrupe algunos de los items que tiene el c_id = 1 en total existe 8,000,000 row que hacen referencia al c_id = 1 solo liste 4 a modo de ejemplo.

Espero que este un poco mas claro.

Saludos!
  #6 (permalink)  
Antiguo 10/09/2012, 07:35
Colaborador
 
Fecha de Ingreso: marzo-2008
Ubicación: Cáceres
Mensajes: 3.735
Antigüedad: 16 años
Puntos: 300
Respuesta: como puedo optimizar una tabla con mucho registros

Con el número de datos de que hablas y la selectividad que mencionas, si la fórmula que suele ofrecerse es la correcta:
(4/8000000)*100%
ya puedes sacar el valor y ver que los índices no sirven de nada ahí. Ahora bien, solucionar el problema es otra cosa y creo que dependerá de para qué uses realmente esos datos tú. Partitioning horizontal y vertical, o programación de operaciones cada vez que cambies un registro para no tener que recorrer esas tablas, pueden ser una solución. Solo puedo decirte esto, porque no tengo experiencia real en este tema...
  #7 (permalink)  
Antiguo 10/09/2012, 08:25
Avatar de antoniopol  
Fecha de Ingreso: agosto-2012
Ubicación: Valladolid
Mensajes: 114
Antigüedad: 11 años, 8 meses
Puntos: 21
Respuesta: como puedo optimizar una tabla con mucho registros

Los indices solo son válidos si el contenido es unico o se repite muy poco, en este caso como bien dicen los compañeros no es muy útil.
__________________
>> Blog de desarrollo web.
>> @antoniopol06 amante de la Web =D
  #8 (permalink)  
Antiguo 10/09/2012, 13:19
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: como puedo optimizar una tabla con mucho registros

El hecho de que tenga información parcialmente repetitiva no es óbice para que la tabla tenga PK. De hecho toda tabla debe tener obligatoriamente una PK, la uses o no en las consultas. supongo que eso lo tienes claro.
Tu problema es que la búsqueda la estás haciendo por un campo con muy baja selectividad, por tanto a MySQL evalúa que si la peor entrada del índice tiene alrededor del 50% de la longitud de la tabla, el índice se omite porque le llevaría menos tiempo hacer un FULL TABLE SCAN, que acceder al índice y después a la tabla.
En definitiva, para poder mejorar la performance no es suficiente usar ese campo como parámetro de indexación. Necesitas alguno más, que permita reducir la cantidad de entradas del índice y aumentar la selectividad.
Sin modificar la forma de indexación, y la cantidad de parámetros del WHERE, no es posible optimizar la consulta, tal y como la planteaste.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #9 (permalink)  
Antiguo 10/09/2012, 15:00
 
Fecha de Ingreso: julio-2012
Mensajes: 25
Antigüedad: 11 años, 9 meses
Puntos: 3
Respuesta: como puedo optimizar una tabla con mucho registros

Les agradezco mucho a cada uno de ustedes sus aportes.

Ok voy explicar un poco mas claro el escenario donde estoy teniendo el problema.
haber si me explico mejor.

Tengo 3 tablas.

tb_grupos
tb_items
tb_estatus.


Cada elemento de la tabla tb_grupos tiene asociado un conjunto de elementos de la tabla tb_items la cardinalidad es de 1:1 , cada item tienen un numero unico dentro del sistema.
por la naturaleza del software los items van cambiando de estatus en todo el trayecto del dia.
esos estatus junto con el numero de item la fecha y hora son almacenados en la tabla tb_estatus que es donde se llava el control de los mismo.

tb_estatus
Código SQL:
Ver original
  1. +-------------+----------+------------+---------+-------+
  2. | Last_Status | Hora * * | Fecha * * *| Item1 * | c_id *|
  3. +-------------+----------+------------+---------+-------+
  4. | * * * * * 3 | 10:10:00 | 2012-09-01 | 1201001 |     1 |
  5. +-------------+----------+------------+---------+-------+

anteriormente para obtener los estatus de los items por ejemplo del grupo 1 en un periodo de tiempo
tenia que hacer una consulta utilizando JOIN para unir las tablas tb_grupos, tb_items, tb_estatus .
eso lo hacia cuando solo tenia 500.000 registros me funcionaba pero ahora que tengo un escenario de 16M la antigua manera no me sirve,
puesto que he obtado por modificar un poco el diseño y agregarle el campo de grupo al que pertenece el item en la tabla tb_estatus, en este caso el campo c_id

de esta forma me evito tener que hacer un join con la tabla tb_grupos y tb_items y tambien trato de que mysql no tenga que hacer un full scan completo de la tabla para obtener 500.000 registros.

Actualmente solo tengo 4 grupos creados y 16M de estatus generado por parte de los items en general, la data esta desplegada de la siguiente forma.

Código SQL:
Ver original
  1. +-------+------------+
  2. | c_id *| totalRow * |
  3. +-------+------------+
  4. | * * 1 | 8000000 * *|
  5. | * * 2 | 7000000 * *|
  6. | * * 3 | 500000 * * |
  7. | * * 4 | 500000 * * |
  8. +---------+-------+--+

Como pueden notar el c_id = 4 tiene un total de 500.000 reportes que han notificado sus conjuntos de items.

yo suponia que si le decia a mysql que me devuelva los estatus pertenecientes al c_id = 4 mysql solo haria un scan por los 500.000 registros pero me he
dando cuenta que esto no es siempre asi, aplique un EXPLAIN Y obtuve el siguiente resultado

Código SQL:
Ver original
  1. mysql> EXPLAIN SELECT item1 FROM myTabla WHERE c_id = 4;
  2. +----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+
  3. | id | select_type | TABLE    | TYPE | possible_keys | KEY   | key_len | REF   | ROWS    | Extra |
  4. +----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+
  5. |  1 | SIMPLE      | myTabla  | REF  | INDEX         | INDEX | 2       | const | 1061072 |       |
  6. +----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+

Si se fijan mysql scaneo 1061072 para llegar a los 500.000 lo que realmente significa mas del doble.


La tabla de tb_estatus no tenia PK lo que hice fue crearle un PK en un campo autoincrementable y cree un orden para que del 1 al 500.000 solo le pertenezcan
al c_id = 4, nuevamente hice el test y sigo scaniando 1061072.

Por si le sirve trabajo con mysql 5.5 y en un servidor slave o sea que supongo que los indices no se afectan mucho cuando se hacen INSERT en el master.

Saludos!
  #10 (permalink)  
Antiguo 10/09/2012, 16:40
 
Fecha de Ingreso: julio-2012
Mensajes: 25
Antigüedad: 11 años, 9 meses
Puntos: 3
Respuesta: como puedo optimizar una tabla con mucho registros

Acabo de hacer una prueba de laboratorio borre y cree nuevamente el PK y ahora anda mejor
Código SQL:
Ver original
  1. mysql> SELECT SQL_NO_CACHE COUNT(c_id) FROM myTabla WHERE c_id = 2;
  2. +--------------+
  3. | COUNT(c_id) |
  4. +--------------+
  5. |     17563648 |
  6. +--------------+
  7. 1 ROW IN SET (5.64 sec)
Código SQL:
Ver original
  1. mysql> SELECT  SQL_NO_CACHE MIN(noRow) AS MIN,MAX(noRow) AS MAX FROM myTabla WHERE c_id = 2;
  2. +----------+----------+
  3. | MIN      | MAX      |
  4. +----------+----------+
  5. | 18022057 | 35585704 |
  6. +----------+----------+
  7. 1 ROW IN SET (8.36 sec)
Código SQL:
Ver original
  1. mysql> EXPLAIN SELECT SQL_NO_CACHE c_id FROM myTabla WHERE c_id = 2 AND (noRow BETWEEN 18022057 AND 35585704);
  2. +----+-------------+----------+------+-----------------+---------+---------+-------+----------+--------------------------+
  3. | id | select_type | TABLE    | TYPE | possible_keys   | KEY     | key_len | REF   | ROWS     | Extra                    |
  4. +----+-------------+----------+------+-----------------+---------+---------+-------+----------+--------------------------+
  5. |  1 | SIMPLE      | myTabla | REF  | PRIMARY,Index_2 | Index_2 | 2       | const | 17563767 | USING WHERE; USING INDEX |
  6. +----+-------------+----------+------+-----------------+---------+---------+-------+----------+--------------------------+
  7. 1 ROW IN SET (0.00 sec)
la PK es noRow, como ven estos resultados ?
se podria optimizar mas ?

Saludos!
  #11 (permalink)  
Antiguo 10/09/2012, 17:32
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: como puedo optimizar una tabla con mucho registros

Cita:
la PK es noRow, como ven estos resultados ?
Un espanto.
Cita:
se podria optimizar mas ?
Por supuesto que si. Pero tu pareces obsesionado en hacer la consulta con ese valor como único parámetro y de esa forma no podrás hacer consultas optimizadas.
¿No te paree que sería una buena idea que crearas un indice al mismo tiempo sobre más de un campo?
Si en lugar de hacer una consulta sobre ese único campo que tiene tan espantosa cardinalidad, pudieses hacerlo sobre más de uno, la consulta mejoraría muchísimo.
Si se pudiesen agregar rangos de tiempo, y crear un índice con clave (fecha, c_id) el resultado sería amplia mente superior.

Ahora bien, a mi me asaltan varias dudas.
Una de ellas es ¿para qué usas un conjunto de medio millón de registros? Porque no es posible que sea para leerlos, ya que eso implicaría leer aproximadamente 6.250 páginas de 80 líneas c/u... lo que francamente no creo que nadie haga.
¿Qué haces luego con esos datos? ¿Llevan algún proceso ulterior?
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)

Etiquetas: registros, select, sql, tabla, tipo, campos
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 14:06.