Whislist

Ya vienen las fiestas de Navidad y con ellas los ajetreos por hacer todas las compras de regalos… esto para mi padre, esto para mi madre, etc. ¡Y como no, los regalos para mi!

Una cámara fotográfica nueva. Para poder seguir haciendo fotografías increíbles. Como ya sabéis, personalmente me encanta la nueva Sony A77. En la sección de fotografía de Fnac, encontraremos esta fantastica cámara a un precio alucinante: 1301,07€.

Sony A77

Sony A77

Y ya puestos a pedir a Papá Noel o a los Reyes Magos, pues aprovecho para sugerir un iPad 2, de Apple, con WiFi y 3G con 32GB para poder mostrar las fotos que hagamos con la cámara y de paso leer el último comentario que nos dejen en Flickr, en 500px o en este blog de tecnología. Como es habitual, cualquier modelo de iPad se puede encontrar en cualquier tienda Fnac. Y concretamente este modelo a un precio espectacular: 699€.

iPad 2 de Apple con WiFi y 3G con 32GB

iPad 2 de Apple con WiFi y 3G con 32GB

¡Un abrazo a tod@s y que disfrutéis de las Navidades¡

MySql tunning

Uno de los primeras cosas que hay que saber antes de empezar a optimizar consultas en MySql es conocer la existencia de la cláusula EXPLAIN.

Con EXPLAIN podemos obtener el plan de ejecución de una consulta dada, como se muestra en el siguiente ejemplo:

EXPLAIN SELECT * FROM People

Resultado:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE People ALL NULL NULL NULL NULL 979

En el ejemplo anterior el plan de ejecución es un simple full scan (type = ALL) de toda la tabla People.

Vamos a ver otro ejemplo:

EXPLAIN SELECT * FROM People WHERE gender = 'Male'

Resultado:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE People ALL NULL NULL NULL NULL 979 Using where

En este caso vemos que la consulta devuelve al motor de base de datos sigue devolviendo todos los registros en un full scan.  En este caso podemos optimizar la consulta creando un índice para gender (Idx_gender). Y de esta forma el resultado de EXPLAIN será:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE People ref Idx_gender Idx_gender 22 const 489 Using where

Ahora se puede ver como ya no se requiere un full scan (type != ALL) y únicamente la filas con valores en el índice serán las seleccionadas.

Hasta ahora se puede intuir que cuando el tipo es ALL y no queremos un full scan (todas las filas), siempre se puede optimizar. Lo más sencillo es con la creación de índices que agilicen las búsquedas más frecuentes.

A continuación teneís el detalle de todos los campos que devuelve EXPLAIN:

Id: El identificador de la SELECT. Es un número secuencial.

Select_type: Tipo de la SELECT.

  • SIMPLE: SELECT simple, sin UNION o subconsultas.
  • PRIMARY: Se refiere a la consulta “más externa”; a la principal.
  • UNION: Resto de consulta/s (segunda, tercera, etc.) en una UNION.
  • DEPENDENT UNION: Resto de consulta/s (segunda, tercera, etc.) en una UNION que depende una una consulta “externa”; PRIMARY.
  • UNION RESULT: Resultado de una UNION.
  • SUBQUERY: Primera consulta de una subconsulta.
  • DEPENDENT SUBQUERY: Primera consulta de una subconsulta que depende una consulta “externa”.
  • DERIVED: Tabla derivada en una SELECT; subquery en la cláusula FROM.
  • UNCACHEABLE SUBQUERY: Subconsulta que no puede ser almacenada en caché, o re-evaluada.
  • UNCACHEABLE UNION: Resto de consulta/s (segunda, tercera, etc.) en una UNION que no puede ser almacenada en caché, o re-evaluada.

Table: tabla a la que se refiere la fila del resultado.

