en: Sin categoría
Si trabajas habitualmente con MySQL probablemente habrás escuchado que MySql no es la elección acertada para manejar tablas con mas de 1,000.000 de registros.
Pero entonces porque MySql es el motor de compañías como Google, Yahoo o Technorati, además estas compañías manejan algunos cientos de millones de registros y consiguen un gran rendimiento.
El motivo de este gran rendimiento es que estas tablas que tienen cientos de millones de registros están diseñadas y entendidas para trabajar con MySql, si diseñamos considerando lo que puede y no puede hacer el motor de base de datos probablemente consigamos un buen rendimiento, cualquier sistema de administración de Bases de Datos es distinto con respecto a los otros, lo que funciona bien y es eficaz en Oracle ó PostgreSQL no debe ser lo que mayor rendimiento ofrezca en Mysql.
Por ello para trabajar con tablas muy grandes debemos tener en cuenta tres claves: Buffers, Índices y Consultas.
Un buffer es una ubicación de la memoria reservada para el almacenamiento temporal de información digital.
La primera cosa que deberíamos tener muy clara es el hecho de que hay una gran diferencia entre “Datos que están en memoria” y “Datos que no están en memoria”.
Pongamos que comenzamos con un tamaño de memoria y notamos un descenso gradual del rendimiento porque la base de datos está creciendo, la solución sería asegurarnos que tenemos memoria suficiente para el volumen de datos que estamos utilizando.
Los índices son usados para encontrar rápidamente los registros que tengan un determinado valor en alguna de sus columnas. Sin un índice, MySql tiene que iniciar una búsqueda por el primer registro y leer toda la tabla para encontrar los registros relevantes.
Un error común es pensar que los índices no afectan en tablas con poco volumen de datos, aún en tablas pequeñas (1.000 registros) es por lo menos 100 veces más rápido leer datos utilizando un índice, sin este índice estaríamos haciendo una lectura secuencial.
Por lo tanto queda claro que los índices son realmente eficaces para acelerar el acceso a datos.
Cuando MySql encuentra un índice en una columna lo utiliza en lugar de hacer un escaneo completo de la tabla (leer todos los registros de la tabla de manera secuencial). Esto reduce los tiempos de CPU y las operaciones de “lectura/escritura en disco”.
Para verlo lo mejor es explicarlo con datos, comenzamos con una tabla que tiene 100 Bytes por registro y suponiendo que tenemos 100MB/segundo de velocidad de lectura por lo que calculando llegamos a la conclusión de que podemos conseguir 1,000.000 de registros por segundo (Tablas tipo MyISAM).
En este ejemplo vamos a hacer lo siguiente, tenemos una tabla con 30,000.000 de registros con una columna que tiene valores comprendidos entre el 1 y el 10.000, en esta prueba vamos a ver la diferencia de tiempos entre “Escaneo total de la tabla” y “Escaneo de un rango de valores de la tabla (entre 1 y 100)”.
SQL:
mysql> SELECT count(pad) FROM large;
+------------+
| count(pad) |
+------------+
| 31457280 |
+------------+
1 row IN SET (4 min 58.63 sec)
mysql> SELECT count(pad) FROM large WHERE val BETWEEN 1 AND 100;
+------------+
| count(pad) |
+------------+
| 314008 |
+------------+
1 row IN SET (29 min 53.01 sec)
Se puede ver que el resultado es contradictorio, ha tardado 5 minutos en contar 30,000.000 de registros y 30 minutos en contar el 1% (300.000).
Hay muchas maneras de optimizar este tipo de consultas, por ejemplo ordenando primero los valores y hacer la búsqueda sobre los registros ya ordenados, esta solución reduciría el tiempo de ejecución de la consulta y el resultado sería el mismo.
El uso de índices se antoja esencial en este tipo de ejemplos en los que tenemos grandes cantidades de datos en nuestras tablas, la mejora en la obtención de datos será muy significativa.
La optimización de las consultas podría ser el punto más extenso de los tres por la gran variedad de posibilidades que tenemos a la hora de optimizar consultas.
Uno de los pasos más importantes a la hora de optimizar nuestras consultas de MySql es identificar cuáles son las que están causando problemas.
Normalmente si tomamos las 10 consultas más lentas y las optimizamos de manera apropiada obtendremos un notable aumento en el rendimiento.
Vamos a ver cómo podemos identificar estas consultas:
Activar el ‘log’ de mysql para consultas lentas
El primer paso será asegurarnos que nuestro servidor tiene activado el log que nos mostrará aquellas consultas más lentas.
Chequeemos si el servidor MySql tiene el log activo:
mysqladmin var |grep log_slow_queries | log_slow_queries | OFF |
Si log_slow_queries esta en ‘ON’ ya tenemos el log activo, por defecto esta opción suele estar desactivada en caso de no tener log_slow_queries definido en la configuración del servidor tambien estará desactivado.
La variable long_query_time (Por defecto 1) define a partir de donde se tiene que considerar una consulta como lenta. El valor 1 está expresado en segundos y determina que toda consulta que exceda ese tiempo es considerada como tal.
Con esto ya estamos listos para activar el mysql slow query log. Debemos de dirigirnos al fichero de configuración (/etc/my.cnf RHEL/Centos o /etc/mysql/my.cnf en Debian, etc.), y en la sección mysqld añadiremos:
[mysqld]
long_query_time = 1
log-slow-queries = /var/log/mysql/mysql-slow.log
Está configuración añadirá al log todas aquellas consultas que sobrepasen un segundo en el archivo /var/log/mysql/mysql-slow.log.
Obviamente es tu decisión determinar cual es el valor para long_query_time.
Analizar el mysql slow queries log
Después de activar el “mysql slow queries log” debemos analizar los datos devueltos, aquí os dejo una serie de detalles que os ayudarán a comprender este archivo:
* Time: Cuánto tardó en ejecutarse la consulta
* Rows: Cuántos registros fueron servidos por el servidor
* Host: Cual fué el host que ejecutó la consulta
* La consulta MySql
Esta información nos será suficiente para determinar qué consultas deben ser optimizadas, cómo se explica al principio de este apartado hay multitud de maneras para optimizar las consultas.
MySql nos ofrece una pequeña utilidad que nos ayuda a analizar estos datos: The Slow Query Log
Por ejemplo, si una columna contiene fechas y tiene varios valores diferentes, un índice diferenciará las filas fácilmente, sin embargo, no le ayudará tanto si se utiliza en una columna para registrar el valores como verdadero,falso y que contiene sólo los dos valores “V” y “F” (cualquiera que sea que busque, tomará casi la mitad de las filas).
Para terminar recordar el principio de la entrada… puedes conseguir que MySQL rinda a buen rendimiento con grandes cantidades de datos pero para ello debes tener en cuenta sus limitaciones y saber cuales son las características que ofrecen mejor rendimiento.
12 Respuestas a ¿Porqué MySQL es lento con grandes tablas?
Richard
16 de Octubre de 2008 a las 8:29 am
Tengo 5 millones de registros en una tabla con solo 2 campos (id, valor) y estoy tratando de eliminar valores duplicados (emails), pero MySQL demora mucho en ejexutar la siguiente consulta:
INSERT INTO contactos_temp (id_usuario, email)
SELECT c.id_usuario, c.email
FROM contactos AS c
WHERE c.id_contacto > 0 AND c.id_contacto < = 1000000
GROUP BY c.email ASC
Esa consulta solo me trata 1 millón de registros, pero me tarda mas de 1 minuto :S
Si lo hago con 1.5 Millones me tarda: 245.7058 seg
Si lo hago con 2 millones no termina nunca
Mierda!! :S Vaya lentitud...
Pregunta: ¿Obtendría mejores resultados si lo hago con otro sistema gestor de base de datos?
http://cleptomano.com/musica/ < < Música Online y mas
Lithium
16 de Octubre de 2008 a las 10:41 am
Hola Richard, tengo una base de datos en mysql no son tanton resgistros como los tuyos, son cerca de 1 un millon y un poquito mas, no está nada lento, tal vez podrías intentar hacer tu query diferente, algo así como esto…
INSERT INTO contactos_temp (id_usuario, email)
values (SELECT contactos.id_usuario,contactos.email
from contactos
WHERE contactos.id_contacto > 0 AND contactos.id_contacto <= 1000000
GROUP BY contactos.email ASC )
igual y puede que te ahórre un poco de tiempo en cada instrucción…
espero te sirva
slds,
Lithium
Jorge Guerrero
4 de Septiembre de 2008 a las 9:55 am
MySql tiene problemas con las consultas almacenadas, cuando se ejecuta la misma consulta almacenada 2 veces se guinda el servidor y se cae el servicio, creo que hay un problema con la cache para consultas almacenadas. De hecho he agregado la instrucción sql_no_cache para omitir ese error. esta consulta tiene varias tablas inmersas, además estan indexados los campos necesarios. alguien podria decirme que problemas tienen las consultas o vistas almacenadas con respecto a la cache?
Anónimo
19 de Junio de 2008 a las 10:59 am
Oh rayos!!!!
Fernando
28 de Septiembre de 2008 a las 5:12 pm
Me gusta el material ya que da un gran primer paso, asiendo se saber que el uso de los indices es fundamental en las busquedas. Pero que paso si tengo 1 billon de registros en una tabla y 1 millon en otra, donde tengo que cruzar las tabalas y ordenar alfabeticamente la informacion. Como puedo optimizar esto, no es posible dejarlo ordenado ya que esto depende de varias variables que el usuario elija por ende. Existe alguna otra solucion fuera de los indices para acelerar nuestras busquedas.
jairojc
24 de Julio de 2008 a las 5:01 pm
Excelente material, te felicito, he estado buscando buenas razones para elegir entre Mysql y Postgre, pero tengo entendido que aunque Postgre sea mas robusto e idoneo para grandes bases de datos, Mysql es mas popular y cuenta con mas documentacion y haciendo las cosas bien con Mysql se puede lograr buenos resultados.
carlos
17 de Junio de 2008 a las 11:30 pm
si la montaña viene ati………. uye ke es un derrumbe
chino fun
28 de Noviembre de 2009 a las 9:41 pm
tengo un problema con una base de datos migrada de sql server, pero al migrarla se perdieron
los indices y creo que esto a perjudicado la velocidad para las consultas. alguien tiene alguna solucion. pero no bedo crear indices.
att: chino fun
BJMM
5 de Febrero de 2010 a las 5:45 pm
SELECT deposito_02.codigo, deposito_02.desc,deposito_02.cntex FROM deposito_02 WHERE NOT EXISTS(SELECT deposito1.codigo FROM deposito1 WHERE deposito_02.codigo = deposito1.codigo) NECESITO OPTIMIZAR ESTA CONSULTA.. SE TARDA CASI 2 MIN Y APENAS SON 12.000 REGISTROS…
Pastor Luis Cordero
8 de Febrero de 2010 a las 6:26 am
Bueno, me parece muy interante este arituculo, pero para aquellos que trabajan con MySQL (mi caso) y desean desarrollar proyectos de gran envergadura y no conocen manejar dicha herramientas como ORACLE… Creo que despues de hecha dicha herramienta es necesario invertir tioempo y migrar tus tablas al nuevo sistema de manejador de datos!!!
Willy
18 de Febrero de 2010 a las 12:30 am
Estimado Pastor Luis Cordero, el aritu-culo que Ud menciona en su primer frase, nada tiene que ver con lo que esta aqui. Podria haber dejado algun comentario con mas trascendencia no?.
rut
9 de Marzo de 2010 a las 1:15 am
¿cómo saber cuánta memoria utiliza una tabla de MySQL? y cómo saber cuánta memoria se necesita para una “operación sencilla” como SELECT?