Profiling en Drupal
sep 4, 19:14
Si bien Drupal tiene el módulo Devel para hacer profiling a full, también se pueden hacer algunas cosas a mano usando una variable algo escondida en Drupal: $dev_query . Al activarla todas las consultas hechas a través de db_query serán almacenadas en un array ($queries) junto con el tiempo que duró la consulta.
Supongamos que queremos hacer profile de un pedazo de código en Drupal. Al inicio de éste llamamos a una funcion profile_start que active $dev_query y que comience a medir el tiempo que toma en ejecutarse el código.
function profile_start()
{
variable_set('dev_query',1);
$start = microtime();
}
También podemos usar getrusage() , que nos da muchos más detalles. Internamente db_query() también usa microtime() . Al final del código le diremos que el profiling se detenga con algo cómo:
function profile_stop()
{
$end = microtime();
global $queries;
// se procesa la información almacenada por db_query()
variable_set('dev_query',0);
}
Hago notar que éste código no es funcional, pero al menos puede dar una buena idea de lo que se necesita hacer. Sería recomendable guardar los resultados obtenidos en una base de datos para procesarlo como queramos. Para que ésto no afecte nuestros resultados ni el rendimiento de nuestra aplicación podemos usar INSERT DELAYED de MySQL, de tal manera que el insert de los resultados se ejecuta en el background y se nos regresa inmediatamente dónde estábamos.
Algunas ideas más para hacer profiling de MySQL en PHP las pueden encontrar en el Capítulo 2 del libro High Performance MySQL (segunda edición): Finding Bottlenecks: Benchmarking and Profiling.
STRAIGHT_JOIN
oct 16, 07:35
Una herramienta muy útil en el trabajo con base de datos MySQL es el slow query log , un registro de las sentencias SQL que demoran más tiempo en realizarse. El tiempo mínimo para registrar la sentencia en el log está determinado por la variable long_query_time . Lamentablemente, esta variable está limitada a segundos, por tanto sólo podemos registrar operaciones que demoran más de 1 segundo. Para solucionar este incoveniente existe un parche para MySQL que permite configurar el long_query_time en microsegundos, claro, si es que se atreven a recompilar el mysql. A partir de la versión 5.1.21 esta característica vendrá incluida de serie en MySQL.
Entonces, en el slow query log encontré una consulta que estaba demorando 3 segundos en realizarse. Era un SELECT con dos INNER JOINs en tres tablas, osea 3 JOINs porque para MySQL toda consulta es un JOIN. Además había un ORDER BY y un LIMIT.
Una buena forma de entender el plan de ejecución de MySQL es usando la sentencia EXPLAIN o si quieren tenerlo más bonito se puede hacer con mk-visual-explain de Maatkit . El join optimizer de MySQL es quien decide cuál es el mejor orden para la ejecución de consultas en múltiples tablas. Por ésto no siempre los JOINs se ejecutarán en el orden qué hemos dispuestos en nuestra consulta SQL. En teoría el join optimizer debería escoger el plan de ejecución que use menos recursos.
Gracias a EXPLAIN entendí que el join optimizer estaba alterando el orden de los JOINs de la consulta SQL en cuestión. Uno debe considerar por defecto que el join optimizer está haciendo bien su trabajo, así que me dediqué a buscar otros puntos donde optimizar la consulta.
Noté por ejemplo que la consulta no se estaba ordenando por ningún campo que fuera índice. Así que procedí a añadir un índice para la columna que usaba el ORDER BY. Sin embargo no hubo gran diferencia en la performance. Lo que noté es que en la columna Extra de EXPLAIN me aparecía “Using temporary; Using filesort” Esto significa que para ordenar la tabla MySQL no podía usar ningún índice y estaba almacenando los resultados en una tabla temporal y recién ahí los ordenaba usando recursos de memoria y disco (filesort)
¿Qué estaba pasando?
Lo que sucede es que lo correcto es que MySQL realice el ORDER BY usando una columna de la tabla principal, la del primer JOIN y como el join optimizer estaba cambiando el plan de ejecución, mi tabla principal no era la misma que se estaba usando para el ORDER BY. La combinación ORDER BY + LIMIT tiene muchos detalles para optimizar.
Así que para determinar si estaba por el buen camino tenía que forzar a MySQL a que siguiera el plan de ejecución del consulta tal como estaba escrito. Para ésto usamos STRAIGHT_JOIN dentro de nuestra consulta, el resultado: la consulta demoraba ahora menos de 1 segundo.
Yo aún creo que debería existir una mejor manera de optimizar la consulta, ya que pocos son los casos en que se debería usar STRAIGHT_JOIN por sobre el join optimizer. Lo más importante de esta experiencia es saber usar algunas herramientas cómo el “slow query log” y EXPLAIN pero sobre todo entender la forma cómo funciona MySQL por dentro y así poder optimizar nuestras consultas.
En este sentido recomiendo leer la presentación Explain Demystified de Baron Schwartz y la segunda edición del libro High Performance MySQL .
Caracteres extraños en mysql
sep 16, 16:58
A veces no basta con tener todo con soporte UTF-8. Por ahí que alguien introduce un caracter extraño proveniente de Microsoft Word en un registro de la base de datos y luego al migrar la información se produce el desastre. Por ejemplo me pasó con las dichosas comillas curvas (curly quotes).
Cuando se migran los datos todo pasa bien, por el UTF8, pero las dichosas comillas se muestran como caracteres extraños. Lo primero que hay que hacer es determinar el valor de estos caracteres. Pero ojo, tenemos que sacar el dato directo de la base de datos (en mi caso MySQL) porque quizás la aplicación o el navegador los lean de otra forma.
Entonces en mi caso en la base de datos en vez de las comillas curvas veía â€? cuyos valores son: char #226, char #128 y char #63 . Entonces hacemos un replace en mysql:
update mitabla set columna = replace(columna, concat(char(226),char(128),char(63)), “””) where id=1;
Siempre es bueno probar primero con un solo valor (p.e. id=1) para no malograr el resto de registros (¡y siempre un backup también!). Y ya está.
High Performance MySQL - Segunda Edición
jul 7, 17:26
Ya está a la venta el libro y ya se están demorando en comprarlo .
Comentarios