Type: el tipo de JOIN. Los tipos de muestran a continuación ordenados desde el mejor al peor.

  • system: la tabla únicamente tiene una fila y es una tabla del sistema. Es un caso especial del tipo const.
  • const: en la tabla coincide una única fila que el optimizador tomo como constante. También se utiliza cuando se comparan todas las partes de una clave primaria o un índice único (UNIQUE) con un valor constante.
  • Eq_ref: una fila de una tabla es leída por cada combinación de filas en una segunda tabla. Se utiliza cuando se usan todas las partes de una clave primaria o un índice único (UNIQUE).
  • ref: todas las filas que coincidan con con los valores de un índice serán leídos por cada combinación de filas de las tablas anteriores. En JOIN se utiliza cuando no se puede seleccionar una única fila en base al valor de la clave. Puede ser usada, por el optimizador, en columnas indexadas que se comparan con =, <=>.
  • fulltext: la JOIN se realiza con un índice FULLTEXT.
  • ref or null: el tipo de JOIN es como ref pero hay una búsqueda extra para campos nulos. Este tipo se suele utilizar para resolver subconsultas.
  • index_merge: se utiliza la optimización index merge.
  • unique_subquery: sustituye a ref en algunas subconsultas (del tipo SELECT clave_primaria) que utilizan IN.
  • index_subquery: sustituye a ref en algunas subconsultas (del tipo SELECT valor_columna) que utilizan IN y que no son únicas.
  • range: cuando se devuelve filas dentro de un rango.
  • index: igual que un full scan pero cuando se escanea el índice.
  • ALL: full scan. Normalmente se debe evitar.

Possible_keys: Muestra que índices puede seleccionar MySql para devolver las filas.

Key: Indica que índice va a utilizar MySql para devolver las filas.

Key_len: tamaño del índice que se va a utilizar.

Ref: columna/s o constante/s que se van a comparar con el índice.

Rows: indica el número de filas que se prevee que MySql examine. En tablas InnoDB es un valor aproximado.

Extra: información adicional sobre como MySql resolverá la consulta.

Para más información sobre el resultado de EXPLAIN por favor mirar en la página web de MySql.

Espero que os halla sido de utilidad este breve artículo de cómo utilizar EXPLAIN para optimizar vuestras consultas a bases de datos.

¡Un saludo a tod@s!

#SpanishRevolution

¡Revolución ya! Es hora de despertar. La pesadilla debe acabar y empezar a vivir un cambio. Un revolución de vez en cuando es sana para revisar que las cosas se están haciendo bien y mejorar las que se están haciendo mal. Nuestros políticos, que en su día se revelaron, se han apoltronado en sus puestos y únicamente hacen acto de ostentación de un cargo que deberían ejercer. Los estados están secuestrados por los mercados que han sabido captar – con cantos de sirena – a quienes deberían gobernar, más pendientes de sus sueldos vitalicios y su “futuro” en el sector privado que en la difícil tarea de gobernar un País. Poderoso caballero es Don dinero y eso las grandes multinacionales lo saben.

Pensar si realmente somos libres. ¿Podemos dejar nuestro trabajo cuando queramos? No. A través de nuestro capricho nos han encadenado a créditos hipotecarios, créditos para estudiar, créditos para irnos de vacaciones, créditos para todo. Hemos vendido nuestra vida a los mercados que a través de los bancos y de nuestros políticos, nos han puesto los grilletes para que esta sociedad siga esclavizada al servicio de unos pocos sin escrúpulos.

Nosotros seguramente ya no tenemos salvación, estamos condenamos a pagar nuestra codicia. Pero todavía podemos salvar a nuestros hijos, nietos y futuras generaciones. Muchos imperios antes han caído y muchos lo harán en el futuro. Y ellos se levantarán,  pero pensado que nosotros también. Y así iremos completando ciclos vitales hasta el fin de tiempos.

Os dejo con el final de una de las mejores películas que he visto. Y dónde el guionista y el director ya nos hacían un guiño de como resetear esta Democracia 1.0 e instalar la 2.0

Microservices for Twitter… #givemeasearch

GiveMeASearch is a microservice for do searches (using Google) from the world of Twitter. Using it is very simple. Add the hashtag #givemeasearch in a tweet – or retweet – and the microservice will do the search, of the text, in Google y after will return a mention or direct message (if you follow GiveMeASearch) with the firsts two links of the result of the search.

Microservicios para Twitter… #givemeasearch

GiveMeASearch es un microservicio de búsquedas (a través de Google) para el universo Twitter. Su utilización es bien sencilla. Al añadir el hashtag #givemeasearch en un tweet – o retweet – el microservicio realiza la búsqueda, del texto, en Google y devuelve vía mención o mensaje directo (si sigues a GiveMeASearch) los enlaces de las dos primeras entradas.

