Professional Documents
Culture Documents
2010
informes@eqsoft.net
1. Instalación:
1. Instalación:
1.Instalación
Requerimientos de hardware:
mismos.
1.Instalación
● Enterprise Edition
● Ventajas: muy seguros, actualizaciones centradas principalmente en la
seguridad.
● Desventajas: versiones antiguas incluso al momento de su lanzamiento.
● Desktop Edition
● Ventajas: actualizaciones constantes, se encuentran versiones más
recientes.
● Desventajas: no siempre bien probadas, principalmente se enfocan en
1. Instalación
¿Unixs Libres? :
Instalando......
1. Instalación:
● La mayoría de las distribuciones actuales generan los directorios
necesarios para correr el cluster de la DB, el caso de Ubuntu:
1. Instalación:
● Dentro de /var/lib/postgresql/x.y/main (reemplazar x.y con la versión de
su PostgreSQL) encontrará los directorios de trabajo de la base de datos:
2 archivos adicionales:
● postmaster.opts <-- comando con el que se ejecuto el servicio de la dbms
2. Asegurando el sistema.
2. Asegurando el sistema
2. Asegurando el sistema
Reiniciamos el sistema
Debilidad:
pg_hba.conf, si lo pueden editar nos desasen la seguridad.
Posbles valores:
Configuración básica:
e)Tipo de autenticación
Md5, gss, sspi, krb5, radius, cert, pam son de menos uso y requieren
configuraciones de otros servicios (como Ldap).
Practica
PhpPgAdmin http://phppgadmin.sourceforge.net/
Aplicación Web que nos permite administrar la base de datos, contiene toda
la funcionalidad necesaria para un DBA.
PgAdmin3 http://www.pgadmin.org/
Practica
5. Afinando Postgresql
Los valores que tiene postgresql.conf están pensados para trabajar en una
configuración de hardware mínima.
Shared_buffers nos dice cuanta memoria va a consumir la dbms, se recomeinda que sea al
menos 10% a 25% de la ram disponible en el sistema y hasta un 40%, el valor nunca
puede ser jamas al informado en “/proc/sys/kernel/shmmax”.
Para medir el valor correcto debemos contar cuantas “páginas” caben en la cantidad de
ram asignada en shared_buffers, una página generalmente mide 8kb, por ejemplo si
tenemos 4gb de ram asignaremos 400mb (400mb no es exacto el 10%):
En postgresql.conf ponemos:
shared_buffers=400mb
5. Afinando Postgresql
5. Afinando Postgresql
work_mem es el espacio de memoria que se usará para los ordenamientos de los datos
cuando se ejecutan consultas, no existe una formula exacta de cálculo dependerá de que
tanta data se mueva en las consultas que ejecutamos y cual es la concurrencia de
ejecución de las consultas.
La regla dice, si las consultas se ejecutan con poca concurrencia entonces asignar
entre 2% a 4% de la ram disponible será ideal, pero si la concurrencia es alta
entonces debe asignarse menos memoria debido a que cada consulta consume la misma
cantidad de ram.
5. Afinando Postgresql
c)temp_buffers
Es la cantidad de memoria que tendrá asignada cada conexión al dbms para manejo de
tablas temporales, esta no se libera hasta que la sesión muera, cada sesión podría
manejar un tamaño difereten y mayor al de default (8mb) pero solo hasta antes de
generar la primera tabla temporal.
d)max_locks_per_transaction
e)max_connections
Configuración básica:
5. Afinando Postgresql
f)random_page_cost
g)effective_cache_size
Setea el tamaño de cache en RAM que se usará en una consulta, el valor por defecto es
128Mb, un valor alto facilitará el uso de índices, un valor bajo hará que se prefiera
el uso de búsquedas secuenciales, se recomienda como máximo 50% del total de la RAM.
Configuración básica:
5. Afinando Postgresql
h)statement_timeout
Configura cuanto tiempo puede demorar un query en ejecutarse, evita que se lancen
querys extremadamente pesados que demoren mucho tiempo en ejecutarse, por defecto es 0
(desactivado) pero se expresa en milisegundos, OjO configurarlo afectará todos los
querys.
1. Objetos convencionales en la DB
PostgreSQL permite crear objetos comunes de uan base de datos tales como:
●Base datos
●Tablas
●Vistas
●Schemas
●Usuarios
●Grupos
●Roles
●Rules
● Etc, etc.
1. Objetos convencionales en la DB
a) Base datos
1. Objetos convencionales en la DB
a) Base datos
1. Objetos convencionales en la DB
b) Tablas
Crear una tabla de un Type nos ayuda a tener estructuras pre-construidas para los
datos.
prueba4=# create type tpy_usuario as (id integer, password char(25), nombre
varchar(100));
prueba4=# create table tbl_usuario of tpy_usuario;
prueba4=# select * from tbl_usuario;
id | password | nombre
++
(0 rows)
prueba4=# drop type tpy_usuario cascade;
NOTICE: drop cascades to table tbl_usuario
DROP TYPE
1. Objetos convencionales en la DB
b) Tablas
prueba4=# create table tbl_usuario2 ( id serial, datos_unicos tpy_usuario);
prueba4=# insert into tbl_usuario2 values (1,(1,'password','nombre'));
prueba4=# insert into tbl_usuario2 (datos_unicos.id, datos_unicos.password,
datos_unicos.nombre) values (2, 'password2', 'nombre2');
prueba4=# select * from tbl_usuario2;
id | datos_unicos
+
1 | (1,"password ",nombre)
1 | (2,"password2 ",nombre2)
prueba4=# select (datos_unicos).password from tbl_usuario2;
password
password
password2
1. Objetos convencionales en la DB
b) Tablas
Borrar el type hará que se pierdan todas los campos creados a partir de este en todas
las tablas donde se haya usado.
prueba4=# drop type tpy_usuario cascade;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table tbl_usuario
drop cascades to table tbl_usuario2 column datos_unicos
DROP TYPE
prueba4=# select * from tbl_usuario2;
id
1
1
1. Objetos convencionales en la DB
b) Tablas
prueba4=# create table tbl_padre (id integer, nombre varchar(100));
prueba4=# create table tbl_hijo (direccion varchar(200)) INHERITS (tbl_padre);
CREATE TABLE
prueba4=# select * from tbl_hijo;
id | nombre | direccion
++
(0 rows)
prueba4=# drop table tbl_padre cascade;
NOTICE: drop cascades to table tbl_hijo
DROP TABLE
LIKE genera el mismo efecto pero al borrar la tabla padre no se pierde la estructura.
prueba4=# create table tbl_hijo2 (like tbl_padre);
prueba4=# create table tbl_hijo3 (like tbl_padre, casa varchar(300));
1. Objetos convencionales en la DB
c) Vistas
1. Objetos convencionales en la DB
d) Schemas
Los esquemas son contenedores de objetos dentro de una db, por default
trabajamos en el schema PUBLIC.
1. Objetos convencionales en la DB
e) Domain
prueba3=# create domain dmn_adulto as integer check (value > 18 and value < 60);
prueba3=# create table tbl_persona(id int, edad dmn_adulto);
1. Objetos convencionales en la DB
f) Sequence
prueba4=# create sequence contador cache 100; <-- reserva 100 números en
Cache
1. Objetos convencionales en la DB
Practica
2. Accesos
a) Los roles
2. Accesos
b) Los permisos
Por defecto uno tiene permisos totales sobre los objetos que haya creado
con su propio rol, ningún rol puede acceder a un objeto creado por otro
rol.
Como usr1
prueba4=> create table tbl_prueba ( id integer);
Como usr2
prueba4=> select * from tbl_prueba;
ERROR: permission denied for relation tbl_prueba
2. Accesos
●GRANT ON TABLE
●GRANT ( column ) ON TABLE
●GRANT ON SEQUENCE
●GRANT ON DATABASE
●GRANT ON FOREIGN DATA WRAPPER <-- para conexiones Dlink
●GRANT ON FOREIGN SERVER <-- para conexiones Dlink
●GRANT ON FUNCTION
●GRANT ON LANGUAGE
●GRANT ON LARGE OBJECT
●GRANT ON SCHEMA
●GRANT ON TABLESPACE
●GRANT role_name TO role_name
2. Accesos
●GRANT ON TABLE
●GRANT ( column ) ON TABLE
Como usr3
2. Accesos
●GRANT ON TABLE
●GRANT ( column ) ON TABLE
Como usr3
2. Accesos
●GRANT ON DATABASE
●GRANT ON SCHEMA
Como superusuario:
2. Accesos
Sigue más o menos la misma estructura de GRANT salvo que en vez de dar
permisos los retira.
2. Accesos
Para ver los accesos superiores de un rol puede utilizar este comando:
2. Accesos
OjO, todas las claves por defecto se guardan encriptadas en MD5 (lo cual
es relativamente seguro, pero no totalmente) sin embargo cerciórese de no
generar claves sin encriptación ya que fácilmente se puede ver estas con el
siguiente comando:
template1=# create role usr8 unencrypted password 'se_me_ve_todo' login;
template1=# select usename, passwd from pg_shadow;
usename | passwd
+
postgres | md54abfba9c735cfbc34d97b56a593120c0
dbadmin | md5695c0e25f6fe7c4ce633c67292190b90
pgsql |
usr1 | md51575823e236277b188fdd5d691aa8d08
usr3 | md5f06099b5e97add7ed510d76e24146f1e
usr8 | se_me_ve_todo
2. Accesos
PRACTICA
a) Tablespace
a) Tablespace
En consola de PgSQL:
template1=# create tablespace ts_prueba location '/home/tablespace';
template1=# create table tbl_prueba(id serial) tablespace ts_prueba;
Como root:
root@depeche:/home/tablespace# ls -la
total 16
drwx------ 3 postgres postgres 4096 2010-10-04 12:43 .
drwxr-xr-x 4 root root 4096 2010-10-04 12:35 ..
drwx------ 2 postgres postgres 4096 2010-10-04 12:43 1 <-- directorio de la data
-rw------- 1 postgres postgres 4 2010-10-04 12:41 PG_VERSION
a) Tablespace
Podemos usar esta funcionalidad con:
●Base de datos
●Tablas
●Indices
Se recomienda que los Tablespaces creados en discos virtuales ó memorias USB solo
almacenen objetos de la db de los cuales se puedo presncindir como tablas temporales,
esto debido a que son muy volátiles y fácil de corromper o perder los datos (por
ejemplo tener un tablespace en disco virtual desaparece si alguien reinicia el
servidor).
Los tablespace de índices tienen una muy buena persormanse en discos SSD.
b) Tablas particionadas
Las tablas particionadas nos permiten crear diferentes espacios de almacenamiento para
una data en común.
b) Tablas particionadas
template1=# create table tbl_hija30(descripcion varchar(100)) inherits (tbl_padre);
template1=# insert into tbl_hija30 values('30.01', 'orden');
template1=# select * from tbl_hija30;
cuenta | descripcion
------------+-------------
30.01 | orden
b) Tablas particionadas
template1=# create table tbl_hija50( check (substr(cuenta,1,1) = '5' )) inherits (tbl_padre);
template1=# insert into tbl_hija50 values('540.01');
b) Tablas particionadas
Supongamos que tenemos el caso de una tabla de movimientos contables, con millones de
registros por mes y decidimos crear una tabla por mes, pero es tanta data que
necesitamos grabarla en diferentes unidades físicas de almacenamiento, aplicamos:
template1=# create table tbl_hija60( check (substr(cuenta,1,1) = '6' )) inherits (tbl_padre)
tablespace ts_prueba;
CREATE TABLE
A cada tabla “hija” podemos aplicarle sus propios índices y relaciones, al igual que a
la tabla padre.
template1=# create index idx_padre on tbl_padre(cuenta);
CREATE INDEX
template1=# create index idx_padre2 on tbl_padre(cuenta) tablespace ts_prueba;
CREATE INDEX
b) Tablas particionadas
Podemos crear rules o triggers para manejar la correcta desviación de los datos cuando
se intenta grabar en la tabla principal ó padre.
b) Tablas particionadas
PRACTICA
Los Types son estructuras de datos definidas por el usuario, además de los ejemplos especificados en las
láminas 35 a 37 también podemos:
template1=# create function fn_cuenta () returns setof tpy_cuenta as $$ select cuenta from tbl_padre
$$ language sql;
CREATE FUNCTION
2. Tipos de datos
a)Tipos de datos numéricos
●smallint
●integer
●bigint
●decimal
●numeric
2. Tipos de datos
b)Tipos de datos caractér
●interval
2. Tipos de datos
d)Tipos direcciones de red
2. Tipos de datos
PRACTICA
El tipo de datos Vector nos permite almacenar cadenas en lexemas para facilitar las
búsquedas de cadenas específicas en textos muy largos.
prueba=# insert into tbl_vector values ( 'esta es una pruena de un vector repitiendo la palabra vector','esta es una
prueba de un vector repitiendo la palabra vector');
prueba=# insert into tbl_vector values ( 'esta es una pruena de un vector repitiendo la palabra vector','esta es una
prueba de un vector repitiendo la palabra vector');
prueba=# insert into tbl_vector values ( 'árbol y vector añade acentos y eñes','árbol y vector añade acentos y eñes');
prueba=# insert into tbl_vector values ( 'las ratas y los ratones estan ratoneando un rato', 'las ratas y los ratones
estan ratoneando un rato');
^
prueba=# select * from tbl_vector;
campo1 | campo2
--------------------------------------------------------------+---------------------------------------------------------------------------
esta es una pruena de un vector | 'de' 'es' 'esta' 'prueba' 'un' 'una' 'vector'
esta es una pruena de un vector repitiendo la palabra vector | 'de' 'es' 'esta' 'la' 'palabra' 'prueba' 'repitiendo' 'un' 'una' 'vector'
árbol y vector añade acentos y eñes | 'acentos' 'añade' 'eñes' 'vector' 'y' 'árbol'
las ratas y los ratones estan ratoneando un rato | 'estan' 'las' 'los' 'ratas' 'rato' 'ratoneando' 'ratones' 'un' 'y'
prueba=# select campo1 from tbl_vector where to_tsvector(campo1) @@ to_tsquery('vector & palabra');
campo1
--------------------------------------------------------------
esta es una pruena de un vector repitiendo la palabra vector
Para una mejor administración de los datos debemos especificar el idioma en el cual
estamos añadiendo los datos.
prueba=# insert into tbl_vector values('esto añade soporte en español', to_tsvector('pg_catalog.spanish','esto añade
soporte en español'));
prueba=# select campo2 from tbl_vector;
campo2
---------------------------------------------------------------------------
'acentos' 'añade' 'eñes' 'vector' 'y' 'árbol'
'añad':2 'español':5 'soport':3
prueba=# select campo1 from tbl_vector where campo2 @@ to_tsquery('añada & vector');
campo1
--------
(0 filas)
prueba=# select campo1 from tbl_vector where campo2 @@ to_tsquery('!vec & añada');
campo1
-------------------------------
esto añade soporte en español
Los vectores se pueden indexar, para ellos existe el tipo de índice GIN.
prueba=# create index idx_vector3 on tbl_vector using gin(campo2);
CREATE INDEX
En caso de que los textos se actualicen demasiado seguido entonces podemos crear un
trigger para que actualice la columna donde están guardados los lexemas.
Los OIDs son identificadores únicos de los objetos en la base de datos, incluso cada
registro tiene un OID propio que jamas se repite en ninguna otra tabla.
Ahora por defecto ya no se crean OIDs para data, esto debido a que en volúmenes muy
grandes de datos los OIDs podrían llegar a ser insuficientes y es por ello que se
prescinde de ellos por defecto.
PostgreSQL permite guardar binarios dentro de una tabla de muchos gigas de extensión,
estos files no se guardan directamente dentro de la tabla creada sino en un ambiente
especial y se apunta el oid del file para acceder a este.
prueba4=# update tbl_files set file = null; <-- borramos el link pero no la data
PRACTICA
4. Sentencias SQL
a)Insert
prueba=# create table tbl_simple ( id serial, nombre varchar(10));
NOTICE: CREATE TABLE creará una secuencia implícita «tbl_simple_id_seq» para la columna serial
«tbl_simple.id»
CREATE TABLE
4. Sentencias SQL
a)Insert
NOTICE: CREATE TABLE creará una secuencia implícita «tbl_simple2_id_seq» para la columna serial
«tbl_simple2.id»
CREATE TABLE
prueba=# insert into tbl_simple2 ( nombrE) select nombre from tbl_simple returning id;
id
----
5
6
7
8
(4 filas)
4. Sentencias SQL
b)Update
prueba=# select * from tbl_simple;
id | nombre
----+---------
1 | ernesto
2 | juan
3 | 111
4 | 10chars
prueba=# update tbl_simple set nombre = (select tbl_simple2.nombre from tbl_simple2 where
tbl_simple2.id = tbl_simple.id);
UPDATE 4
4. Sentencias SQL
b)Update
prueba=# update tbl_simple2 set nombre = '2'||nombre;
prueba=# update tbl_simple set nombre = a.nombre from ( select id, nombre from tbl_simple2) as a
where tbl_simple.id = a.id;
UPDATE 4
prueba=# update tbl_simple set nombre = a.nombre from ( select id, nombre from tbl_simple2) as a
where tbl_simple.id = a.id returning tbl_simple.*;
id | nombre
----+-----------
1 | 21ernesto
2 | 21juan
3 | 21111
4 | 2110chars
4. Sentencias SQL
b)Update
prueba=# update tbl_simple set nombre = a.nombre from ( select tbl_simple2.id, tbl_simple2.nombre
from tbl_simple2 join tbl_simple on tbl_simple.id = tbl_simple2.id) as a where a.id=tbl_simple.id
returning tbl_simple.*;
id | nombre
----+------------
1 | 321ernesto
2 | 321juan
3 | 321111
4 | 32110chars
(4 filas)
4. Sentencias SQL
c)Delete
prueba=# delete from tbl_simple using tbl_simple2 where tbl_simple.id=tbl_simple2.id returning
tbl_simple.*;
id | nombre
----+------------
1 | 321ernesto
2 | 321juan
3 | 321111
4 | 32110chars
4. Sentencias SQL
d)Copy
4. Sentencias SQL
d)Copy
prueba=# select * from tbl_simple;
id | nombre
----+--------
(0 filas)
http://www.postgresql.org/docs/9.0/interactive/sql-copy.html
4. Sentencias SQL
e)Select - OVER
prueba=# select * from tbl_window;
mes | nombre | sueldo
--------+---------+--------
201001 | ernesto | 10
201002 | ernesto | 11
201003 | ernesto | 12
201001 | juan | 13
201003 | juan | 15
201002 | juan | 14
prueba=# select nombre, mes, sueldo, sum(sueldo) as sueldo_total over (partition by nombre) from tbl_window;
nombre | mes | sueldo | sueldo_total
---------+--------+--------+-------------
ernesto | 201001 | 10 | 33
ernesto | 201002 | 11 | 33
ernesto | 201003 | 12 | 33
juan | 201001 | 13 | 42
juan | 201003 | 15 | 42
juan | 201002 | 14 | 42
prueba=# select nombre, mes, sueldo, sum(sueldo) over (partition by nombre) sueldo_total, sum(sueldo) over (partition by
nombre) / 3 as sueldo_promedio, (sum(sueldo) over (partition by nombre) / 3 )- sueldo as desviacion_promedio from
tbl_window;
nombre | mes | sueldo | sueldo_total | sueldo_promedio | desviacion_promedio
---------+--------+--------+--------------+-----------------+---------------------
ernesto | 201001 | 10 | 33 | 11 | 1
ernesto | 201002 | 11 | 33 | 11 | 0
ernesto | 201003 | 12 | 33 | 11 | -1
juan | 201001 | 13 | 42 | 14 | 1
juan | 201003 | 15 | 42 | 14 | -1
juan | 201002 | 14 | 42 | 14 | 0
4. Sentencias SQL
e)Select - OVER
prueba=# select nombre, mes, sueldo, sum(sueldo) over (partition by nombre order by nombre desc, mes ) from tbl_window;
nombre | mes | sueldo | sum
---------+--------+--------+-----
juan | 201001 | 13 | 13
juan | 201002 | 14 | 27
juan | 201003 | 15 | 42
ernesto | 201001 | 10 | 10
ernesto | 201002 | 11 | 21
ernesto | 201003 | 12 | 33
prueba=# select nombre, mes, sueldo, rank() over (partition by nombre order by sueldo desc) from tbl_window;
nombre | mes | sueldo | rank
---------+--------+--------+------
ernesto | 201003 | 12 | 1
ernesto | 201002 | 11 | 2
ernesto | 201001 | 10 | 3
juan | 201003 | 15 | 1
juan | 201002 | 14 | 2
juan | 201001 | 13 | 3
prueba=# select nombre, sueldo, mes, sum(sueldo) over ventana, avg(sueldo) over ventana from tbl_window window ventana
as (partition by nombre);
nombre | sueldo | mes | sum | avg
---------+--------+--------+-----+---------------------
ernesto | 10 | 201001 | 33 | 11.0000000000000000
ernesto | 11 | 201002 | 33 | 11.0000000000000000
ernesto | 12 | 201003 | 33 | 11.0000000000000000
juan | 13 | 201001 | 42 | 14.0000000000000000
juan | 15 | 201003 | 42 | 14.0000000000000000
juan | 14 | 201002 | 42 | 14.0000000000000000
4. Sentencias SQL
4. Sentencias SQL
4. Sentencias SQL
A simple vista parecen iguales, pero en el caso de Limit en siguientes ocasiones donde
se ejecute el query el orden en el que tome los datos no necesariamente será el mismo
(en el que se almacenaron en la db) a menos que se use un ORDER BY, para FETCH el
orden siempre sera igual.
4. Sentencias SQL
FOR UDATE bloqueda el acceso a los registros que se solicitan de tal manera que el
query no desbloqueara los registros hasta que haya culminado la transacción en curso.
prueba=# select * from tbl_simple2 limit 2 for update;
4. Sentencias SQL
e)Select – WITH
prueba=# with suma as ( select nombre, sum(id) from tbl_simple2 group by nombre order by 2 desc limit 2) select nombre,
id from tbl_simple2 where nombre in (select nombre from suma);
nombre | id
---------+----
ernesto | 10
juan | 20
ernesto | 12
4. Sentencias SQL
e)Select – SIMILAR TO
prueba4=# select * from log_regla;
fecha | id | nombre | estado
+++
20101008 20:26:37.200866 | 2 | Ernesto | I
20101008 20:49:24.691783 | 8 | pedro | I
20101008 21:00:08.529349 | 1 | alejandro | U
20101008 21:21:55.82194 | 5 | pepelucho | U
prueba4=# select * from log_regla where nombre similar to '%(a|c)%'; < contiene a ó c
fecha | id | nombre | estado
+++
20101008 21:00:08.529349 | 1 | alejandro | U
20101008 21:21:55.82194 | 5 | pepelucho | U
prueba4=# select * from log_regla where nombre similar to '%(x|f)%';
fecha | id | nombre | estado
+++
4. Sentencias SQL
e)Select – SIMILAR TO
prueba4=# select * from log_regla where nombre similar to '(d|f)%'; < inicia con d ó f
fecha | id | nombre | estado
+++
(0 rows)
prueba4=# select * from log_regla where nombre similar to '(p|f)%';
fecha | id | nombre | estado
+++
20101008 20:49:24.691783 | 8 | pedro | I
20101008 20:49:43.711889 | 9 | pedro | I
20101008 21:21:55.82194 | 5 | pepelucho | U
20101008 21:22:06.759216 | 5 | pepelucho1 | U
prueba4=# select * from log_regla where nombre similar to '[az]{5}'; < alfabéticos de al menos
fecha | id | nombre | estado 5 letras
+++
20101008 20:49:24.691783 | 8 | pedro | I
20101008 20:49:43.711889 | 9 | pedro | I
4. Sentencias SQL
PRACTICA
1. Transacciones
El modelo ACID
1. Transacciones
La estructura básica de una transacción es:
BEGIN
--- Querys ---
COMMIT ó si hay problemas ROLLBACK
prueba=# create table tbl_transaccion ( id integer);
prueba=# begin;
prueba=# insert into tbl_transaccion values(1);
prueba=# insert into tbl_transaccion values(2);
prueba=# commit;
prueba=# select * from tbl_transaccion;
id
----
1
2
prueba=# begin;
prueba=# insert into tbl_transaccion values(3);
prueba=# insert into tbl_transaccion values(4);
prueba=# rollback;
prueba=# select * from tbl_transaccion;
id
----
1
2
1. Transacciones
SAVEPOINT, nos permite determinar en que punto deseamos ir grabando la información que
vamos procesando antes de ejecutar un rollback en caso de problemas.
prueba5=# begin;
prueba5=# insert into tbl_usuario (nombre) values ('manuel');
prueba5=# insert into tbl_usuario (nombre) values ('rosa');
prueba5=# savepoint sv_uno;
prueba5=# insert into tbl_usuario (nombre) values ('carmen');
prueba5=# rollback to savepoint sv_uno;
prueba5=# insert into tbl_usuario (nombre) values ('lucia');
prueba5=# commit;
1. Transacciones
El comando LOCK nos permite bloquear una tabla.
prueba=# begin;
BEGIN
prueba=# lock tbl_transaccion in exclusive mode;
LOCK TABLE
Sin embargo si hacemos un “select” a esa tabla en otra consola la información procesará sin ningún
problema, los niveles de bloqueo permiten ejecutar cierto tipo de operaciones.
1. Transacciones
Tipos de LOCK:
●ACCESS SHARE
●ROW SHARE
●ROW EXCLUSIVE
●SHARE
●EXCLUSIVE
●ACCESS EXCLUSIVE
http://www.postgresql.org/docs/9.0/interactive/explicit-locking.html
Hay que se cuidadoso con este comando, todas las operaciones a una DB ejecutan algún
tipo de lock pre-definido y entre ellos pueden llegar a colisionar
1. Transacciones
Para ver los querys que están ejecutando los locks:
SELECT
waiting.locktype AS waiting_locktype,
waiting.relation::regclass AS waiting_table,
waiting_stm.current_query AS waiting_query,
waiting.mode AS waiting_mode,
waiting.pid AS waiting_pid,
other.locktype AS other_locktype,
other.relation::regclass AS other_table,
other_stm.current_query AS other_query,
other.mode AS other_mode,
other.pid AS other_pid,
other.granted AS other_granted
FROM
pg_catalog.pg_locks AS waiting
JOIN pg_catalog.pg_stat_activity AS waiting_stm ON ( waiting_stm.procpid = waiting.pid )
JOIN pg_catalog.pg_locks AS other ON ((waiting."database" = other."database" AND waiting.relation = other.relation)
OR waiting.transactionid = other.transactionid )
JOIN pg_catalog.pg_stat_activity AS other_stm ON (other_stm.procpid = other.pid)
WHERE NOT waiting.granted AND waiting.pid <> other.pid
2. Funciones
Las funciones en PostgreSQL son el equivalente a los store procedures además de
funcionar como funciones en si mismas.
PostgreSQL soporta una variedad muy grande de lenguajes de programación para escribir
funciones (java, perl, python, php, ruby, c, etc.) sin embargo el lenguaje de
programación más desarrollado es Pl/PgSql.
Desde la versión 8.3 – 8.4 PostgreSQL ya incluye como lenguaje por defecto el Pl/PgSQL
cuando creamos una DB, pero si requerimos instalarlo manualmente existen 2 opciones:
2. Funciones - Estructura
prueba5=# create or replace function <-- declaración de ingreso de una función
f_prueba (parametro integer) <-- nombre y parámetros
returns integer as <-- declaración de tipo de dato que se retornará
Prueba5-# $$ <-- delimitador de inicio/fin de código
prueba5$# Declare <-- zona de declaración de variables internas que
prueba5$# variable integer := 10; usará la función
prueba5$# Begin <-- inicio de código
prueba5$# return parametro * variable; <-- código de la función
prueba5$# end; <-- fin de código
Prueba5$# $$
prueba5-# language plpgsql; <-- lenguaje “pl” que se está usando
CREATE FUNCTION
2. Funciones - Estructura
Podemos tener “bloques” de código anidados:
return parametro;
end;
$$
language plpgsql;
Los bloques anidados NO SON transacciones anidadas, solo se ponen con fines de
agrupamiento.
prueba5=# create table tbl_personas (edad int, nombre varchar(100), ciudad varchar(100));
create or replace function f_prueba2 (p_edad integer, p_nombre varchar) returns integer as
$$
Declare
v_ciudad CONSTANT varchar := 'LIMA';
v_registro tbl_personas%ROWTYPE;
v_nombre tbl_personas.nombre%TYPE;
Begin
insert into tbl_personas(edad, nombre, ciudad) values (p_edad,p_nombre, v_ciudad);
select * into v_registro from tbl_personas where nombre = p_nombre;
select nombre into v_nombre from tbl_personas where nombre = p_nombre;
return 1;
end;
$$
language plpgsql;
create or replace function f_prueba3 (p_talla numeric, p_peso numeric) returns integer as
$$
Declare
v_talla_peso tpy_persona;
v_registro record;
Begin
v_talla_peso.altura := p_talla;
v_talla_peso.peso := p_peso;
2. Funciones – Parametros
En Pl/PgSql podemos declarar parametros de entrada (IN) y de salida (OUT), ó
parámetros INOUT.
create or replace function f_prueba4 ( p_quienes varchar, OUT p_nombre varchar, OUT p_apellido varchar) returns record
as
$$
Begin
p_nombre := substr(p_quienes,1,8);
p_apellido := substr(p_quienes,10,8);
end;
$$ language plpgsql;
2. Funciones – Parametros
create or replace function f_prueba6 (id integer, OUT r1 refcursor, OUT r2 refcursor) returns record as
$$
begin
open r1 for select * from tbl_personas;
open r2 for select * from tbl_padre;
return;
end;
$$ language plpgsql;
2. Funciones – Parametros
prueba5=# select * from f_prueba7();
NOTICE: Tabla 1, data: 15 juan LIMA
NOTICE: Tabla 2, data: 00.01
NOTICE: Tabla 2, data: 10.01
NOTICE: Tabla 2, data: 10.02
NOTICE: Tabla 2, data: 40.01
NOTICE: Tabla 2, data: 540.01
f_prueba7
-----------
1
(1 fila)
2. Funciones – Parametros
Podemos crear funciones con N número de parametros (pero siempre del mismo tipo), se
soporta anyelement, anyarray, anynonarray ó anyenum.
2. Funciones – Perform
Permite ejecutar querys/funciones sin necesidad de procesar devolución de datos
create or replace function f_prueba8 (numero integer) returns integer as
$$
BEGIN
update tbl_prueba set id = id * numero; return 1;
END;
$$ language plpgsql;
2. Funciones – STRICT
2. Funciones – STRICT
prueba4=# select * from f_prueba10(1);
NOTICE: )No hay datos B: 1 <NULL>
f_prueba10
------------
4
● TYPES < declarados por el usuario
● RECORD < estructura no definida de datos
● SETOF RECORD < conjunto de estructuras de datos
● (TABLA) < podemos especificar el nombre de una tabla
● REFCURSOR < como SETOF RECORD
prueba4=# create type tpy_prueba as( id integer, nombre varchar(100));
create or replace function f_prueba11 (p_numero integer, p_nombre varchar) returns tpy_prueba as
$$
DECLARE
data tpy_prueba;
BEGIN
data.id := p_numero; data.nombre := p_nombre; return data;
END;
$$language plpgsql;
prueba4=# select * from f_prueba11(10,'ernesto');
id | nombre
+
10 | ernesto
En este caso que varios registros cumplan la condición retornará solo uno de ellos,
sin preferencia alguna.
prueba4=# select * from f_prueba13() as (id integer, nombre varchar);
id | nombre
+
10 | Dato 10
20 | Dato 20
23 | Dato 23
10 | Dato 10
10 | Dato 10
prueba4=# select * from f_prueba15();
id | nombre
+
10 | Dato 10
20 | Dato 20
23 | Dato 23
10 | Dato 10
10 | Dato 10
prueba4=# begin; select * into resultado from f_prueba16('data'); fetch all from data;
BEGIN
SELECT 1
id | nombre
+
10 | Dato 10
20 | Dato 20
23 | Dato 23
10 | Dato 10
10 | Dato 10
(5 rows)
prueba4=# commit;
COMMIT
create or replace function f_prueba13_3() returns setof tpy_data as
$$
BEGIN
return query select id,nombre from tbl_prueba;
return;
END;
$$
language plpgsql;
prueba4=# select * from f_prueba13_3();
id | nombre
+
10 | Dato 10
20 | Dato 20
23 | Dato 23
10 | Dato 10
10 | Dato 10
(5 rows)
prueba4=# select * from f_prueba13_4();
p_id | p_nombre
+
10 | Dato 10
20 | Dato 20
23 | Dato 23
10 | Dato 10
10 | Dato 10
(5 rows)
Return query ó return query execute nos permiten devolver set de datos de la ejecución
directa de un query, en el segundo caso puede ser un query dinámico.
create or replace function f_prueba20() returns setof tpy_data2 as
$$
BEGIN
return query select a.id,a.fecha,b.id,b.monto from factura_cab a, factura_det b where a.id =
b.fac_id;
return;
END;
$$
language plpgsql;
create or replace function f_prueba20_2() returns setof tpy_data2 as
$$
BEGIN
return query execute 'select a.id,a.fecha,b.id,b.monto from factura_cab a, factura_det b where
a.id = b.fac_id';
return;
END;
$$
language plpgsql;
create or replace function f_prueba22() returns setof tpy_data3 as
$$
DECLARE
data tpy_data3;
BEGIN
FOR data IN select a.id,a.fecha,b.id,b.monto, '' from factura_cab a, factura_det b where a.id =
b.fac_id
LOOP
if data.monto > 200 then data.mensaje = 'Muy caro'; end if;
RETURN NEXT data;
END LOOP;
return;
END;
$$ language plpgsql;
prueba4=# select * from f_prueba22();
id | fecha | id_det | monto | mensaje
++++
1 | 20100101 | 1 | 100.20 |
1 | 20100101 | 2 | 100.30 |
2 | 20100102 | 3 | 200.30 | Muy caro
3 | 20100103 | 4 | 2500.30 | Muy caro
2. Funciones
PRACTICA
CASE p_valor
WHEN 1 THEN raise notice 'CASE Valor UNO';
WHEN 2,3 THEN raise notice 'CASE Valor DOS o TRES';
WHEN 2,3,4 THEN raise notice 'CASE Valor DOS, TRES o CUATRO';
ELSE raise notice 'CASE Valor %:', p_valor;
END CASE;
CASE
WHEN p_valor >= 1 and p_valor <= 6 THEN
raise notice 'CASE2 Valor entre UNO y SEIS';
WHEN p_valor >=1 and (p_valor % 2) = 0 THEN
raise notice 'CASE2 Valor mayor a UNO y PAR';
ELSE
raise notice 'CASE2 Valor %:', p_valor;
END CASE;
END;
$$ language plpgsql;
create or replace function f_loop(p_valor int) returns void as
$$
DECLARE
contador integer := 0;
BEGIN
LOOP
contador := contador + 1;
RAISE NOTICE 'Valor %:', contador;
EXIT WHEN contador >= 3;
IF contador >= p_valor THEN
RAISE NOTICE 'Salió por el IF';
EXIT;
END IF;
END LOOP;
END;
$$
language plpgsql;
prueba4=# select f_loop(2); prueba4=# select f_loop(5);
NOTICE: Valor 1: NOTICE: Valor 1:
NOTICE: Valor 2: NOTICE: Valor 2:
NOTICE: Salió por el IF NOTICE: Valor 3:
CONTINUE WHEN contador < 5; fuerza el loop
RAISE NOTICE 'Entro al continue :%', contador;
IF contador >= p_valor THEN
RAISE NOTICE 'Salió por el IF'; prueba4=# select f_loop(8);
EXIT; NOTICE: CONTADOR :1
END IF; NOTICE: CONTADOR :2
NOTICE: CONTADOR :3
END LOOP; NOTICE: CONTADOR :4
END; NOTICE: CONTADOR :5
$$ prueba4=# select f_loop(3); NOTICE: Entro al continue :5
language plpgsql; NOTICE: CONTADOR :1 NOTICE: CONTADOR :6
NOTICE: CONTADOR :2 NOTICE: Entro al continue :6
NOTICE: CONTADOR :3 NOTICE: CONTADOR :7
NOTICE: CONTADOR :4 NOTICE: Entro al continue :7
NOTICE: CONTADOR :5 NOTICE: CONTADOR :8
NOTICE: Entro al continue :5 NOTICE: Entro al continue :8
NOTICE: Salió por el IF NOTICE: Salió por el IF
create or replace function f_while(p_valor int) returns void as
$$
DECLARE
contador integer := 0;
BEGIN
WHILE contador <= p_valor LOOP
contador := contador + 1;
IF contador < 5 THEN
CONTINUE;
END IF;
RAISE NOTICE ' Contador : %', contador;
END LOOP;
END;
$$ language plpgsql;
prueba4=# select f_while(6); prueba4=# select f_while(2);
NOTICE: Contador : 5 f_while
NOTICE: Contador : 6
NOTICE: Contador : 7 (1 row)
FOR contador IN 1..p_valor LOOP
contador := contador + 2;
RAISE NOTICE 'Contador D %', contador;
END LOOP;
END;
$$
language plpgsql;
Se puede hacer un query dinámico con:
FOR data IN EXCUTE
'select a.id,a.fecha,b.id,b.monto, '' from factura_cab a, factura_det b where a.id = b.fac_id'
LOOP
2. Funciones – Mensajes
create or replace function f_raise(p_valor integer) returns void as
$$
DECLARE
valor varchar;
BEGIN
raise notice 'Mensaje Simple';
raise notice 'El parametro es :%', p_valor;
raise notice 'Este mensaje es' using HINT = '__una sugerencia__';
raise sqlstate '23505' using MESSAGE = 'Cuando se de el ERROR 23505 saldra este mensaje';
END;
$$
language plpgsql;
prueba5=# create table tbl_tabla2 ( id integer);
prueba5=# create index idx_1 on tbl_tabla2(id) unique;
create or replace function f_error() returns void as
$$
BEGIN
BEGIN
insert into tbl_tabla2 values(1);
insert into tbl_tabla2 values(1);
exception
when unique_violation then
raise notice 'Violo UNIQUE index';
END;
BEGIN
insert into tbl_tabla2 values(1);
insert into tbl_tabla2 values(1);
exception
when sqlstate '23505' then
raise notice 'Violo UNIQUE index (2)';
END;
END;
$$ language plpgsql;
prueba5=# select f_error(1);
NOTICE: Violo UNIQUE index
NOTICE: Violo UNIQUE index (2)
2. Funciones – Cursores
create or replace function f_cursor1() returns void as
$$
DECLARE
c_tabla1 refcursor;
data record;
BEGIN
open c_tabla1 for execute 'select * from tbl_usuario';
LOOP
fetch c_tabla1 into data;
IF NOT FOUND THEN
exit;
END IF;
raise notice 'Nombre: %', data.nombre;
END LOOP;
END;
$$
language plpgsql;
prueba5=# select f_cursor1();
NOTICE: Nombre: ernesto
NOTICE: Nombre: juan
NOTICE: Nombre: pedro
2. Funciones – Cursores
create or replace function f_cursor2() returns void as $$
DECLARE
c_tabla1 refcursor; data record; contador integer := 0;
BEGIN
OPEN c_tabla1 SCROLL FOR EXECUTE 'select * from tbl_usuario';
LOOP
contador = contador +1;
IF contador % 3 = 0 THEN
FETCH PRIOR FROM c_tabla1 INTO data;
ELSE
FETCH NEXT FROM c_tabla1 INTO data;
END IF;
IF NOT FOUND THEN exit; END IF;
raise notice 'Nombre: % %', contador, data.nombre;
END LOOP;
END;
$$ language plpgsql;
prueba5=# select f_cursor2();
NOTICE: Nombre: 1 ernesto
NOTICE: Nombre: 2 juan
NOTICE: Nombre: 3 ernesto
NOTICE: Nombre: 4 juan
NOTICE: Nombre: 5 pedro
NOTICE: Nombre: 6 juan
NOTICE: Nombre: 7 pedro
Para mas variaciones de FETCH (siempre abrir el cursor con SCROLL para esto)
http://developer.postgresql.org/pgdocs/postgres/sqlfetch.html
2. Funciones – Cursores
create or replace function f_cursor4() returns void as
$$
DECLARE
c_tabla1 refcursor;
data record;
BEGIN
OPEN c_tabla1 FOR EXECUTE 'select * from tbl_usuario';
LOOP
FETCH c_tabla1 INTO data;
IF NOT FOUND THEN
exit;
END IF;
raise notice 'Nombre: %', data.nombre;
move relative 1 FROM c_tabla1;
END LOOP;
END;
$$
language plpgsql;
La característica principal de MOVE es que no devuelve data de la tabla a la cual esta
unida el cursos, solo mueve el puntero de posición.
Variaciones: NEXT, PRIOR, FIRST, LAST, ABSOLUTE XX, RELATIVE XX, ALL, FORWARD XX ó ALL,
BACKWARD XX ó ALL, donde XX es la cantidad de espacios
2. Funciones – Cursores
create or replace function f_cursor5( p_valor integer) returns void as $$
DECLARE
c_tabla1 cursor FOR select * from tbl_usuario where id = p_valor;
data record;
contador integer;
BEGIN
OPEN c_tabla1;
LOOP
FETCH c_tabla1 INTO data;
IF NOT FOUND THEN exit; END IF;
raise notice 'Nombre: %', data.nombre;
update tbl_usuario set nombre='' || data.nombre where id = data.id;
GET DIAGNOSTICS contador = ROW_COUNT; también existe RESULT_OID y OID
if contador = 1 then
raise notice 'Se proceso % registro', contador;
end if;
END LOOP;
END; $$ language plpgsql;
prueba5=# select * from f_cursor5(1);
NOTICE: Nombre: ernesto
NOTICE: Se proceso 1 registro
f_cursor5
(1 fila)
prueba5=# select * from f_cursor5(5);
f_cursor5
(1 fila)
prueba5=# select * from tbl_usuario;
id | nombre
+
2 | juan
3 | pedro
1 | ernesto
create or replace function f_commit1() returns void as
$$
BEGIN
insert into tbl_usuario (nombre) values ('lucho');
insert into tbl_usuario (nombre) values ('pedro');
END;
$$ language plpgsql;
create or replace function f_commit2() returns void as
$$
BEGIN
update tbl_usuario set nombre = 'juan' where nombre = 'juan';
update tbl_usuario set nombre = 'pedro' where nombre = 'pedro';
END;
$$ language plpgsql;
$conn = pg_connect("host=127.0.0.1 port=5432 dbname=prueba5 user=dbadmin
password=dbadmin");
if ($conn <> false ) {
echo "entro en la db\r\n";
pg_exec("begin");
pg_exec("select f_commit1()");
pg_exec("select f_commit2()");
pg_exec("rollback");
}
?>
Nótese que la transacción principal no se esta cerrando en el código, más bien se está
forzando a realizar un rollback.
prueba5=# select * from tbl_usuario;
id | nombre
+
2 | juan
3 | pedro
1 | ernesto
NO SE EJECUTO NADA!!, ahora cambiemos el rollback en el PHP por un commit y ejecutemos el
código.
ernesto@depeche:~/Documentos$ php prueba.php
entro en la db
prueba5=# select * from tbl_usuario;
id | nombre
+
1 | ernesto
8 | lucho
9 | pedro
2 | juan
3 | pedro
2. Funciones
PRACTICA
3. TRIGGERS
prueba5=# create table alumnos(id serial, nombre varchar(100), edad integer, observ varchar(100));
create or replace function ft_prueba1() returns trigger as $t_alumnos$
begin
IF NEW.edad is NULL THEN
NEW.observ := 'NO especifica';
ELSEIF NEW.edad < 18 THEN
NEW.observ := 'menor edad';
ELSEIF NEW.edad >= 18 THEN
NEW.observ := 'mayor edad';
END IF;
RETURN NEW;
end;
$t_alumnos$ language plpgsql;
prueba5=# create trigger t_alumnos BEFORE INSERT ON alumnos FOR EACH ROW EXECUTE Procedure ft_prueba1();
prueba5=# insert into alumnos (nombre,edad) values ('ernesto', null);
INSERT 0 1
prueba5=# insert into alumnos (nombre,edad) values ('juan', 15);
INSERT 0 1
prueba5=# insert into alumnos (nombre,edad) values ('pedro', 25);
INSERT 0 1
prueba5=# select * from alumnos;
id | nombre | edad | observ
+++
1 | ernesto | | NO especifica
2 | juan | 15 | menor edad
3 | pedro | 25 | mayor edad
3. TRIGGERS
create or replace function ft_prueba2() returns trigger as $t_alumnos2$
begin
IF NEW.edad is NULL THEN
NEW.observ := 'NO especifica';
ELSEIF NEW.edad < 18 THEN
NEW.observ := 'menor edad';
ELSEIF NEW.edad > 18 and NEW.edad < 100 THEN
NEW.observ := 'mayor edad';
ELSEIF NEW.edad > 100 THEN
raise notice 'Ya debería estar muerto';
RETURN NULL;
END IF;
RETURN NEW;
end;
$t_alumnos2$ language plpgsql;
Prueba5=# create trigger t_alumnos2 BEFORE INSERT ON alumnos FOR EACH ROW EXECUTE Procedure ft_prueba2();
prueba5=# insert into alumnos (nombre,edad) values ('cesar', 115);
NOTICE: Ya debería estar muerto
INSERT 0 0
prueba5=# select * from alumnos;
id | nombre | edad | observ
+++
1 | ernesto | | NO especifica
2 | juan | 15 | menor edad
3 | pedro | 25 | mayor edad
(3 filas)
3. TRIGGERS
create or replace function ft_prueba3() returns trigger as $t_alumnos3$
begin
IF NEW.edad is NULL THEN
raise notice 'NO ES VALIDO, NO ACTUALIZO';
RETURN OLD;
ELSEIF NEW.edad < 18 THEN
NEW.observ := 'menor edad';
ELSEIF NEW.edad >= 18 and NEW.edad < 100 THEN
NEW.observ := 'mayor edad';
ELSEIF NEW.edad > 100 THEN
raise notice 'NO ES VALIDO, NO ACTUALIZO';
RETURN OLD;
END IF;
RETURN NEW;
end;
$t_alumnos3$ language plpgsql;
prueba5=# create trigger t_alumnos3 BEFORE UPDATE ON alumnos FOR EACH ROW EXECUTE Procedure ft_prueba3();
prueba5=# update alumnos set edad = 18 where id = 1;
UPDATE 1
prueba5=# update alumnos set edad = 118 where id = 2;
NOTICE: NO ES VALIDO, NO ACTUALIZO
UPDATE 1
prueba5=# select * from alumnos;
id | nombre | edad | observ
+++
3 | pedro | 25 | mayor edad
1 | ernesto | 18 | mayor edad
2 | juan | 15 | menor edad
3. TRIGGERS
create or replace function ft_prueba4() returns trigger as $t_alumnos4$
begin
IF TG_OP = 'INSERT' THEN
IF NEW.edad is NULL or NEW.edad < 18 or NEW.edad > 100 THEN
raise notice 'Edad prohibidas'; RETURN NULL;
ELSE
NEW.observ = 'dato valido'; RETURN NEW;
END IF;
ELSEIF TG_OP = 'DELETE' THEN
raise notice 'Prohibido borrar data de esta tabla'; RETURN NULL;
ELSEIF TG_OP = 'UPDATE' THEN
IF NEW.edad is NULL or NEW.edad < 18 or NEW.edad > 100 THEN
raise notice 'Edad prohibidas'; RETURN OLD;
ELSE
NEW.observ = 'En los esperado'; RETURN NEW;
END IF;
END IF;
end;
$t_alumnos4$ language plpgsql;
prueba5=# create trigger t_alumnos4 BEFORE INSERT OR UPDATE OR DELETE ON alumnos FOR EACH ROW EXECUTE Procedure ft_prueba4();
prueba5=# insert into alumnos (edad,nombre) values (16,'luis'); prueba5=# select * from alumnos;
NOTICE: Edad prohibidas id | nombre | edad | observ
prueba5=# insert into alumnos (edad,nombre) values (26,'luis'); +++
prueba5=# update alumnos set edad = 29 where id = 1; 3 | pedro | 25 | mayor edad
prueba5=# update alumnos set edad = 129 where id = 1; 2 | juan | 15 | menor edad
NOTICE: Edad prohibidas 6 | luis | 26 | dato valido
prueba5=# delete from alumnos where id = 1; 1 | ernesto | 29 | En los esperado
NOTICE: Prohibido borrar data de esta tabla
3. TRIGGERS
create or replace function ft_prueba5() returns trigger as $t_alumnos5$
begin
raise notice 'NEW: %', NEW;
raise notice 'OLD: %', OLD;
raise notice 'TG_NAME: %', TG_NAME;
raise notice 'TG_WHEN: %', TG_WHEN;
raise notice 'TG_LEVEL: %', TG_LEVEL;
raise notice 'TG_OP: %', TG_OP;
raise notice 'TG_RELID: %',TG_RELID;
raise notice 'TG_RELNAME: %',TG_RELNAME;
raise notice 'TG_TABLE_NAME: %',TG_TABLE_NAME;
raise notice 'TG_TABLE_SCHEMA: %', TG_TABLE_SCHEMA;
raise notice 'TG_NARGS: %',TG_NARGS;
raise notice 'TG_ARGV[]: %',TG_ARGV[1];
end;
$t_alumnos5$ language plpgsql;
prueba5=# create trigger t_alumnos5 BEFORE UPDATE ON alumnos FOR EACH ROW EXECUTE Procedure ft_prueba5();
prueba5=# update alumnos set edad = 14 where id = 1;
NOTICE: NEW: (1,ernesto,14,"En los esperado")
NOTICE: OLD: (1,ernesto,29,"En los esperado")
NOTICE: TG_NAME: t_alumnos5
NOTICE: TG_WHEN: BEFORE
NOTICE: TG_LEVEL: ROW
NOTICE: TG_OP: UPDATE
NOTICE: TG_RELID: 22264
NOTICE: TG_RELNAME: alumnos
NOTICE: TG_TABLE_NAME: alumnos
NOTICE: TG_TABLE_SCHEMA: public
NOTICE: TG_NARGS: 0
NOTICE: TG_ARGV[]: <NULL>
3. TRIGGERS
CREATE TRIGGER name { BEFORE | AFTER } { event [ OR ... ] }
ON table [ FOR [ EACH ] { ROW | STATEMENT } ]
[ WHEN ( condition ) ]
EXECUTE PROCEDURE function_name ( arguments )
create trigger t_alumnos5
BEFORE UPDATE
ON alumnos
FOR EACH ROW
WHEN (NEW.* IS DISTINCT FROM OLD.* ) < solo en PostgreSQL 9.0
EXECUTE PROCEDURE ft_prueba5();
3. TRIGGERS
BEGIN;
-- desactivamos los triggers
UPDATE pg_catalog.pg_class SET
reltriggers = 0
WHERE oid = 'nombre_tabla'::pg_catalog.regclass;
-- operaciones sobre nombre_tabla ...
-- activamos los triggers sobre nombre-tabla
UPDATE pg_catalog.pg_class SET
reltriggers = (SELECT pg_catalog.count(*)
FROM pg_catalog.pg_trigger
where pg_class.oid = tgrelid)
WHERE oid = 'nombre_tabla'::pg_catalog.regclass;
COMMIT;
4. RULES
Las reglas nos permiten de una manera más limitada desarrollar alguna acción ante un
evento producido en una tabla ó vista, no permiten desarrollar toda una lógica como en el
caso de los triggers.
create table regla (id serial , nombre varchar(100));
create table log_regla( fecha timestamp , id integer, nombre varchar(100), estado char(1));
CREATE RULE rul_i_fecha AS ON INSERT TO regla
DO insert into log_regla values ( now(), NEW.id, NEW.nombre, 'I');
prueba4=# insert into regla (nombre) values ('Ernesto');
prueba4=# select * from regla;
id | nombre
+
1 | Ernesto
prueba4=# select * from log_regla;
fecha | id | nombre | estado
+++
20101008 20:26:37.200866 | 2 | Ernesto | I
Ojo con el serial “id”, al reutilizarlo se relanza el nextval y devuelve un valor
erroneo, lo correcto sería:
CREATE OR REPLACE RULE rul_i_fecha AS ON INSERT TO regla
DO insert into log_regla values ( now(), currval('regla_id_seq'), NEW.nombre, 'I');
4. RULES
“Instead” nos permite que la acción solicitada ya no se lleve a cabo y se realice la
acción alternativa declarada en la regla.
CREATE OR REPLACE RULE rul_i_fecha AS ON INSERT TO regla
DO INSTEAD insert into log_regla values ( now(), NEW.id, NEW.nombre, 'I');
prueba4=# insert into regla (nombre) values ('Ernesto4');
INSERT 0 1
prueba4=# select * from regla;
id | nombre
+
1 | Ernesto
3 | Ernesto2
5 | Ernesto3
(3 rows)
prueba4=# select * from log_regla;
fecha | id | nombre | estado
+++
20101008 20:26:37.200866 | 2 | Ernesto | I
20101008 20:29:47.29924 | 4 | Ernesto2 | I
20101008 20:34:00.101965 | 6 | Ernesto3 | I
20101008 20:35:08.391818 | 7 | Ernesto4 | I
4. RULES
CREATE OR REPLACE RULE rul_u_fecha AS ON UPDATE TO regla WHERE OLD.id < 6
DO insert into log_regla values ( now(), NEW.id, NEW.nombre, 'U');
prueba4=# update regla set nombre = 'alejandro' where id = 1;
prueba4=# update regla set nombre = 'alejandro' where id = 9;
prueba4=# select * from regla;
id | nombre
+
3 | Ernesto2
5 | Ernesto3
1 | alejandro
9 | alejandro
prueba4=# select * from log_regla;
fecha | id | nombre | estado
+++
20101008 20:26:37.200866 | 2 | Ernesto | I
20101008 20:29:47.29924 | 4 | Ernesto2 | I
20101008 20:34:00.101965 | 6 | Ernesto3 | I
20101008 20:35:08.391818 | 7 | Ernesto4 | I
20101008 20:39:57.221768 | 8 | Ernesto4 | I
20101008 20:49:24.691783 | 8 | pedro | I
20101008 20:49:43.711889 | 9 | pedro | I
20101008 20:59:19.761879 | 1 | Ernesto | U
20101008 21:00:08.529349 | 1 | alejandro | U
4. RULES
CREATE OR REPLACE RULE rul_d_fecha AS ON DELETE TO regla
DO select sum(id) as quedan from regla;
prueba4=# select * from regla;
id | nombre
+
3 | Ernesto2
5 | Ernesto3
9 | alejandro
(3 rows)
prueba4=# delete from regla where id = 3;
quedan
17
(1 row)
prueba4=# select * from regla;
id | nombre
+
5 | Ernesto3
9 | alejandro
(2 rows)
4. RULES
CREATE OR REPLACE RULE rul_u_fecha AS ON UPDATE TO regla WHERE OLD.id < 6
DO (insert into log_regla values ( now(), NEW.id, NEW.nombre, 'U'); select * from log_regla where id =
NEW.id);
prueba4=# select * from regla;
id | nombre
+
9 | alejandro
5 | pepelucho
prueba4=# update regla set nombre = 'pepelucho1' where id = 5;
fecha | id | nombre | estado
+++
20101008 21:21:55.82194 | 5 | pepelucho | U
20101008 21:22:06.759216 | 5 | pepelucho1 | U
prueba4=# select * from regla;
id | nombre
+
9 | alejandro
5 | pepelucho1
PRACTICA
GiN : <@,@>,=,&&
Para obtener provecho de esto las consultas deben hacer el pedido de la data en la
estructura en la que se ha creado el índice.
●Create index idx_nombre on tabla1 (campo1) where campo1 > 100 and campo1 <= 100000;
Podemos especificar un índice de este tipo donde los valores WHERE sean diferentes a
los que estamos indexando.
●Create index idx_nombre on tabla1 (campo1) where campo2 > 100 and campo2 <= 100000;
Select * from tabla1 where campo1 = 10 and campo2 = 1000; <-- usará el índice
Select * from tabla1 where campo2 > 1000 and campo3 = 1000; <-- podría usar el índice
Explain permite visualizar el plan de ejecución de un query, el plan de
ejecución son los pasos que sigue la dmbs para procesar la consulta, tabla
por tabla con la que trabaja, las uniones, tipos de índices que utiliza,
tuplas movidas, etc.
prueba4=# explain select * from regla;
QUERY PLAN
Seq Scan on regla (cost=0.00..18.00 rows=800 width=72)
(1 row)
Informa los campos requeridos en la consulta
prueba4=# explain verbose select * from regla;
QUERY PLAN
Seq Scan on public.regla (cost=0.00..18.00 rows=800 width=72)
Output: id, nombre
(2 rows)
prueba4=# explain analyze verbose select * from regla;
QUERY PLAN
Seq Scan on public.regla (cost=0.00..18.00 rows=800 width=72) (actual time=0.010..0.013 rows=2 loops=1)
Output: id, nombre
Total runtime: 0.050 ms
(3 rows)
prueba4=# explain select * from factura_cab a join factura_det b on a.id =b.fac_id;
QUERY PLAN
Merge Join (cost=260.93..525.73 rows=17120 width=29)
Merge Cond: (b.fac_id = a.id)
> Sort (cost=111.15..115.15 rows=1600 width=21)
Sort Key: b.fac_id
> Seq Scan on factura_det b (cost=0.00..26.00 rows=1600 width=21)
> Sort (cost=149.78..155.13 rows=2140 width=8)
Sort Key: a.id
> Seq Scan on factura_cab a (cost=0.00..31.40 rows=2140 width=8)
(8 rows)
El primer explain fue hecho sin hacer un VACUMM a las tablas, en el segundo se
procedió a ello, nótese las diferencia en las cifras, esto se debe a las estadísticas.
prueba4=# explain select * from factura_cab a join factura_det b on a.id =b.fac_id;
QUERY PLAN
Hash Join (cost=1.07..2.16 rows=4 width=25)
Hash Cond: (b.fac_id = a.id)
> Seq Scan on factura_det b (cost=0.00..1.04 rows=4 width=17)
> Hash (cost=1.03..1.03 rows=3 width=8)
> Seq Scan on factura_cab a (cost=0.00..1.03 rows=3 width=8)
(5 rows)
El costo:
(cost=149.78..155.13 rows=2140 width=8)
149.78 < costo inicial de traer la primera tupla
155.13 < costo total estimado
Rows=2140 < filas escaneadas
Width=8 < filas de salida
El costo total estimado se calcula sobre la siguiente formula
(disk pages read * seq_page_cost) + (rows scanned * cpu_tuple_cost)
seq_page_cost < costo de acceso a las páginas de la data (1.00 default)
cpu_tuple_cost < costo del proceso de cada fila durante la consultas (0.01 default)
Seq Scan < indica que esta llevando a cabo una busqueda secuencial en la
tabla, bien porque no existe un índice o bien porque no la
necesita.
on factura_cab a < nos indica que esta buscando sobre la tabla “factura” con
alias “a”.
Hash (cost=1.03..1.03 rows=3 width=8)
Hash < significa que esta creando un mapa de datos e índices con el
Fin de facilitar búsquedas
Sort (cost=149.78..155.13 rows=2140 width=8)
Sort Key: a.id
SORT KEY < nos índica por que campo esta realizando un ordenamiento y
Posteriormente el costo del ordenamiento
Hash Join (cost=1.07..2.16 rows=4 width=25)
Hash Cond: (b.fac_id = a.id)
Tanto en el caso Merge Join como en el caso Hash Join el dbms esta realizando la unión
de las dos tablas, nos indica el costo para cada caso.
Lo que tenemos que buscar siempre es que los COSTOS de nuestras consultas
sean lo más bajos posibles, no siempre una búsqueda secuencial puede tener
un costo mayor que una búsqueda indexada, eso dependerá de la data y
estructura de las tablas.
Es importante escribir querys limpios, dar el menor trabajo posible al
analizador de querys de PostgreSQL para que la resolución del plan de
ejecución sea la menor posible.
●Nested Loop < Se combinan dos tablas utilizando bucles anidados. Por cada fila
de la tabla padre, se recorren todas las filas de la tabla hija.
●Index scan < búsqueda sobre un índice
●Unique < elimina registros de valores duplicados
●Limit < indica que se esta pidiendo una cantidad limitada de registros,
aparece cuando se ha usado el operador en la consulta
●Aggregate < concatenación de columnas
●Subquery Scan < indica una subconsulta dentro del contexto de un UNION
●Subplan < indica una subconsulta dentro de un subquery
●Append < indica que se están uniendo 2 tablas, aparece cuando se uso el
operador UNION en la consulta
●Tid Scan (raro)
●Group < indica que se hace un GROUP BY
●Result < indica una operación que no mueve datos
●Materialize < se da en caso de que existan subconsultas que se repiten y
el dbms decide almacenar los resultados obtenidos para su
rehuso.
http://www.iphelp.ru/faq/15/ch04lev1sec3.html
1. Análisis de Querys
PRACTICA
pf_dump NOMBRE_DB a < solo datos
pf_dump NOMBRE_DB b < incluir objetos grandes
pg_dump NOMBRE_DB c < incluye limpieza de objetos de la db, inserta drops antes
De crearlos
pg_dump NOMBRE_DB C < incluye un create database
pg_dump NOMBRE_DB encoding=LATIN1 < backup con otra codificación
pg_dump NOMBRE_DB file=backup.dump < el backup se crear en este archivo
pg_dump NOMBRE_DB format=p < backup en texto plano
pg_dump NOMBRE_DB format=c < backup en formato que soporta pg_restore, comprimido
pg_dump NOMBRE_DB schema=NOMBRE_SC < backup solo del esquema especificado
pg_dump NOMBRE_DB excludeschema=NO< backup excluyendo el esquema especificado
pf_dump NOMBRE_DB o < incluir el OID de los objetos, útil solo si se usa los OID
Especificamente.
pf_dump NOMBRE_DB O < no se backupean los OWNER de los objetos, es útil cuando
Cuando se mueve una db de un servidor a otro diferente.
pf_dump NOMBRE_DB S < solo backupea estructura de la db más no la data
pg_dump NOMBRE_DB table=NOMBRE_TAB < backupea solo la tabla especificada
pg_dump NOMBRE_DB excludetable=TA < backupea sin la tabla especificada
pg_dump NOMBRE_DB X < no se backupean los permisos
pg_dump NOMBRE_DB –compres=0..9 < especifica el nivel de compresión del backup, útil cuando
Se usa el parámetro: format=c
pg_dump NOMBRE_DB inserts < genera inserts de la data en vez de copys, añadir
columninserts si se desea que se especifiquen en los
Insert los nombres de los campos
pg_dump NOMBRE_DB disabletriggers < desabilita los triggers, útil solo si copiamos data y no
Estructura de la db.
pg_dump NOMBRE_DB notablespaces < no incluye las definiciones de los tablespaces en el backup
Todos los parámetros donde se especifican nombre de objteos (tablas, schemas, etc.)
pueden usar el comodín “*”, por ejemplo todas la tabla que empiezan con EQSOFT es “
table=EQSOFT*”
Todos se pueden usar solos o en combinación, además están los parametros de conexión
los cuales son:
h HOST_NAME < ip del servidor o nombre del host
p PUERTO < número del puerto
U USER_NAME < nombre del usuario
w < no pide password
W < fuerza a pedir el password
Se pueden usar estas variables de entorno: PGDATABASE, PGHOST, PGOPTIONS, PGPORT y
PGUSER
ernesto@depeche:~/aaa$ pg_dump prueba5 > archivo.dump
pg_dump: [archivador (bd)] falló la conexión a la base de datos «prueba5»: FATAL: no se
especifica un nombre de usuario en el paquete de inicio
ernesto@depeche:~/aaa$ export PGUSER=dbadmin
ernesto@depeche:~/aaa$ pg_dump prueba5 > archivo.dump
Implementa los mismos parámetros de pg_dump, añade el parámetro “l NOMBRE_DB” para
especificar el nombre de la base de datos a kacupear (mejor usar pg_dump).
pg_dumpall ademas copia usuarios de la base de datos además de la data y estructura
cosa que no hace pg_dump
Para comprimir un dump normal (en texto plano) podemos usar:
ernesto@depeche:~/aaa$ pg_dump prueba5 U dbadmin > dump.dump
ernesto@depeche:~/aaa$ ls dump.dump la
rwrr 1 ernesto ernesto 24522 20101009 12:07 dump.dump
ernesto@depeche:~/aaa$ pg_dump prueba5 U dbadmin | gzip > dump.dump.gz
ernesto@depeche:~/aaa$ ls dump.dump.gz la
rwrr 1 ernesto ernesto 3940 20101009 12:06 dump.dump.gz
Algunas ventajas de usar pg_restore sobre el metodo alternativo es que tenemos mayor
velocidad en restore de bases de datos enormes debido al uso de multihilos para el
restore.
ernesto@depeche:~/aaa$ pg_dump prueba5 format=c U dbadmin > pgrestore.dump
ernesto@depeche:~/proyectos$ dropdb prueba5 U dbadmin
ernesto@depeche:~/proyectos$ createdb prueba5 U dbadmin
ernesto@depeche:~/aaa$ pg_restore pgrestore.dump U dbadmin –dbname=prueba5
ernesto@depeche:~/aaa$ pg_dump prueba5 > otro.dump U dbadmin
ernesto@depeche:~/proyectos$ createdb prueba6 U dbadmin
ernesto@depeche:~/aaa$ pg_restore otro.dump U dbadmin dbname=prueba6
pg_restore: [archivador] el archivo de entrada no parece ser un archivador válido
Pg_restore permite el uso de muchos parámetros, básicamente los mismos de pg_dump en
sentido inverso (no baja data sino sube obviamente), la lista completa puede ser
revisada aquí:
http://www.postgresql.org/docs/9.0/interactive/apppgrestore.html
Para especificar cuantos hilos deseamos que se lancen en el proceso de restore usamos
el parámetro j
ernesto@depeche:~/aaa$ pg_restore pgrestore.dump U dbadmin j 4 dbname=prueba8
El tiempo mejorado depende de: cantidad de data, estructura de la db, cantidad de
jobs, disponibilidad de la db, etc. Eventualmente se obtendrán beneficios de 25% de
reducción del tiempo hasta 85% (lo máximo reportado) de ahorro.
Pgrman
http://code.google.com/p/pgrman/
Otra opción es hacer backups “online” de los archivos WAL.
http://www.postgresql.org/docs/9/static/continuousarchiving.html
Los archivos WAL son los intercambios de data transaccional en la base de datos a
nivel binario, no es necesariamente consistente el backup.
3. Administración – Procesos
a)TOP y HTOP
TOP es un comando convencional de Linux / Unix que nos permite ver los procesos que se
ejecutan en el servidor.
Los procesos ejecutados por PostgreSQL son normalmente ejecutados por los usuarios
“postgres”, “pgsql” ó “postmaster”.
ernesto@depeche:~/aaa$ ps aux | egrep postgres
postgres 961 0.0 0.1 101580 2228 ? S Oct08 0:06 /usr/lib/postgresql/8.4/bin/postgres D
/var/lib/postgresql/8.4/main c config_file=/etc/postgresql/8.4/main/postgresql.conf
postgres 989 0.0 0.3 101704 6208 ? Ss Oct08 0:11 postgres: writer process
postgres 990 0.0 0.0 101580 568 ? Ss Oct08 0:08 postgres: wal writer process
postgres 991 0.0 0.0 102380 1320 ? Ss Oct08 0:09 postgres: autovacuum launcher process
postgres 992 0.0 0.0 73704 848 ? Ss Oct08 0:17 postgres: stats collector process
Recuerde que PostgreSQL maneja un procesador por conexión, si tiene varios
procesadores un proceso lanzado no usará varios procesadores, solo uno, deja los otros
disponibles para otras conexiones que lanzan sus propios procesos, la ventaja del uso
de esta funcionalidad se complementa con la capacidad de administración de usuarios
concurrentes que tenga el sistema operativo que se está usando (que soporte SMP).
Nunca mate un proceso que demora mucho
3. Administración – Procesos
b)PG_TOP
http://ptop.projects.postgresql.org/
El paquete instalador en Ubuntu es PTOP e instala la aplicación pg_top.
ernesto@depeche:~/aaa$ pg_top help
pg_top: invalid option ''
pg_top version 3.6.2
Usage: pg_top [ITWbcinqu] [x x] [s x] [o field] [z username]
[p PORT] [U USER] [d DBNAME] [h HOSTNAME] [number]
ernesto@depeche:~/aaa$ pg_top U dbadmin d prueba5
En una consola:
prueba5=# begin;
prueba5=# lock alumnos in exclusive mode;
En otra Consola:
prueba5=# insert into alumnos values(5,'chicho',12,'nada');
PgTop nos muestra:
ast pid: 29499; load avg: 1.59, 1.59, 1.69; up 1+03:48:24
3 processes: 3 sleeping
CPU states: 47.0% user, 2.6% nice, 8.8% system, 40.5% idle, 1.1% iowait
Memory: 1920M used, 81M free, 26M buffers, 659M cached
Swap: 375M used, 1532M free, 45M cached
PID USERNAME PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND
29500 postgres 20 0 102M 4232K sleep 0:00 0.02% 0.20% postgres: dbadmin prueba5 [local] idle
29215 postgres 20 0 102M 5048K sleep 0:00 0.00% 0.00% postgres: dbadmin prueba5 [local] idle in transaction
29396 postgres 20 0 102M 3628K sleep 0:00 0.00% 0.00% postgres: dbadmin prueba5 [local] INSERT waiting
3. Administración – Procesos
b)PG_TOP
A < permite ver el plan de ejecución de un query, especifique el PID del proceso
C < activa/desactiva color
c < permite ver la linea de comandos completa
D < cambia página de listado
h ó ? < help
E < ver versión actualizada del plan de ejecución
e < permite ver errores del sistema
I < ver/no ver procesos en espera o durmiendo
K < mata un proceso, indicar el pid
L < permite ver los locs del proceso, especificar el pid
M < ordena por uso de memoria
N < ordena por número de proceso
n ó # <indica cuantos procesos se pueden ver, máximo 65
O < cambia el orden de muestra dependiendo un parámetro especial ("cpu", "res", "size", "time",
"seq_scan", "seq_tup_read", "idx_scan", "idx_tup_fetch", "n_tup_ins","n_tup_upd", "n_tup_del")
P < ordena por utilización del proceso
Q < muestra el query, especificar el pid
q < Quit
R < Display user table statistics.
r < ??
s < cambia la cantidad de segundos de refresco de la pantalla
T < ordena por tiempo de ejecución
T < ??
U < muestra los procesos de un usuario, ingresar el usuario
X < muestra las estadísticas de los índices
4. DBLinks
PostgreSQL no permite acceder de manera transparente entre la data de un servidor y
otro, para ello se requiere crear una conexión entre ambos servidores.
Tome en cuenta uan cosa, acceder a otra db desde la cual se esta trabajando y operar
sobre ella requerirá que PostgreSQL jale toda la data de las tablas que involucren la
operación, luego el dbms filtrará la necesaria en la db actual pero solo después de
haber jalado todo.
DbLink no viene por defecto, es necesario instalar el paquete “contrib” de la versión
que estemos usando, instalado este paquete requerimos ejecutar el siguiente script:
prueba5=# \i /usr/share/postgresql/8.4/contrib/dblink.sql
a) CREATE FOREIGN DATA WRAPPER
Creamos una fuente de datos externa, solo el super usuario puede realizar esta acción.
Prueba5=# CREATE FOREIGN DATA WRAPPER dw_prueba VALIDATOR postgresql_fdw_validator;
VALIDATOR postgresql_fdw_validator esta predeterminado para chequear la consistencia
de la conexión, si no se especifica esto no se validará la misma.
4. DBLinks
b) CREATE SERVER
Con está sentencia creamos el servidor al cual nos vamos a conectar
prueba5=# CREATE SERVER srv_prueba FOREIGN DATA WRAPPER dw_prueba OPTIONS (hostaddr '127.0.0.1',
dbname 'drupal7',port '5432');
c) CREATE USER MAPPING
Creamos un usuario de conexión a la db foranea.
prueba5=# CREATE USER MAPPING FOR dbadmin SERVER srv_prueba OPTIONS (user 'usuario_foraneo',
password 'password_foraneo');
Dbadmin < es el usuario/rol al cual le vamos a dar acceso al servidor
usuario_foraneo < es el usuario que tiene acceso a la db foránea
password_foraneo < clave
d) SELECT dblink_connect
Antes de poder usar la el dblink necesitamos conectarnos:
prueba5=# SELECT dblink_connect('mi_conexion','srv_prueba');
4. DBLinks
e)Probando la conexión:
prueba5=# select dblink_exec('mi_conexion','create table tbl_pruebas(id serial,nombre varchar(100))');
dblink_exec
CREATE TABLE
prueba5=# select dblink_exec('mi_conexion','insert into tbl_pruebas (nombre) values (''ernesto'')');
dblink_exec
INSERT 0 1
prueba5=# select dblink_exec('mi_conexion','insert into tbl_pruebas (nombre) values (''juan'')');
dblink_exec
INSERT 0 1
ernesto@depeche:~$ psql drupal7 U dbadmin
psql (8.4.4)
Digite «help» para obtener ayuda.
drupal7=# select * from tbl_pruebas;
id | nombre
+
1 | ernesto
2 | juan
(2 filas)
drupal7=#
4. DBLinks
f)Trayendo Data:
prueba5=# select* from dblink('mi_conexion','select * from tbl_pruebas') as (f_id integer, f_nomber varchar(100));
f_id | f_nomber
+
1 | ernesto
2 | juan
(2 filas)
Para conocer más sobre las funciones de dblink
http://www.postgresql.org/docs/9/static/dblink.html
5. Vacuum
El Vacuum es una de las más importantes tareas de administración, lo que hace es
limpiar las “páginas” no usadas por el sistema y actualiza las estadísticas de las
tablas e índices para una mejor resolución de querys.
La dbms ejecuta periodicamente (definido en postgresql.conf) un Lazy Vacuum, esto es
libera páginas no usadas por data, más no por índice, este vacuum no genera demasiado
tiempo de bloqueo en la tabla (depende el tamaño).
5. Vacuum
El full vacuum requiere acceso exclusivo a la tabla durante el tiempo que demoré la
operación, esta limpiara totalmente las páginas no usadas.
Mejora notablemente el tiempo de acceso a los datos.
5. Vacuum
Se pueden aplicar Vaccums a nivel de tabla o base de datos.
●Vacuum full TABLA < limpia todo el espacio no utilizado, reescribe totalmente la
tabla por lo cual consume más espacio.
●Vacuum analyze TABLA < actualiza las estadísticas para e generador de plan de
ejecución.
●Vacuum TABLA < solo limpia data y reorganiza las páginas.
Se puede añadir de precisión un Vacuum sobre un campo.
“Vacuumdb” se utiliza externamente desde la linea de comandos del sistema operativo
para ejecutar la operación sobre la base de datos seleccionada.
ernesto@depeche:~$ vacuumdb full prueba5 U dbadmin