varlena
varlena
PostgreSQL Training,
Consulting & Support
General Bits
By A. Elein Mustain


08-Dec-2003 Edición: 53

Archives | General Tidbits | Google General Bits | Docs | Castellano | Português | Subscriptions | Notifications

General Bits General Bits es una publicación periódica escrita con información desde la lista de PostgreSQL, pgsql-general.
Para saber más sobre pgsql-general y PostgreSQL, visite www.PostgreSQL.org.

¿Por qué usar cursores?
[GENERAL] are cursors necessary? 5-Dec-2003

En el programa testlibpq.c, estas cinco sentencias SQL se ejecutan para ilustrar los mecanismos básicos del funcionamiento de los cursores.

   res = PQexec(conn, "BEGIN");
   res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_database");
   res = PQexec(conn, "FETCH ALL in myportal");
   res = PQexec(conn, "CLOSE myportal");
   res = PQexec(conn, "END");
Esto es el equivalente de
	res = PQexec(conn, "select * from pg_database");
¿Por qué querría ejecutar cinco sentencias en lugar de una?

Si los datos retornardos por la consulta son pocos, o si desea obtener todos los datos de una sola vez, entonces la consulta única es la mejor opción. Se seleccionarán todos los resultados y se enviarán al cliente de una sola vez.

Si desea poder desplazarse a través del conjunto de datos sin transmitirlo completo, o si desea transmitirlo de a trozos, lo que desea es usar el cursor.

Los cursores pueden ahorrar ancho de banda tanto de la red como procesamiento en el cliente. Si desea mostrar una página de datos cada vez, y permitir a la aplicación desplazarse hacia adelante y hacia atrás en los datos, entonces el cursor es la solución apropiada. Si desea obtener todos los datos lo más rápido posible, use el SELECT simple.

Así como este ejemplo usa libpq, lo mismo se aplica a todas las interfaces cliente.

Jan Weick: ¿De veras crees que alguien va a querer usar más de 640 filas?
Mike Mascari: ¡Ja ja! ¿Cada una de 1 kB?

Contribuyeron: Mark Harrison mh at pixar.com Richard Huxton dev at archonet.com Jan Wieck JanWieck at Yahoo.com Mike Mascari mascarm at mascari.com Alex Satrapa alex at lintelsys.com.au
Pequeño resumen de 'detalles' en 7.4
Cambios en 7.4 06-Dec-2003

