MySQL: Analizando la performance de un SELECT

Me encontré con la necesidad de saber con exactitud cuánto demora un SELECT de una fila cuando el campo que buscamos no es un índice, o si es un índice secundario o uno primario.

Para explicar mejor la situación, propongo el siguiente ejemplo:

Tenemos la siguiente Tabla de Usuarios:

Id Name UserName Telephone Notes

 

La configuración que primero se nos ocurre es que el campo “Id” sea un índice primario, pero qué sucede si por alguna razón, tenemos que hacer siempre un SELECT donde en el WHERE se use con la columna UserName, por ejemplo, si tenemos que loguear al usuario y el dato que tenemos es el username, la consulta sería:

SELECT * FROM Users WHERE UserName='pepe';

En cualquier sistema, hasta en un servidor con escasos recursos, esta consulta no tarda mucho y poco importa si tarda unos milisegundos más o menos…  pero en ciertas ocasiones, con tablas de miles de registros,  dependiendo del entorno,  los milisegundos comienzan a tomar importancia, sobre todo si no tenemos mucho poder de procesamiento, el timing comienza a ser de mucha importancia.

Las bases de datos actuales, para resumirlo de una forma brutal y básica, guardan la información en estructuras de datos ordenadas (árboles avanzados) por índices, lo cual nos hace pensar que si buscamos por el campo “Id” es más rápido que si buscamos por el campo “UserName” ya que el campo “Id” está indexado.

Qué podemos hacer entonces??

Hagamos que UserName sea un índice!!!  Muy bonito, pero, cuando la base de datos busca, comparar un INTEGER (“Id”) es muchísimo más rápido que comparar un VARCHAR (“UserName”) de unos 20 caracteres de longitud, por lo tanto, cualquier operación en la tabla se vuelve un poco más lenta…

Entonces, que conviene más?  Usar un índice que haga la tabla más lenta en general, pero que devuelva una fila mucho más rápido? o usar un índice ágil, pero luego tendremos demoras al buscar una sola fila por otro campo?

La respuesta a esta última pregunta, depende un 100% del entorno del sistema en el que estemos…
En un sistema con pocos usuarios, podría no ser un inconveniente, pero cuando tenemos un servidor con escasos recursos, como por ejemplo la Raspberry Pi o similares y en nuestra aplicación una diferencia de milisegundos importa, se convierte en un inconveniente.

Se me ocurrieron algunas opciones para medir el rendimiento y realizar algunos benchmarks de MySQL corriendo con bajos recursos…

  • Comparar los resultados usando:

    • a)  El campo Id como Índice Primario y el resto campos comunes. (Situación normal)
    • b)  El campo Id como Índice Primario y el campo UserName como Índice Secundario
    • c)  El campo UserName como Índice Primario y el campo Id como Índice Secundario
  • Comparar el comportamiento de las configuraciones anteriores con distintas cantidades de registros:

    • a)  100 (cien) registros
    • b)  1000 (mil) registros
    • c)  10000 (diez mil) registros
    • d)  100000 (cien mil) registros
    • f )  1000000 (un millón) de registros
  • Ya que estamos haciendo benchmarks, comparemos los resultados anteriores con los dos motores más populares de MySQL:

    • a)  MyISAM
    • b)  InnoDB

Cómo hago estos benchmarks???

Para ello, escribí unas pocas lineas en PHP, que me permitieron llenar una BD de pruebas con información aleatoria y precisa para las pruebas…  si, en total generé más de 6.500.00 filas! casi 1GB de registros aleatorios. (demoró varios minutos)
Por si a alguien le interesa, al final del post les dejo la descarga del archivo PHP utilizado para generar los datos aleatorios, la estructura de la base de datos sin registros y la bd llena de datos.

Condiciones de las pruebas:

  • Las consultas se hacen en PhpMyAdmin.
  • Se busca un registro a la mitad del total de la tabla.
  • El tiempo es obtenido de PhpMyAdmin.
  • El servidor MySQL corre en una Raspberry Pi.
  • El sistema operativo es Raspbian ‘Wheezy’.
  • Las configuraciones de Apache/PHP/MySQL son las que vienen por defecto al instalarlos.
  • El cache MySQL es reseteado antes de cada prueba.
  • El campo UserName es un VARCHAR de 25 caracteres.
Ejemplo de consultas:

Basta de palabras!!!   quiero ver los números!

Todos los valores de tiempos están expresados en mS (milisegundos).

Aquí tenemos dos tablas, una con los resultados de MyISAM y otra con los de InnoDB. En ambos casos comparamos las tres configuraciones de índices mencionadas anteriormente (a, b, c) en distintas cantidades de registros. Primero buscando por el campo ID y luego por el campo UserName.

MyISAM

 ID Indice PrimarioUserName Índice SecundarioUserName Índice Primario
WHERE->Id='x'UserName='x'Id='x'UserName='x'Id='x'UserName='x'
1003.74.43.84.43.93.8
1.0003.710.53.84.54.14.0
10.0003.776.13.94.54.24.1
100.0004.2789.14.14.84.34.2
1.000.0005.28158.85.15.46.14.8

InnoDB

 ID Indice PrimarioUserName Índice SecundarioUserName Índice Primario
