Algo muy común cuando se está trabajando en el mejoramiento del performance de los querys es saber cuales querys son los que están tomando más tiempo en ejecutarse, y ver cuales son los que más frecuentemente se ejecutan para considerar la posiblidad de almacenarlos en cache.

El problema es que cuando ya se está en ambiente de producción tener esta información es un poco complicada si no se conoce un poco de configuración del PostgreSQL.

En postgreSQL existe el archivo de configuración postgresql.conf de donde se leen las configuraciones iniciales.

En ese archivo hay muchas variables a configurar, pero específicamente una sección dedicada a las estadísticas.

#--------------------------------------------------------
# RUNTIME STATISTICS
#--------------------------------------------------------

# - Statistics Monitoring -

#log_parser_stats = off
#log_planner_stats = off
#log_executor_stats = off
#log_statement_stats = off

# - Query/Index Statistics Collector -

#stats_start_collector = on
stats_command_string = on
#stats_block_level = off
stats_row_level = on
#stats_reset_on_server_start = off

Por default la variable stats_command_string esta desáctivada, en las estadísticas no se permite ver el query que se ejecuta, sino simplemente aparece así:

 datid   |     datname   | procpid | usesysid |  usename |         current_query        |    query_start   |   backend_start  | client_addr    | client_port
---------+---------------+---------+----------+----------+------------------------------+------------------+------------------+----------------+-------------
58964727 | database1     |   31874 |    16384 | usuario1 | <command string not enabled> | 2007-11-29 14:51 | 2007-11-29 14:51 | 192.168.10.16  |  4096
58964727 | database1     |    3031 |    16384 | usuario1 | <command string not enabled> | 2007-11-29 22:02 | 2007-11-29 22:01 |                |    -1
58964727 | database1     |    3189 |  6191381 | rene     | <command string not enabled> | 2007-11-29 23:10 | 2007-11-29 23:09 | 192.168.10.109 |  4767
58964727 | database1     |   32157 |    16384 | usuario1 | <command string not enabled> | 2007-11-29 16:49 | 2007-11-29 15:16 | 192.168.10.16  |  2892
58964727 | database1     |    3190 |  6191381 | rene     | <command string not enabled> | 2007-11-29 23:11 | 2007-11-29 23:09 | 192.168.10.109 |  4775
35829649 | rene          |    3192 |  6191381 | rene     | <command string not enabled> | 2007-11-29 23:11 | 2007-11-29 23:11 |                |    -1

En cambio si activamos dicha variable stats_command_string = on, obtendremos:

  datid   |     datname   | procpid | usesysid |  usename |              current_query    |  query_start     | backend_start    |  client_addr   | client_port
----------+---------------+---------+----------+----------+-------------------------------+------------------+------------------+----------------+-------------
 58964727 | database1     |    3189 |  6191381 | rene     | <IDLE>                        | 2007-11-29 23:10 | 2007-11-29 23:09 | 192.168.10.109 |  4767
 58964727 | database1     |   32157 |    16384 | usuario1 | <IDLE>                        | 2007-11-29 16:49 | 2007-11-29 15:16 | 192.168.10.16  |  2892
 58964727 | database1     |    3190 |  6191381 | rene     | select to from tabla group to | 2007-11-29 23:11 | 2007-11-29 23:09 | 192.168.10.109 |  4775
 35829649 | rene          |    3192 |  6191381 | rene     | <IDLE>                        | 2007-11-29 23:11 | 2007-11-29 23:11 |                |    -1
    10793 | postgres      |     617 |  6191381 | rene     | <IDLE>                        | 2007-11-29 23:08 | 2007-11-29 16:42 | 192.168.10.109 |  1688
 35842383 | usuario1      |   30003 |    16384 | usuario1 | <IDLE>                        | 2007-11-29 12:20 | 2007-11-29 12:20 | 192.168.10.16  |  2555

De aquí podemos obtener cierta información para poder tomar desiciones sobre nuestros querys.

Les dejo el query que suelo utilizar yo cuando estoy revisando el tiempo que duran cada ejecución de un select por ejemplo

select procpid,current_query,
extract(minute from now()- query_start) ,
extract(second from now()- query_start)
from pg_stat_activity
where current_query ilike '%select%'
order by extract(minute from now()-query_start) desc;

Con este query puedo saber cuantos minutos y segundos llevan ejecutándose los querys.

