Primero que nada, quiero aclarar que por bases de datos “grandes” me refiero a aquellas que tienen más de 100.000 filas.
Una base de datos muy grande puede generar bastantes problemas, como por ejemplo que un sitio se demore una eternidad en cargar o incluso que deje de responder. Pero el problema no es la base de datos ni el motor. Dicen que cuando hay que trabajar con grandes cantidades de datos debe dejar de usarse MySQL y usar SQL, pero finalmente una base de datos MySQL puede funcionar tan bien como una SQL si está bien configurada.
En base a mi experiencia, realmente lo complicado de las bases de datos grandes no son la cantidad de filas que tengan, sino la cantidad de datos que deben cruzarse.
Voy a poner un ejemplo práctico. Yo tengo una base de datos que tiene 3 tablas:
ciudades: 2.650.000 filas
regiones: 3850 filas
paises: 250 filas
Una de las formas más eficientes de mejorar las consultas son los “índices”, para lo cual se debe definir (idealmente) un largo y que columna se indexará. Lo que hacen los índices es generar una especie de “libro” donde tomará los X primeros caracteres de cada palabra de la columna definida y los agrupará (indexará). De esta forma, cuando yo busque algo, el sistema buscará en su índice primero y verá cuales son los que cumplen con esas caracteríscticas y luego irá a consultar esos datos (de esa manera no busca en toda la base de datos, sino en los que dice el índice).
Otra manera es utilizando LIMIT. Si estamos consultando algo que sabemos que retornará 1 sólo dato (por ejemplo cuando buscamos algo por ID), al ponerle LIMIT 1 se reducen considerablemente los tiempos. Esto es lógico pues al consultar dentro de 2.650.000 filas, si el sistema encuentra el dato en la fila n°4 (por ejemplo), al no tener un “LIMIT”, continuará consultando hasta el final de la base de datos. Por el contrario, si tiene el LIMIT, dejará de consultar apenas obtenga la cantidad de resultados especificada.
Otra cosa a considerar es que a utilizar LIKE (‘%xxx%’), el largo del string xxx influye mucho en los tiempos de respuesta. Por ejemplo, si busco (en la base de datos de las ciudades) alguna que contenga “%s%”, la consulta tarda 0,0022 seg. Si busco alguna que contenga “%santiago de %”, la consulta tarda 3,877.
Y finalmente el GRAN problema es cuando se cruzan datos. La tabla paises tiene 3 datos: ID, nombre, region. La región es un ID que va asociado al ID de la tabla regiones (de ahí sacaré los nombres de cada región). Y la región pertenece a un país, cuyo nombre está en la tabla de paises (ID, nombre pais).
Si quiero pedir el nombre de la ciudad, el nombre de la región y el nombre del país de todas las ciudades que comiencen con “santiag%”, tendría una consulta como la siguiente:
SELECT ciudad.nombre, region.nombre, pais.nombre FROM ciudades, regiones, paises WHERE ciudad.nombre LIKE ("santiag%") AND ciudad.region=region.id AND region.pais=pais.id
Esta consulta, al tener que cruzar datos entre tablas demorará mucho tiempo, ya que obligaremos al motor de base de datos a tener en memoria los nombres de todas las ciudades, regiones y países y hacerlos coincidir. Mientras más WHERE apliquemos, más lenta se tornará la consulta.
¿Qué hacemos en casos como este, en que la consulta demore por ejemplo 35 segundos?… claramente no podemos dejar esperando a nuestros clientes todo ese rato. Para casos como estos, la solución es tan simple como hacer 3 consultas a la base de datos:
- Primero, se consulta el listado de paises y se guarda en un array asociativo, donde el Key sea el ID del pais y el valor sea el Nombre del pais.
- Luego se hace lo mismo con las regiones
- Finalmente se hace la consulta SOLAMENTE de las ciudades que partan con “santiag%”. Sin cruce de datos ni nada.
Entonces, cuando queramos mostrar los datos del pais y la región haremos algo como: <? echo $regiones[ID_CIUDAD]; ?>, <? echo $paises[ID_CIUDAD]; ?>, lo cual mostraría en pantalla algo como “Región Metropoitana, Chile”.
Esta manera, en algunos casos es mucho más eficiente que esperar 35 segundos por consulta, ya que como son 3 consultas simples, demorarían menos de 0,5 seg. cada una.
Estas son algunas formas de optimizar las consultas a la base de datos. Aunque se diga lo contrario por ahí, SI es posible manejar millones de datos en MySQL sin tener problemas de tiempos de respuesta. Sólo basta con configurar y optimizar las consultas.