WHERE->Id='x'UserName='x'Id='x'UserName='x'Id='x'UserName='x'
1004.37.04.45.04.23.7
1.0004.435.44.45.04.43.9
10.0004.6312.24.55.14.64.3
100.0004.62802.84.65.24.74.6
1.000.0007.035883.88.09.45.04.8

Resultados:

A primera vista, podemos notar la diferencia entre InnoDB y MyISAM en cuanto a la performance de los SELECTs.  Si tomamos como referencia las primer columna, donde ID es un Índice Primario, en InnoDB buscar un indice en 1.000.000 de registros, es un 35% más lento, pero si buscamos un registro no indexado, InnoDB es un 440% más lento que MyISAM.

Entonces, descartamos InnoDB para el resto de las comparaciones.

Evidentemente, buscar un registro que no es un índice, en un millón de filas, demora 8158.8 milisegundos, eso es es más de 8 segundos!!!  De hecho en 10.000 filas, demora casi 100 milisegundos, lo cual, en algunos casos, puede ocasionar problemas. Obviamente y como podíamos imaginar, si el tiempo es clave, ésta es la peor configuración.

Nos quedan dos opciones, utilizar el campo UserName como un indice secundario, o como un indice primario.

Como se puede ver en la tabla, si buscamos la mejor velocidad, nos conviene hacerlo un índice primario, pero en contra, la busqueda por ‘Id’ demora un par de milisegundos más.

Conclusión Final:

Como conclusión final, voy a elegir la configuración de “UserName como índice secundario“.  Porqué? Porque en promedio, parece tener los mejores tiempos, ningun tiempo supera los 6ms, sin importar si es índice primario o secundario. Realmente, muy buenos timings.

¿Qué es una VPS?

VPS, o Virtual Private Server, en español significa, Servidor Privado Virtual.

Que es una VPS

¿Qué es una VPS?

Una VPS, es un servidor virtual, que corre en un servidor físico que a su vez también alberga otras VPS. Cada VPS esta completamente aislada de las demás, tanto como de espacio en disco, como en uso del CPU. El manejo de la RAM en una VPS puede ser un poco mas complejo…  lo explico mas adelante en este post.

Una VPS es un paso intermedio, entre un hosting comun, y un servidor dedicado, hay mucha variedad de VPS, la mayor ventaja es que son completamente upgradeables es decir, que en la medida que el servidor fisico lo soporte, podemos aumentar la RAM, la velocidad del CPU, o la velocidad del puerto ethernet, con un par de clicks, instantaneamente.

Otra ventaja con respecto a un hosting compartido comun, es que en el 99% de los casos, NO dependemos de otros usuarios y somos completamente responsables de el uptime del server, ya que si una VPS está usando el CPU al 100%, ésto no afecta a las otras VPS.

Otra ventaja, es la cantidad de sistemas operativos que hay para elegir, también, con solo dos clicks, podemos elegir que distro de linux usaremos, e inclusive versiones de windows server.

 

Sistemas Operativos

¿Cómo elegir una VPS?

Hay dos tipos de VPS, Managed, y Unmanaged, cada una tiene sus ventajas, que explicare ahora, pero  un gran porcentaje de la desicion se basa en el conocimiento de linux (o windows server) que tengamos.

Ventajas de una VPS “Managed“:

  • No necesitas tener conocimientos de servidores.
  • Puedes tener tu hosting online en pocos minutos.
  • Por lo general, el soporte tecnico es mejor que en las Unmanaged.

 

Desventajas de una VPS “Managed“:
  • No tienes acceso al 100% de tu VPS.
  • Dependes del software que te instalen.
  • El precio.

 

Antes de pasar a las VPS “Unmanaged” aclaremos el tema del precio. En general, las “Managed” arrancan en 15 dolares al mes, mientras que “Unmanaged” hay desde 3 dolares al mes.

 

Ventajas de una VPS “Unmanaged“:
  • Acceso al 100% a la VPS.
  • Podemos elegir que programas instalar, y cuales no.
  • El precio.

 

Desventajas de una VPS “Unmanaged“:
  • Necesitas tener conocimientos de Linux o Windows Server.
  • Poco soporte técnico.

 

RAM

Como dije anteriormente, la decisión entre una VPS Managed y una UnManaged, pasa por tus conocimientos de linux.
Cuando ya tengas decidido que tipo de VPS deseas tener, el factor mas importante para la eleccion del plan de VPS, será la memoria RAM.

 

Aqui, tambien tenemos dos puntos a considerar:
  • RAM Dedicada
  • Burstable RAM

La primera, es la RAM que tendremos disponible físicamente garantizada SIEMPRE en nuestra VPS, y la segunda es una RAM compartida entre VPS, que no siempre tendremos disponible, y que solo se usará en casos de urgencia, por ejemplo, cuando un sitio a cierta hora del día, tiene muchas visitas.

 

Algunos de los vendedores, ofrecen burstable RAM, pero otros NO. Por eso, ésta gran ventaja que supone tener más RAM cuando se necesite, puede ser otro factor a tener en cuenta a la hora de elegir una VPS.
Espero sus comentarios, con respecto al tema. En lo personal, a mi me gustan las VPS UnManaged, y en un próximo Post, voy a explicar como montar un Servidor Web COMPLETO, desde cero.

 

Saludos!