Nota: Luego de cambiar el valor de la variable, no se olviden de reiniciar la Base de Datos, y no dejen activado dicho valor siempre, pues es una carga más a la BD que reducirá su rendimiento.

Espero que les sirva y como siempre, estamos en contacto!

siempre desde el blog SEO Profesional, una referencia a un tutorial para el uso de .htaccess, mas que un tutorial busca orientarles en el manejo del .htaccess ya que esta escrito en forma de consejos o tips, así que ahi les va la referencia:

http://www.seoprofesional.com/index.php/14-11-2007/posicionamiento-web-en-buscadores/tutorial-de-htaccess/

Una de las tecnicas en la Optimizacion para Motores de Busqueda (SEO por sus siglas en inglés) es la de eliminar el paso de variables por querystring y utilizar URLs simulando una estructura de carpetas, las cuales facilitan el indexamiento de las mismas. En un ejemplo explícito estamos hablando de trasladar:

http://tusitio/archivo.php?variable1=valor1&variable2=valor2

a un equivalente como este:

http://tusitio/archivo/valor1/valor2/

Una explicación más detallada pueden verla en el siguiente post de SEO Profesional:

http://www.seoprofesional.com/index.php/05-11-2007/posicionamiento-web-en-buscadores/optimizacion-de-codigo/htaccess-url-dinamicas-y-seo/

Espero les sea útil.

Este es un pequeño tip que me ha acompañado y que aún he tenido la oportunidad de recomendarlo cuando alquien llega con la duda de como hacer que una imagen, o mas bien dicho, que un elemento de HTML pueda transformarse en un botón y tener las propiedades que dicho elemento de HTML. Para este post tomaré como ejemplo el transformar una imagen en un botón utilizando la tag <BUTTON> y un poco de css, ya dejo en ustedes el realizar pruebas exhaustivas al respecto.