Three useful or not… Java functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int heavy_decimal_count(int a, int b) {
    int result = 0;
    Hashtable<String, Double> range = new Hashtable<String, Double>(); 
 
    char[] number;
    double avg;
    for (int i = a; i < = b; i++) {
        number = String.valueOf(i).toCharArray();
 
        avg = 0.0;		
	for(int j = 0; j < number.length; j++) {
	    avg += Integer.parseInt(String.valueOf(number[j]));
	}
 
        avg /= number.length;
	if (avg >= 7.25)
	    result++;
 
        range.put(String.copyValueOf(number), Double.valueOf(avg));
    }
 
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int dominator(int[] A) {
    int result = -1;
 
    Hashtable<String, Double> occurrence;
    Hashtable<Integer, Hashtable<String, Double>> indexes = new Hashtable<Integer, Hashtable<String, Double>>();
 
    for (int i = 0; i < A.length; i++) {
        if (indexes.containsKey(Integer.valueOf(A[i]))) {
            occurrence = indexes.get(Integer.valueOf(A[i]));
            occurrence.put("OCCURRENCES", occurrence.get("OCCURRENCES").doubleValue() + 1);
            occurrence.put("DOMINATOR", (occurrence.get("OCCURRENCES").doubleValue() + 1) / A.length);
            occurrence.put("LASTINDEX", Double.valueOf(i));
        } else {
            occurrence = new Hashtable<String, Double>();
            occurrence.put("OCCURRENCES", 1.0);
            occurrence.put("DOMINATOR", 1.0 / A.length);
            occurrence.put("LASTINDEX", Double.valueOf(i));
        }
        indexes.put(Integer.valueOf(A[i]), occurrence);
    }
 
    Iterator<Hashtable<String, Double>> it = indexes.values().iterator();
    while (it.hasNext()) {
        occurrence = it.next();
	if (occurrence.get("DOMINATOR").doubleValue() > 0.5) {
            result = occurrence.get("LASTINDEX").intValue();
        }
    }
 
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int amplitude(int[] A) {
    int result = -1;
    int newVal = 0;
 
    for (int i = 0; i < A.length ; i++) {
        for (int j = 0; j < A.length; j++) {
            if (j == i)
                continue;
            newVal = Math.abs(A[i] - A[j]);
            if (newVal > result)
                result = newVal;
        }
    }
 
    return result;
}

Programador horario con Arduino

¡Hola a tod@s!

Últimamente estoy inmerso en un proyecto con Arduino. El proyecto en cuestión trata el diseño y programación de un controlador para la Pecera del Quinto. Uno de los primeros escollos a resolver es el programador horario y para ello he hecho la siguiente función. La función between(..) permite saber si la hora actual (o cualquier otra) está entre dos horas diferentes, además permite incluir una hora final en el siguiente día (ver ejemplo).

Código de la función:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
* Between is a method to check if current time is between two different times (initial time and final time). This method supports a 'final time' in the next day.
* @param currHour integer (0-23) with the current hour.
* @param currMinute integer (0-59) with the current minute.
* @param initHour integer (0-23) with the initial hour.
* @param initHour integer (0-59) with the initial minute.
* @param finalHour integer (0-23) with the final hour.
* @param finalMinute integer (0-59) with the final minute.
* @return true if the current hour is between the two times (initial and final)
* @author Oscar Sanchez Montaner (OSanchezMon)
*/
boolean between(int currHour, int currMinute, int initHour, int initMinute, int finalHour, int finalMinute) {
  boolean result = false;
 
  // Converting times to minutes.
  int  on = initHour  * 60 +  initMinute;
  int now = currHour  * 60 +  currMinute;
  int off = finalHour * 60 + finalMinute;
 
  // If final time is in the next day...
  if (finalHour < initHour) {
    // ... must first check if current time is above 12AM (24)...
    if (now < off) {
      now += 1440; // ... if it is above; increase it 1440 minutes.
    }
    off += 1440; // Final time (for the next day) is always increased 1440 minutes.
  }
 
  // Development information.
  if (DEBUG_ON) {
    Serial.print("On: "); Serial.print(on); Serial.print(", Now: ");
    Serial.print(now); Serial.print(", Off: "); Serial.println(off);
  }
 
  // Check if current time is between initial and final time.
  if (now >= on && now < off) {
    result = true;
  }
 
  return result;
}

En el siguiente ejemplo se quiere saber si la hora actual está comprendida entre las 23:10 y las 10:10 (de la mañana siguiente).

Ejemplo de utilización:

1
2
3
4
5
6
7
if (between(hora_actual, minuto_actual, 23, 10, 10, 10)) {
    if (!relay02On) {
      digitalWrite(relay02Pin, HIGH);
      relay02On = true;
      logger("Relay 02 enabled.");
    }
}

Where are my site-packages stored?

The location depends on the operating system, to find out try to execute the following code:

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

Cheers!

Cómo utilizar JOIN en sentencias UPDATE o DELETE.

Una práctica muy recomendable antes de lanzar una sentencia UPDATE o DELETE sobre un subconjunto de tuplas, es probar a realizar la proyección, afinando las condiciones de restricción para el subconjunto (mediante una sentencia WHERE). Cuando nos encontramos ante una condiciones sencillas, reutilizar la misma clausula WHERE es trivial. Pero qué sucede cuando queremos utilizar funciones de composición (JOIN) para restringir el conjunto de datos.

Ejemplo para UPDATE, donde se puede ver como se han utilizado varios JOINs en el bloque de referencia a la table (table_reference en el manual de MySql):

UPDATE table1 T1 INNER JOIN table2 T2 ON T1.id = T2.id INNER JOIN table3 T3 ON T3.other_id = T2.other_id INNER JOIN table4 T4 ON T4.category = T3.category SET T1.readed = 0 WHERE T1.TYPE = 'X' AND T1.category  = 'A';

Ejemplo para DELETE. En este caso después del DELETE hay que especificar la tabla o tablas (multi-delete):

DELETE T2 FROM table2 T2 ON T1.id = T2.id INNER JOIN table3 T3 ON T3.other_id = T2.other_id INNER JOIN table4 T4 ON T4.category = T3.category WHERE T1.TYPE = 'X' AND T1.category  = 'A';

Espero que estos ejemplos os sirvan de ayuda.

NOTA: Todos los ejemplos se han ejecutado en un servidor MySql version 5.1.

Actualización

Ejemplo para MS SQL 2005:

UPDATE table1 SET T1.readed = 0 FROM table1 T1 INNER JOIN table2 T2 ON T1.id = T2.id INNER JOIN table3 T3 ON T3.other_id = T2.other_id INNER JOIN table4 T4 ON T4.category = T3.category  WHERE T1.TYPE = 'X' AND T1.category  = 'A';

Zope and Apache HTTP Server working as reverse proxy

I folks,

If you want to create an scenario with a Zope working as production web site and other/s Zope working as application server, probably you are looking for the way to configure Apache as reverse proxy between the front row (web site and content) and the rear row (web applications). In this case, working with Zope makes the configuration be easier because it has a product (VirtualHostMonster) that does part of the work; “A Virtual Host Monster’s only job is to change the URLs which your Zope objects generate. This allows you to customize the URLs that are displayed within your Zope application, allowing an object to have a different URL when accessed in a different way“. This is very useful because in other way we should use a third-party module called ProxyHtml. mod_proxy_html is used to rewrite HTML code, specially links. But in our case, we only need to use the rewrite module (mod_rewrite) and the proxy module (mod_proxy).

Let’e get to work:

To redirect an application from a public server to a private server (private server does not need to has an Apache running) we should add the following code in the virtual host configuration file (/etc/apache2/vhosts.d/myhost.conf).

RewriteRule ^/Intranet/Apps/app1(.*) http://private.com:8080/VirtualHostBase/http/<strong>%{HTTP_HOST}</strong>:80/DOM/VirtualHostRoot/Intranet/Apps/app1/$1 [L,P]
ProxyPassReverse / http://private.com:8080/VirtualHostBase/http/<strong>%{HTTP_HOST}</strong>:80/DOM/VirtualHostRoot/

Note than in the second part of both rules the URL is compliant with the VHM requirements. First we found the rewrite and redirection to the private server (http://private.com:8080/VirtualHostBase/) and after the /http/ we find the host (here I use the Apache’s variale HTTP_HOST) where the VirtualHostMonster will do the reverse proxy. %{HTTP_HOST} is an Apache’s variable, and we can use it here or directly the name of the public server.

And this is all :-) If you have any other experience or comment please don’t hesitate to comment here!