2011-10-24 35 views
5

He estado tratando de descubrir qué hay de malo en un conjunto de consultas que tengo y estoy confundido en este momento.Las consultas de MySQL son rápidas cuando se ejecutan directamente pero realmente son lentas cuando se ejecutan como proc almacenado

Se supone que está en un procedimiento almacenado al que llama una aplicación GUI.

Sólo hay un "pequeño" problema, la primera vez que un simple UPDATE, a continuación, un INSERT utilizando un SELECT con una subselección y finalmente otra UPDATE. Al ejecutar estas consultas a mano, obtengo un tiempo total de ejecución de 0.057 s, no muy mal.

Ahora, intento crear un procedimiento almacenado con estas consultas y cinco variables de entrada, ejecuto este procedimiento y en el primer intento me llevó 47.096s con las siguientes llamadas mostrando tiempos de ejecución similares (35 a 50s). Ejecutar consultas individuales desde MySQL Workbench aún muestra tiempos de ejecución de menos de 0.1s

Realmente no hay nada sofisticado en estas consultas, entonces ¿por qué el procedimiento almacenado tarda una eternidad en ejecutarse mientras las consultas solo toman una fracción de segundo? ¿Hay algún tipo de peculiaridad de MySQL que me falta aquí?

Otros resultados de la prueba:

Parece que si corro las consultas en MySQL Workbench pero el uso de variables en lugar de limitarse a poner los valores de las variables en las consultas que se ejecuta tan lento como el procedimiento almacenado. Así que traté de cambiar el procedimiento almacenado para usar solo valores estáticos en lugar de variables y de repente funcionó increíblemente rápido. Aparentemente, por algún motivo, el uso de una variable lo hace extremadamente lento (por ejemplo, la primera consulta UPDATE va de tomar aproximadamente 0.98s con tres variables a 0.04-0.05s cuando utilizo los valores de las variables directamente en la consulta, independientemente de si es en el procedimiento almacenado o ejecutando la consulta directamente).

Entonces, el problema no es el procedimiento almacenado, es algo relacionado con mi uso de variables (que es inevitable).

+0

Necesitaríamos ver algunos códigos. La primera suposición descabellada sería algo extraño que estás haciendo al declarar/manejar las variables ... pero eso es una suposición completamente * salvaje * sin ver un código. –

+0

Como dije, las consultas muy simples que se ejecutan muy rápido por sí solas, simplemente 'UPDATE table SET column = variable WHERE othercolumn> = othervariable O othercolumn = yetanothervar' type stuff. Y las variables se declaran en el formulario regular 'IN varname COLUMNTYPE (SIZE)' como parámetros para el procedimiento almacenado. Lo que me desconcierta es que no hay nada raro o lento (y sí, evito mostrar el código porque mi jefe probablemente se enoja porque yo lo haya hecho). – mludd

+0

Puedo mencionar que eliminar todas menos la primera consulta 'UPDATE' (que a su vez requiere menos de 0.05s para ejecutarse y luego ejecutar el proceso almacenado todavía da un tiempo de ejecución de alrededor de 1s, y el comentario anterior es una descripción bastante acertada de cómo complejo que 'ACTUALIZAR' es ... – mludd

Respuesta

0

Voto a favor para una pregunta muy interesante y más importante. Encontré this discussion de algunas de las razones por las cuales un procedimiento almacenado puede ser lento. Me interesaría ver las reacciones de los lectores al respecto.

La principal recomendación que tomé del intercambio: me ayudó a agregar más índices.

+0

Su respuesta aquí tenía un enlace muerto. Lo corregí lo mejor que pude, pero tuve que referirme a archive.org. Ninguna de las fuentes "duplicadas" que vi incluía las adiciones de Ronald Bradford. –

0

Como no quería perder demasiado tiempo tratando de descubrir por qué el uso de variables en mis procedimientos almacenados los hacía extremadamente lentos, decidí emplear una solución que algunos considerarían bastante desagradable. Simplemente ejecuté cada consulta directamente desde la capa de acceso a datos de mi aplicación. No es la manera más bonita de hacerlo (ya que muchas otras cosas para esta aplicación usan procedimientos almacenados) pero funciona y ahora el usuario no tendrá que esperar más de 40 segundos para ciertas acciones, ya que ocurren casi al instante.

Por lo tanto, no es realmente una solución o explicación de lo que estaba sucediendo, pero al menos funciona.

3

Tuve un problema similar. Ejecutar una rutina mysql fue horrible lento. Pero un colega me ayudó. El problema era que AUTOCOMMIT era cierto; Así que cada inserción y selección estaba creando una transacción completa. Luego ejecutar mi rutina con

SET autocommit=0; 

al principio y

SET autocommit=1;      

al final. El rendimiento pasó de casi 500 a 4 años

5

Tuve el mismo problema. Después de investigar durante un tiempo, descubrí que el problema era el problema de la compilación mientras MySQL estaba comparando texto.

TL; DR: la tabla se creó en una colación, mientras que MySQL "pensó" que la variable estaba en otra intercalación. Por lo tanto, MySQL no puede usar el índice previsto para la consulta.

En mi caso, la mesa fue creado con (latin1, latin1_swedish_ci) de colación. Para hacer MySQL a usar el índice, que tenía que cambiar la cláusula where en el procedimiento almacenado de

UPDATE ... WHERE mycolumn = myvariable 

a

UPDATE ... WHERE mycolumn = 
     convert(myvariable using latin1) collate latin1_swedish_ci 

Después del cambio, el procedimiento almacenado visto algo como esto:

CREATE PROCEDURE foo.'bar'() 
    BEGIN 
     UPDATE mytable SET mycolumn1 = variable1 
     WHERE mycolumn2 = 
      convert(variable2 using latin1) collate latin1_swedish_ci 
    END; 

donde (latin1, latin1_swedish_ci) es la misma colla con la que se creó mi tabla A.

para comprobar si MySQL utiliza el índice o no, puede cambiar el procedimiento almacenado para ejecutar una instrucción explain como sigue:

CREATE PROCEDURE foo.'bar'() 
    BEGIN 
     EXPLAIN SELECT * FROM table WHERE mycolumn2 = variable2 
    END; 

En mi caso, el resultado explain mostró que ningún índice fue utilizado durante la ejecución de la consulta.

Tenga en cuenta que MySQL puede usar el índice cuando ejecuta la consulta solo, pero todavía no usará el índice para la misma consulta dentro de un procedimiento almacenado, lo que tal vez porque de alguna manera MySQL ve la variable en otra intercalación.

Más información sobre la cuestión de colación se puede encontrar aquí: http://lowleveldesign.wordpress.com/2013/07/19/diagnosing-collation-issue-mysql-stored-procedure/ copia de seguridad de enlace: http://www.codeproject.com/Articles/623272/Diagnosing-a-collation-issue-in-a-MySQL-stored-pro

0

Algo que nos encontramos en toda la actualidad que hace que los procedimientos lento, incluso cuando se ejecutan muy rápido como las consultas directas, es tener nombres de parámetros (o, presumiblemente, variables) que son los mismos que los nombres de columna. La versión corta es, no use un nombre de parámetro que sea el mismo que una de las columnas en la consulta en la que se usará. Por ejemplo, si tiene un campo llamado account_id y un parámetro llamado igual, cámbielo a algo como in_account_id y su tiempo de ejecución puede ir de varios segundos a centésimas de segundo.

Cuestiones relacionadas