Bueno, pues la mayoria conocemos al elemento <button> que van dentro de un formulario en sus variantes de tipo Submit, Reset y button (sin acción en el formulario), pues resulta que en XHTML podemos contar ahora con el elemento <button> pero ya no como una tag individual sino como una tag que puede enmarcar a otros elementos, en nuestro caso la tag <img> permitiendo siempre tener los atributos estándar y de eventos que posee dicho elemento (referencia w3c: http://www.w3schools.com/tags/tag_button.asp).

Directo al grano entonces:

Para transformar una imagen en un botón, lo que necesitamos es encerrar la tag

<img width="80" src="http://www.fboiton.com/wp-content/plugins/lazy-gallery/lazy-img.php?file=S2020407.JPG&thumb=1" mce_src="http://www.fboiton.com/wp-content/plugins/lazy-gallery/lazy-img.php?file=S2020407.JPG&thumb=1" />

entre la tag button de la siguiente forma:

<button><img width="80" src="http://www.fboiton.com/wp-content/plugins/lazy-gallery/lazy-img.php?file=S2020407.JPG&thumb=1" mce_src="http://www.fboiton.com/wp-content/plugins/lazy-gallery/lazy-img.php?file=S2020407.JPG&thumb=1" /></button>

y obtendremos entonces el siguiente boton :

Ahora bien, si se dan cuenta tenemos un borde, y un fondo el cual le quita la vista a la imagen, es acá donde entra en juego el css ya sea creando una clase y luego asignarsela al boton o, como lo haremos en este caso, aplicar utilizando el atributo “style” de la siguiente forma:

style="margin: 0px; background-color: transparent; border: none;"

dejando el boton así:

Muchas veces, nos pasa que al aprender un nuevo lenguaje de programacion, nos encontramos con funciones que aparentemente, son simples, y no tienen mucha utilidad, pero con el paso del tiempo, nos damos cuenta, que nos pueden sacar de apuros, e incluso hacen ver nuestro codigo mas limpio, e incluso mas profesional.

Este es el caso, de 3 funciones (2 realmente, la otra es una construccion del lenguaje), muy simples de PHP, que nos pueden ayudar a simplificar nuestro codigo y ahorrarnos tiempo y trabajo.

La primera que veremos es list():

list()  es una construccion del lenguaje, que nos permite asignar valores a un conjunto de variables, en un solo paso, para entenderlo de mejor forma, veamoslo con un ejemplo:

Supongase que tenemos el arreglo:

$arreglo = array(‘solido’, ‘liquido’, ‘gaseoso’);

Si quisieramos asignar cada uno de los valores del arreglo a variables, normalmente hariamos lo siguiente:

$estado1 = $arreglo[0];
$estado2 = $arreglo[1];
$estado3 = $arreglo[2];

Y aqui es donde la funcion list() nos puede a ayudar a hacer nuestro codigo mas facil de leer y tambien mas reducido, veamos como podemos hacerlo:

list($estado1, $estado2, $estado3) = $arreglo;

list() lo que hace es mapear cada uno de los elementos del arreglo, a cada una de las variables enviadas como argumento a la funcion, empezando desde el indice 0 por supuesto. Pero no todo es perfecto, y el unico inconveniente con la funcion list() es que solo funciona para arreglos con indices numericos.

Pero no todo esta perdido, para eso PHP nos ofrece otra alternativa, y es la funcion extract

extract() nos permite mapear cada uno de los elementos de una matriz asociativa a la tabla de simbolos actual, por ejemplo:

Supongamos que tenemos el siguiente arreglo asociativo

$tupla = array(‘nombre’ => ‘Maria’, ‘edad’ => 22, ‘estado_civil’ => ‘soltera’);

Normalmente, lo que hariamos para utilizar individualmente cada uno de los valores del arreglo, seria lo siguiente:

$nombre = $tupla[‘nombre’];
$edad = $tupla[‘edad’];
$estado_civil = $tupla[‘estado_civil’];

Lo cual, es valido, pero un poco tedioso, mas cuando se trata de un arreglo de muchos elementos, cosa que se puede hacer en una sola linea, utlizando la funcion extract(), veamos como:

extract($tupla);
echo “$nombre, $edad, $estado_civil \n”;

Lo que nos retornaria:

Maria, 22, soltera

Como podemos ver, es una funcion simple, pero nos permitiria ahorrar algunas lineas de codigo, y nos seria de mucha utilidad por ejemplo, cuando necesitamos obtener una tupla de la BD, la cual nos es retornada por una funcion, como un arreglo associativo, donde cada llave del arreglo, es el nombre de la columa de la tabla.

Y por ultimo, y no por eso, es la menos importante, la funcion compact():

compact() es todo lo contrario a las funciones list() y extract(), su funcion es construir un arreglo con variables previamente definidas en nuestra tabla de simbolos, por ejemplo:

Supongamos que tenemos los siguientes datos:

$identificacion = array(‘nombre’ => ‘maria’, ‘apellido’ => ‘bonita’);
$direccion = array(‘Pais’ => ‘Guatemala’, ‘Ciudad’ => ‘Guatemala’);
$hijos = array(‘pedro’, ‘pablo’, ‘paco’);

Y quisieramos unirlos todos en un arreglo, que representaria la informacion personal de Maria, normalmente lo hariamos de esta forma:

$info = array(‘identificacion’ => $identificacion, ‘direccion’ => $direccion, ‘hijos’ => $hijos);

Lo cual no esta mal, pero puede ser un poco tedioso, e incluso verse un poco desordenado, cuando se traten de muchos datos, lo cual se simplificaria utilizando la funcion compact(), veamos como:

$info = compact(‘identificacion’, ‘direccion’, ‘hijos’);

Que se ve mucho mas compacto y mas simple de entender. compact() lo que hace en resumidas cuentas, es buscar los argumentos en la tabla de simbolos, y construir un arreglo donde, el argumento, en caso de que exista una variable con ese nombre en la tabla de simbolos, se convierte en la llave y el valor de la variable, como el valor de la llave en el arreglo.

De esta forma, si  imprimimos el contenido de $info obtendriamos:

Array 
( 
    [identificacion] => Array 
        ( 
            [nombre] => maria 
            [apellido] => bonita 
        )     

    [direccion] => Array 
        ( 
            [Pais] => Guatemala 
            [Ciudad] => Guatemala 
        )     

    [hijos] => Array 
        ( 
            [0] => pedro 
            [1] => pablo 
            [2] => paco 
        )     

)

Bueno, espero que este articulo, les haya sido de utilidad, y que pongan en practica alguna de las funciones que aprendimos.

Hola de nuevo, no se si a ustedes les ha pasado , pero a mi al menos cuando comenzaba en esto me paso lo que a continuacion se los detallare, Yo utilizo mucho las librerias de PEAR para el desarrollo de aplicaicones en PHP por su versatilidad, porque no son muy pesadas (en sentido de espacio) y la mayoria trae una documentacion muy decente y me ha facilitado grandemente la existencia para el desarrollo web. Pero vayamos al grano. Read more…

Bueno, para realizar esta tarea hay muchas formas de realizarla, hay muchos scripts y librerias que lo pueden hacer, y esta es otra forma mas en que se puede realizar esto de una manera sencilla y sin despeinarnos, para esto hago uso de 2 clases de PEAR que son HTTP_Upload y la otra es Image_Transform basicamente esto es lo que necesitamos para poder subir y crear nuestro thumbnail de una manera sencilla como veremos a continuacion. Read more…

Hace algun tiempo me topé con la necesidad de realizar un ordenamiento con base a la distancia entre la ubicación del visitante al sitio y los resultados de una busqueda. Esto fue desarrollado para los estados unidos, utilizando una base de datos de codigos postales (zipcodes) donde se tiene ,adicionalmente a la ciudad y estado a los que pertenece cada codigo postal, el geoposicionamiento en coordenadas de latitud y longitud.

Esto se trabajó utilizando Postgres 8.1 y se dejo como un procedimiento almacenado en PL/PGSQL (pl/pgsql store procedure).

La distancia entre dos coordenadas es la base para encontrar esa distancia, antes de utilizar la información hay que tomar en cuenta si la coordenada está dada en radianes o en grados. Vamos a dejar para algun blog matematico esa referencia, y veremos entonces la realización de este cálculo.

Al aquirir una base de datos con información de codigos postales, habran muchos campos por cada zipcode, pero tomemos como base una tabla con al menos codigo postal y su cordenada, es decir, la latitud y longitud que le corresponde en el globo terraqueo.

CREATE TABLE zipcodes(
zipcode text,
latitude double precision,
longitude double precision,
CONSTRAINT pk_zipcodes PRIMARY KEY (zipcode)
);

A este punto cargamos la información de la base de datos con que se cuente y entonces, como consejo, es buena idea entonces crear una tabla precargando la combinacion de codigo postal origen y codigo postal destino junto con la distancia existente entre ambos. Para ello utilizaremos la misma tabla para obtener los datos de ambos codigos postales y para ello utilizaremos la facilidad de los aliases para simular dos tablas, una con los codigos postales origen y otra con los codigos postales destino.

Adicionalmente vale la pena, segun la necesidad del caso, aplicar la restricción de que no se calcule la distancia si en ambos casos es el mismo codigo postal, así como establecer un radio o distancia máximo para calcular. Claro estas condiciones eran practicas para el enfoque que se necesitaba, sin embargo, cada caso puede variar y lo importante es la simulacion de ambas tablas y la formula del calculo de distancia que es de la siguente forma:

  • a es la tabla de codigos postales de destino.
  • b es la tabla de codigos postales de origen.

La formula es:

(3963*acos(sin(a.latitude/57.2958)*sin(b.latitude/57.2958)+cos(a.latitude/57.2958)*cos(b.latitude/57.2958)*cos(a.longitude/57.2958-b.longitude/57.2958)))

Ya con estas consideraciones entonces podemos preparar la consulta: 

select a.zipcode as destination_zipcode, b.zipcode as origin_zipcode, (3963*acos(sin(a.latitude/57.2958)*sin(b.latitude/57.2958)+cos(a.latitude/57.2958)*cos(b.latitude/57.2958)*cos(a.longitude/57.2958-b.longitude/57.2958))) as distance
from zipcode a, zipcode b
where NOT (a.zipcode = b.zipcode) AND (3963*acos(sin(a.latitude/57.2958)*sin(b.latitude/57.2958)+cos(a.latitude/57.2958)*cos(b.latitude/57.2958)*cos(a.longitude/57.2958-b.longitude/57.2958))) <= 50

Y por ultimo generar la tabla final con el pre-calculo de distancias lista para utilizarse:

SELECT
a.zipcode as destination_zipcode,
b.zipcode as origin_zipcode,
(3963*acos(sin(a.latitude/57.2958)*sin(b.latitude/57.2958)+cos(a.latitude/57.2958)*cos(b.latitude/57.2958)*cos(a.longitude/57.2958-b.longitude/57.2958))) as distance
INTO TABLE zipcode_distances
FROM zipcode a, zipcode b
WHERE NOT (a.zipcode = b.zipcode)
AND (3963*acos(sin(a.latitude/57.2958)*sin(b.latitude/57.2958)+cos(a.latitude/57.2958)*cos(b.latitude/57.2958)*cos(a.longitude/57.2958-b.longitude/57.2958))) <= 50

Agregamos un par de índices para evitar recorridos secuenciales en la información

CREATE INDEX idx_zipcode_origin ON zipcode_distances (zipcode_origin);
CREATE INDEX idx_zipcode_destination ON zipcode_distances (zipcode_destination);

y con ello ya podemos realizar el cálculo de las distancias, espero les sea funcional, nos vemos pronto nuevamente!

                              Yo en postgresql no soy un gran conocedor, y a la semana realizo varios store procedures aunque estos no son nada del otro mundo, ni complicados para nada. Pero una cosa que no sabia , y tampoco me habia tomado el tiempo para investigar (un gran error), fue ver como se podian recibir y utilizar los arreglos en un sp en postgres, que realmente no es complicado y pueden llegar a ser muy utiles, también aqui aparte de ver como se usan , también haré un ejemplo de como usarlos y preparar el arreglo desde PHP que también puede llegarles a ser muy util. Read more…

Hace poco escribí un artículo mencionando lo útil que es usar funciones agregadas para agrupar datos en la Base de Datos en vez de hacerlo en PHP por ejemplo.

Hoy escribo su contraparte, una función en PHP que nos permite agrupar un arreglo (array)con cualquier cantidad de llaves (índices).

Por ejemplo veamos el siguiente arreglo de PHP. (La versión con más datos está en el script.)

Array
(

    [0] => Array
        (
            [name] => Juan
            [color] => Azul
            [edad] => 24
        )

    [1] => Array
        (
            [name] => Juan
            [color] => Rojo
            [edad] => 24

        )
    [2] => Array
        (
            [name] => Juan
            [color] => Verde
            [edad] => 24
        )
    [3] => Array
        (
            [name] => Pablo
            [color] => Azul
            [edad] => 25
        )
    [4] => Array
        (
            [name] => Pablo
            [color] => Amarillo
            [edad] => 25
        )
)

Digamos que lo queremos agrupar por el indice “name”.

Con la función:

function groupArray($array,$groupkey)
{
 if (count($array)>0)
 {
 	$keys = array_keys($array[0]);
 	$removekey = array_search($groupkey, $keys);		if ($removekey===false)
 		return array("Clave \"$groupkey\" no existe");
 	else
 		unset($keys[$removekey]);
 	$groupcriteria = array();
 	$return=array();
 	foreach($array as $value)
 	{
 		$item=null;
 		foreach ($keys as $key)
 		{
 			$item[$key] = $value[$key];
 		}
 	 	$busca = array_search($value[$groupkey], $groupcriteria);
 		if ($busca === false)
 		{
 			$groupcriteria[]=$value[$groupkey];
 			$return[]=array($groupkey=>$value[$groupkey],'groupeddata'=>array());
 			$busca=count($return)-1;
 		}
 		$return[$busca]['groupeddata'][]=$item;
 	}
 	return $return;
 }
 else
 	return array();
}

Podemos enviar un arreglo como primer parámetro y luego en el segundo parámetro indicar el indice por el que queremos agrupar. Por ejemplo agrupando por “name” tenemos:

Array
(
    [0] => Array
        (
            [name] => Juan
            [groupeddata] => Array
                (
                    [0] => Array
                        (
                            [color] => Azul
                            [edad] => 24
                        )
                    [1] => Array
                        (
                            [color] => Rojo
                            [edad] => 24
                        )
                    [2] => Array
                        (
                            [color] => Verde
                            [edad] => 24
                        )
                )
        )
    [1] => Array
        (
            [name] => Pablo
            [groupeddata] => Array
                (
                    [0] => Array
                        (
                            [color] => Azul
                            [edad] => 25
                       )
                    [1] => Array
                        (
                            [color] => Amarillo
                            [edad] => 25
                        )
                )
        )
)

o podríamos agrupar por “edad”:

Array
(
    [0] => Array
        (
            [edad] => 24
            [groupeddata] => Array
                (
                    [0] => Array
                        (
                            [name] => Juan
                            [color] => Azul
                        )
                    [1] => Array
                        (
                            [name] => Juan
                            [color] => Rojo
                        )
                    [2] => Array
                        (
                            [name] => Juan
                            [color] => Verde
                        )
                )
        )
    [1] => Array
        (
            [edad] => 25
            [groupeddata] => Array
                (
                    [0] => Array
                        (
                            [name] => Pablo
                            [color] => Azul
                        )
                    [1] => Array
                        (
                            [name] => Pablo
                            [color] => Amarillo
                        )
                )
        )
)

Espero que les sea útil. Estamos en contacto!