Tags: variables
Proyecto Euler 2 en Mysql
By admin on Sep 5, 2009 | In Trucos avanzado | Send feedback »
Aquí está la pregunta 2 del Proyecto de Euler The Euler Project :
Cada nuevo número de la secuencia de Fibonaci se genera sumando los dos números que lo preceden.
Empezando por el 1 y el 2, los diez primeros números serán:1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
Hallar la suma de todos números pares de la secuencia de Fibonaci que no exceda de cuatro millónes.
Pues, en cuanto a una solución de Perl, tenemos el siguiente código
Code:
#!/usr/bin/perl | |
| |
@f=(1,2); | |
$sum=2; | |
while(($f=$f[0]+$f[1]) <= 4_000_000) { | |
shift @f; push @f,$f; | |
$sum+=$f if $f%2==0 } | |
print $sum, "\n"; | |
# Answer = 4613732 |
Vemos que el programa Perl se suma a $sum donde la variable $f es un número par, y los lazos hasta que el valor cambiado en la memoria (que se añade a cada valor anterior para producir la serie de Fibonacci) es superior a 4.000.000.
¿Cómo podemos lograr esto en MySQL? Una vez más (como en la primera entrada) vamos a utilizar variables para iterar. Con el fin de obtener la secuencia de Fibonacci se puede utilizar este...
Code:
set @varsum=1; | |
set @varadd=1; | |
set @var1=1; | |
set @var2=1; | |
| |
select @varsum:=@varadd+@varsum as fibonacci, | |
@varadd:=@var2, | |
@var2:=@varsum, orderid | |
from orders limit 40; |
(orders es una tabla que yo uso que tiene miles de filas).
Puse 40 en la cláusula de LIMIT después de un poco de ensayo y error. Recuerdes restaurar las variables cada vez que se ejecuta una consulta como esta.
A continuación, puede hacer una suma de los valores devueltos cuando el valor de Fibonacci es menos de 4 millones de dólares, mediante un INNER SELECT:
Code:
set @varsum=1; | |
set @varadd=1; | |
set @var1=1; | |
set @var2=1; | |
| |
select sum(fibonacci) from (select @varsum:=@varadd+@varsum as fibonacci,@varadd:=@var2,@var2:=@varsum, orderid from orders limit 40) tmp where fibonacci < 4000000; |
Pero estamos sumando todos los números haciendo esto - el problema dice que sólo debe sumar los números pares de la secuencia. Modificar fácilmente (véte la solución para el número 1) utilizando la función MOD:
Code:
set @varsum=1; | |
set @varadd=1; | |
set @var1=1; | |
set @var2=1; | |
| |
select sum(fibonacci) from | |
(select @varsum:=@varadd+@varsum as fibonacci, | |
@varadd:=@var2, @var2:=@varsum | |
from orders limit 40) tmp | |
where fibonacci < 4000000 | |
and mod(fibonacci,2)=0; | |
| |
+----------------+ | |
| sum(fibonacci) | | |
+----------------+ | |
| 4613732 | | |
+----------------+ | |
1 row in set (0.27 sec) |
Espero que este código es de utilidad para alguien.
Saludos, Mark
Proyecto Euler 1 en Mysql
By admin on Sep 1, 2009 | In Aprendiz, Trucos avanzado | Send feedback »
Hola, he llegado recientemente a través del Proyecto de Euler http://projecteuler.net/ que plantea retos matemáticos en cualquier lenguaje de codificación que prefieres utilizar.
Entonces no estoy diciendo que MySQL es especialmente apto para afrontar estos retos, pero me preguntaba si yo podría resolver uno o dos solamente por el uso de MySQL.
He aquí la primera cuestión
Si hacemos una lista de los numeros naturales múltiplos de 3 ó 5, menores de 10.
Obtenemos 3,5,6 y 9. La suma de estos múltiplos es 23.
Hallar la suma de todos los multiplos de 3 o 5 menores de 1000.
En primer lugar voy a investigar la forma en que se puede hacer en Perl y luego ver cómo se puede aplicar esto en Mysql. (La siguiente es una adaptación de una solución Perl que he encontrado en Euler_problems_as_perl_oneliners )
#!/usr/bin/perl
# adds each multiple of 3 to $n
# then adds each mutiple of 5 to $n unless divisible by 3
# to avoid duplication!
$n=0;
for($i=3;$i<1000;$i+=3) {$n+=$i}
for($i=5;$i<1000;$i+=5)
{$n+=$i unless $i%3 == 0}
print $n, "\n";
# produces 233168
Por mi código de MySQL voy a empezar por ver cómo probar si un número es divisible por otro número en sql. Una forma es utilizar la función de MOD que devuelve el resto exacto tras la división (Es operación de módulo). Por lo tanto, debe retornar 0, cuando el número es divisible por tu numero de prueba. Asi, select mod(9,3); retorna 0 mientras select mod(8,2); retorna 2.
A continuación, necesitamos una manera de reiterar hasta 999 (es decir, todos los números por debajo de 1000). Suelo usar una tabla llena con números ascendentes para este tipo de tarea; sin embargo, es posible utilizar una técnica de variables, siempre que se inscriba a una tabla de base de datos con el número necesario de filas en él. Por ejemplo, si tenemos una tabla llamada orders con 20.000 registros, se puede traer de vuelta a tan sólo 20 filas numeradas como este:
Code:
select @rownum:=@rownum+1 'row_num', e.* from orders e, | |
(SELECT @rownum:=0) r | |
order by orderid desc limit 20 |
Así, con el fin de traer de vuelta a todos aquellos en los que el row_num campo es divisible por 3, ponemos el código anterior en un SELECT interno (Inner Select):
Code:
select row_num from | |
(select @rownum:=@rownum+1 'row_num' | |
from orders e, | |
(SELECT @rownum:=0) r | |
order by orderid desc limit 20) tmp | |
where mod(row_num,3) = 0; |
Por último añadir una cláusula de OR incluir números divisibles por 5, y suma el resultado:
Code:
select sum(row_num) from | |
(select @rownum:=@rownum+1 'row_num' | |
from orders e, | |
(SELECT @rownum:=0) r | |
order by orderid desc limit 999) tmp | |
where mod(row_num,3) = 0 or mod(row_num,5) = 0; |
Esto da una respuesta de: 233168. Se volvió bastante rápidamente también - apenas 0,08 de segundo! Hasta pronto!
Más información sobre las variables.
By admin on May 2, 2009 | In Gestión etc., Trucos avanzado | Send feedback »
Hola, yo pensé en hacer una pequeña adición a mi post anterior sobre las variables, ya que parece ser muy popular entre los lectores. En mi anterior entrada hablé principalmente de la utilización de las variables de sistema. Estos se establecen en el ámbito de tu período de sesiones utilizando Mysql - una vez que la conexión se termina la variable sale de ámbito de aplicación. Antes de ir a las variables globales, me gustaría mostrar el mejor uso que he visto recientemente de una variable de sesión. Se utiliza como alternativa a la función rownum, que está disponible en Oracle, pero no en Mysql. Aquí hay un ejemplo de esto en uso:
Code:
select @rownum:=@rownum+1 'row_num', | |
e.* from emp e, | |
(SELECT @rownum:=0) r | |
order by empno desc limit 5; |
Con este código se evita la necesidad de escribir una primera línea que asigna un valor a la variable antes de ejecutar la consulta de Select, es decir SET @rownum := 0;
Ahora voy a escribir un poco sobre las variables de sistema, que son muy útiles para las personas que tratan de mejorar el rendimiento de su sesión de Mysql. Normalmente puedes ver el estado de estas variables utilizando el comando SHOW VARIABLES. Aunque las variables de sistema tienen valores por defecto, la mayoría de ellas pueden cambiarse en tiempo de ejecución usando el comando SET. Ver el enlace para ver mas sobre variables de sistema del servidor:
manual server system variables
También hay variables de estado del servidor. Estos existen en las conexiones, y se puede actualizarlas en el archivo de configuración my.cnf Normalmente puedes ver el estado de estas variables utilizando el sentencia SHOW STATUS. Por ejemplo, el valor contra el nombre Select_full_join muestra el número de Full-joins que no utilizan índices. Si ves aquí un alto valor indica la necesidad de hacer una mejor indexación de las tablas correspondientes. Ver el enlace para ver el manual sobre variables de estado del servidor:
Manual server-status-variables
Por cierto, aquí hay un enlace que da 10 variables de MySql que debes controlar.
techrepublic link (en ingles)
Las diez variables en el enlace anterior son:
Threads_connected -- El número de conexiones abiertas actualmente. Esto puede ayudar en el análisis del tráfico o de decidir el mejor momento para un servidor de volver a empezar.
Created_tmp_disk_tables -- El número de tablas temporales en disco creadas automáticamente por el servidor mientras ejecutaba sentencias. Acceso a tablas en disco es generalmente más lento que el acceso a las mismas tablas en la memoria. Por lo tanto, las consultas que utilizan la sintaxis CREATE TEMPORARY TABLE puedan ser lento cuando este valor es alto.
Handler_read_first -- El número de veces que se lee la primera entrada de un índice. Si MySQL haga con frecuencia el acceso a la primera fila de una tabla de índice, sugiere que se trata de realizar un escaneo secuencial de todo el índice. Esto indica que la tabla correspondiente no ha sido debidamente indizados.
Innodb_buffer_pool_wait_free -- Normalmente, las escrituras al buffer de InnoDB se llevan acabo en segundo plano. Aún así, si es necesario leer o crear una página y no existe ninguna página vacía disponible, entonces es también necesario esperar a que las páginas sean volcadas previamente. Este contador cuenta las instancias de estas esperas. Si el tamaño del buffer ha sido establecido correctamente, este valor debería ser pequeño.
Key_reads -- El número de lecturas físicas de un bloque de claves desde disco. Si Key_reads es grande, entonces el valor de key_buffer_size es, probablemente, demasiado pequeño.
Max_used_connections -- El número máximo de conexiones que han sido utilizadas simultáneamente desde que el servidor ha sido iniciado. Este valor ofrece un punto de referencia para ayudarle a decidir el número máximo de conexiones de su servidor debe apoyar.
Open_tables -- El número de tablas que han sido abiertas. Si Opened_tables es grande, probablemente el valor de table_cache es demasiado pequeño.
Select_full_join -- El número de joins que no utilizan índices. Si este valor no es 0, debería comprobar cuidadosamente los índices de sus tablas.
Slow_queries -- El número de consultas que han tardado más de long_query_time segundos. Un valor alto indica que el número de consultas no se ejecuta óptimamente. Un siguiente paso necesario sería examinar el log de consultas lentas e identificar estas consultas para la optimización.
Uptime -- El número de segundos que el servidor ha estado funcionando ininterrumpidamente
Recuerda que si estás buscando una variable específica a través de SHOW STATUS, siempre podriás utilizar la cláusula de LIKE por ejemplo:
Code:
show status like 'max%'; |
Bueno, como ya he dicho, es sólo una breve entrada esta vez.
Vuelvo
Thanks,
Mark