Seleccionar consulta lleva más tiempo del que debería


9

Tengo una tabla de base de datos MySQL con casi 23 millones de registros. Esta tabla no tiene clave primaria, porque nada es único. Tiene 2 columnas, ambas están indexadas. A continuación se muestra su estructura:

ingrese la descripción de la imagen aquí

A continuación se muestran algunos de sus datos:

ingrese la descripción de la imagen aquí

Ahora, ejecuté una consulta simple:

SELECT `indexVal` FROM `key_word` WHERE `hashed_word`='001'

Desafortunadamente, esto tardó más de 5 segundos en recuperar los datos y mostrármelos. Mi tabla futura tendrá 150 mil millones de registros, por lo que esta vez es muy, muy alta.

Ejecuté el Explaincomando para ver qué está pasando. El resultado está abajo.

ingrese la descripción de la imagen aquí

Luego ejecuté el perfil usando el siguiente comando.

SET profiling=1;
SELECT `indexVal` FROM `key_word` WHERE `hashed_word` = '001';
SHOW profile;

A continuación se muestra el resultado del perfil:

ingrese la descripción de la imagen aquí

A continuación hay más información sobre mi mesa:

ingrese la descripción de la imagen aquí

Entonces, ¿por qué esto está tomando tanto tiempo? ¡También están indexados! En el futuro, tengo que ejecutar muchos LIKEcomandos, por lo que esto está tomando demasiado tiempo. ¿Qué ha salido mal?


"Esta tabla no tiene clave principal, porque nada es único". Sí, claro ... es hora de volver a examinar su diseño. Todas las tablas deben tener una clave primaria (o única).
ypercubeᵀᴹ

Respuestas:


10

Usted preguntó " ¿por qué esto está tomando tanto tiempo ?". También dijo " Desafortunadamente, esto tardó más de 5 segundos en recuperar los datos y mostrármelos ". Además, informó el resultado del perfil de su consulta.

Como puede ver, la suma de los tiempos reportados por el generador de perfiles para cada paso cuenta hasta 0.000154 segundos. Entonces, desde el punto de vista del generador de perfiles, la consulta se completó en ese momento (0.000154).

Entonces, ¿por qué está obteniendo resultados en " ... más de 5 segundos? ".

Dijiste que estás filtrando una tabla de registro de 23 millones con un campo de 3 caracteres. Desafortunadamente, no nos dice cuántos registros está devolviendo su consulta ... pero gracias al EXPLAIN SELECT proporcionado, parece que su consulta devolvió 336052 registros.

Parece, también, que toda su actividad se ejecuta a través de alguna GUI (PHPMyAdmin?).

Entonces, después de todo lo anterior, podemos reformular su pregunta original como:

"¿por qué obtengo, dentro de mi GUI, 336.052 registros que se muestran en más de 5 segundos, si el tiempo de ejecución de MySQL para la consulta relacionada es 0.000154 segundos?"

La respuesta, en mi opinión, es bastante simple: 5 segundos es el tiempo (realmente bajo) para permitir que 336.052 registros viajen a lo largo del camino: motor MySQL => bibliotecas cliente MySQL => módulo PHP MySQL => Apache => red = > su PC TCP / IP stack => Browser => DOM parser / builder / etc. => Página HTML representada.

En cuanto a mi experiencia previa, el tiempo requerido por la transmisión de resultados es "normalmente" mucho mayor que el tiempo necesario para recuperar dichos datos. Esto es especialmente cierto cuando las bibliotecas como PHP-MySQL o Perl-DBD-MySQL están involucradas: realmente requieren mucho tiempo para recuperar los registros, después de MySQL los haya identificado (... y extraído) correctamente.

¿Cómo resolver este problema?

De nuevo, con bastante facilidad: ¿está realmente seguro de que necesita TODO el registro 336.052, en un único conjunto de datos completo?

  • Si su respuesta es realmente "¡SÍ! Los necesito a todos", entonces su aplicación manejará la PAGINACIÓN y / o la Interacción del USUARIO por sí misma y ... una vez que haya reunido todos esos datos, probablemente pasará mucho tiempo interactuando con el usuario sin requerir ninguna interacción adicional de MySQL. En tal caso, esperar 5 segundos (o incluso más) no debería ser un problema;

  • Si su respuesta es "NO, quiero tratar con un tamaño de conjunto de datos más" humano ", de lo que debe refinar su consulta (al menos) para que le devuelva un conjunto de datos más" humano "(decenas o, cientos, como máximo, registros). En tal caso, apuesto a que obtendrá su resultado en un tiempo más corto.


Por cierto: este es exactamente el mismo problema que experimentó en esta otra publicación , en ServerFault: 88 segundos para permitir que 132M registros viajen a lo largo de ... la ruta mágica no estrictamente relacionada con mysql :-)


Espero una respuesta de la op.
Jnanaranjan

5
  1. Compruebe el mysql innodb_buffer_pool_size . Debería ser lo suficientemente grande: cuanto más, mejor. Pero no demasiado para evitar el intercambio del sistema operativo.

    show variables like 'innodb_buffer_pool_size'

    mostrará el tamaño del búfer en bytes.

  2. Verifique la consulta más de una vez. La primera ejecución puede ser demasiado larga ya que los datos deben leerse desde el disco a la memoria. Cuando ejecuta la consulta por primera vez, los datos aún no están en el búfer innodb y deben leerse desde el disco. Lo cual es mucho más lento que si los datos ya estuvieran en caché. Ejecute la consulta un par de veces para asegurarse de que se sirve desde la memoria caché.

  3. Inhabilite el caché de consultas, ya que cada ejecución consecuente se cumplirá a partir de él y sesgará los resultados de la prueba. Hay un mecanismo en MySQL, llamado "caché de consultas" que está diseñado para almacenar consultas junto con sus resultados. Entonces, la segunda vez que se solicita a MySQL que ejecute la consulta, puede omitir la ejecución y recuperar los resultados del caché de la consulta.

  4. Considere usar un "índice de cobertura":

    ALTER TABLE key_word ADD KEY IX_hashed_word_indexVal (hashed_word, indexVal);

Esto sería mucho más eficiente, ya que MySQL puede cumplir con la solicitud de consulta solo desde el índice.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.