En ediciones anteriores se han mostrado varios de los cambios en 7.4 En la Edición #48, por ejemplo, se mostraron los cambios en postgresql.conf. Esta lista viene de la Documentación de 7.4, Apéndice E.1.2. Se muestra la migración a la versión 7.4 y aquellos cambios que puedan ser sorpresivos o problemáticos. Las Release Notes son lectura obligatoria.

  • La configuración de autocommit fue eliminada del lado del servidor y reimplementada en las aplicaciones y bibliotecas cliente. autocommit ya no está disponible en postgresql.conf.
    Para desactivar autocommit, use \SET AUTOCOMMIT OFF en psql.
  • La redacción de los mensajes ha cambiado sustancialmente en esta versión, y se agregaron códigos de error.
    Si alguna aplicación procesa las cadenas de texto de los mensajes de error, es imperativo que consulte la nueva documentación acerca de los códigos de error en el Apéndice de la documentación de 7.4. Los códigos de error ahora son conformes a los estándares SQL. Esto significa que debe verificarse el código de error y no el mensaje. Es poco probable que los códigos cambien, mientras que los textos pueden variar y además serán diferentes en algunos idiomas.
  • Los JOINs de ANSI se comportan diferente porque están mejor optimizados
    Puede que vea resultados de EXPLAIN diferentes con JOINs ANSI. Si la limpieza (vacuum) y estadísticas están al día, estas consultas deberían estar mejor optimizadas. Si ve un cambio de comportamiento que resulte en una consulta mucho más lenta, debe verificar "los sospechosos de siempre". Verifique los tipos de dato en las calificaciones e índices para asegurarse que coincidan, etc.
  • MOVE/FETCH 0 no hace nada; el código de retorno de MOVE/FETCH 1/0 varía dependiendo del desplazamiento actual del cursor
    Recuerde que las diferencias entre MOVE y FETCH sólo son que FETCH retorna datos, y MOVE no. Ambos mueven el CURSOR a una fila enumerada dentro de un resultado. Anteriormente, FETCH 0 era el dialecto PostgreSQL para indicar FETCH ALL. No se podía usar FETCH 0 o FETCH RELATIVE 0 para extraer la fila actual. El nuevo comportamiento de esos comandos es extraer la fila a la que el cursor está actualmente apuntando.
  • COPY puede procesar archivos separados por retorno de carro y salto de línea, o por sólo retorno de carro. Retornos de carro y saltos de línea literales ya no son aceptados como valores de dato; use \r y \n para reemplazarlos.
    Si espera poder usar archivos antiguos creados por COPY con datos que contengan retornos de carro y saltos de línea literales, es hora de utilizar un guión Perl para convertir esos caracteres a \r o \n.
  • Los espacios al final son eliminados cuando se convierte de CHAR(n) a VARCHAR(n) o TEXT
    Si usa CHAR(n) y espera obtener los espacios al final de las cadenas, asegúrese de no usar conversiones explícitas o implícitas a TEXT o VARCHAR(n), puesto que estos tipos de dato no conservarán dichos espacios.
  • FLOAT(p) mide la precisión 'p' en bits, no dígitos
    Este cambio trae a PostgreSQL de vuelta con el estándar SQL. Verifique sus campos de números en punto flotante si se definen explícitamente con precisión para asegurarse que los está declarando correctamente.
  • 'now' y 'today' ya no se pueden usar como valores por omisión de las columnas; en su lugar se debe usar now()
    Verifique cualquier campo de marca de hora y fecha que tengan now o today como valor por omisión. Cámbielos por la llamada a función now() o las variables especiales current_timestamp, current_date, etc.

    Contribuyeron: Tom Lane tgl at sss.pgh.pa.us, Bruce Momjian pgman at candle.pha.pa.us, elein at varlena.com
    Actualizaciones Concurrentes
    [GENERAL] postgresql locks the whole table! 03-Dec-2003

    Dada una tabla como la que se muestra abajo, se ejecutan dos inserciones paralelas en conexiones separadas usando bloques de transacciones. El segundo INSERT se bloqueará hasta que la primera transacción se complete.

    CREATE TABLE take2
    (
      id serial not null,
      timestamp timestamp NOT NULL DEFAULT now(),
      description text,
      FOREIGN KEY (asset_id) REFERENCES public.asset (id),  
      ON UPDATE CASCADE ON DELETE CASCADE,
      PRIMARY KEY(id)
    );
    
    Conexión 1 Conexión 2
    BEGIN;
    insert into table take2
      values(default, default, 't1');
      BEGIN;
    insert into table take2
      values(default, default, 't2');
    ...otros comandos...   Bloqueado
    ...COMMIT;   Se desbloquea
    inactivo   ...otros comandos ...
    inactivo   ...COMMIT;

    Cuando PostgreSQL hace una referencia a public.asset, crea un lock exclusivo en la tabla — el equivalente de un SELECT FOR UPDATE. Este lock exclusivo puede verse examinando pg_locks.

     relation | database | transaction |  pid  | mode             | granted
    ----------+----------+-------------+-------+------------------+---------
        39356 |    34862 |        NULL | 18671 | AccessShareLock  | t
        39356 |    34862 |        NULL | 18671 | RowExclusiveLock | t
         NULL |     NULL |        9914 | 18671 | ExclusiveLock    | t
        39354 |    34862 |        NULL | 18671 | AccessShareLock  | t
        34886 |    34862 |        NULL | 18671 | AccessShareLock  | t
        34886 |    34862 |        NULL | 18671 | RowShareLock     | t
        16759 |    34862 |        NULL | 18671 | AccessShareLock  | t
    (7 rows)
    
    PostgreSQL no implementa locks compartidos de lectura a nivel de fila (Ed.: ¿aún?)

    Para evitar esta clase de conflicto, asegúrese que sus transacciones son lo más pequeñas posible. Nunca permita interacción del usuario cuando una transacción ha comenzado (los humanos son tan poco confiables :-) Este consejo se mantiene para todos los tipos de transacciones.

    En este caso particular, donde la transacción ya es lo más pequeña que se puede, puede postergar la verificación de llave foránea hasta el momento de comprometer (commit) la transacción. Hay dos maneras de hacer esto, dependiendo de las acciones dentro de la transacción. Puede definir FOREIGN KEY como DEFERRABLE y usar SET CONSTRAINTS ALL DEFERRED durante la transacción. El otro mecanismo es crear las restricciones INITIALLY DEFERRED.

       CREATE TABLE take2
       (
         id serial not null,
         timestamp timestamp NOT NULL DEFAULT now(),
         description text,
         FOREIGN KEY (asset_id) REFERENCES public.asset (id) DEFERRABLE,
         ON UPDATE CASCADE ON DELETE CASCADE,
         PRIMARY KEY(id)
       );
    
    Se puede cambiar el estado de las restricciones con:
       BEGIN
       SET CONSTRAINTS ALL DEFERRED
       insert into table take2
    values(default, default, 't1'); ... COMMIT;

    Contribueron: Dr NoName spamacct11 at yahoo.com, Mike Mascari mascarm at mascari.com, Alistair Hopkins alistair at berthengron.co.uk, Jan Wieck JanWieck at Yahoo.com, Scott Ribe scott_ribe at killerbytes.com, Greg Stark gsstark at mit.edu, Bruce Momjian pgman at candle.pha.pa.us
    Función Reverse
    [SQL] Equivalent of Reverse() functions 27-Nov-2003

    A continuación se presentan dos buenas implementaciones de una función que invierte el orden de un campo de texto. La primera, de Joe Conway, gana en simplicidad, pero requiere plperl. La segunda, de Greg Sabino Mullane, es un buen ejemplo del uso de bucles en plpgsql.

    	CREATE OR REPLACE FUNCTION reverse(TEXT) 
    	RETURNS TEXT AS '
    	   RETURN reverse($_[0]);
    	' LANGUAGE 'plperl';
    
    	CREATE OR REPLACE FUNCTION reverse(TEXT) RETURNS TEXT AS '
    	   DECLARE
    	      original ALIAS FOR $1;
    	      reversed TEXT := \'\';
    	      onechar  VARCHAR;
    	      mypos    INTEGER;
    	   BEGIN
    	      SELECT LENGTH(original) INTO mypos;
    	      LOOP
    	         EXIT WHEN mypos < 1;
    	         SELECT substring(original FROM mypos FOR 1) INTO onechar;
    	         reversed := reversed || onechar;
    	         mypos := mypos -1;
    	      END LOOP;
    	      RETURN reversed;
    	   END
    	' LANGUAGE plpgsql IMMUTABLE RETURNS NULL ON NULL INPUT;
    

    Contribuyeron: Kumar sgnerd at yahoo.com.sg, Joe Conway mail at joeconway.com, greg at turnstep.com
    Número de Filas Afectadas
    [GENERAL] plpgsql question 25-Nov-2003

    Para determinar la cantidad de filas afectadas por una sentencia en una función plpgsql, puede usar GET DIAGNOSTICS. Esto es muy útil si quiere verificar el número de filas que fueron afectadas por una sentencia que afecta muchas filas, ya sea directa o indirectamente a través de un disparador (trigger) o una regla.

       DECLARE
         RowsAffected INTEGER;
       BEGIN
         -- EJECUTAR la sentencia
         GET DIAGNOSTICS RowsAffected = ROW_COUNT;
       END
    

    Contribuyeron: Brian Hirt bhirt mobygames.com, Michael A Nachbaur mike@nachbaur.com


  • Comments and Corrections are welcome. Suggestions and contributions of items are also welcome. Send them in!.
    Copyright A. Elein Mustain 2003, 2004,2005

    Google
    Search General Bits & varlena.com Search WWW