sábado, abril 21, 2007

un bloqueo en postgresql

Al revisar el blog de CarlosAL, en específico la entrada indices-y-foreign-keys me entró la duda de que pasa con postgreSQL, claro que solo revise el caso de los bloqueos, me parece que en postgres también es bueno crear índices por cada llave foránea que se tenga.

contexto:
miguel@asakura:~$ psql postgres
Bienvenido a psql 8.1.8, la terminal interactiva de PostgreSQL.

Digite: \copyright para ver los términos de distribución
\h para ayuda de comandos SQL
\? para ayuda de comandos psql
\g o or termine con punto y coma para ejecutar una consulta
\q para salir

postgres=# \d prueba01;
Tabla «public.prueba01»
Columna | Tipo | Modificadores
---------+-------------------+---------------
id_n | integer | not null
c_txt | character varying |
Índices:
«idx_id_n» PRIMARY KEY, btree (id_n)

postgres=# \d prueba04;
Tabla «public.prueba04»
Columna | Tipo | Modificadores
---------+---------+---------------
id_n | integer |
upper | text |
Restricciones de llave foránea:
«fdx_id_n» FOREIGN KEY (id_n) REFERENCES prueba01(id_n)

postgres=# SELECT * from prueba01;
id_n | c_txt
------+--------------
1 | uno
2 | dos
3 | tres
4 | cuatro
5 | cinco
6 | seis
11 | once
21 | veintiuno
23 | veintitres
24 | veinticuatro
25 | veinticinco
30 | treinta
(12 filas)

postgres=# SELECT * from prueba04;
id_n | upper
------+--------
1 | UNO
2 | DOS
3 | TRES
4 | CUATRO
5 | CINCO
6 | SEIS
(6 filas)

sesión 1
postgres=# BEGIN ;
BEGIN

sesión 2
postgres=# BEGIN ;
BEGIN
postgres=# INSERT into prueba04 VALUES (30,'TREINTA');
INSERT 0 1

sesión 1

postgres=# DELETE FROM prueba01 WHERE id_n = 30;
En este caso espera, porque la sesión 2 está haciendo uso de la fila que tiene id_n = 30 en prueba01

sesión 2
postgres=# commit;
COMMIT

sesión 1
inmediatamente despues del commit de la sesión 2
ERROR: update o delete en «prueba01» viola la llave foránea «fdx_id_n» en «prueba04»
DETAIL: La llave (id_n)=(30) todavía es referida desde la tabla «prueba04».
postgres=# end;
ROLLBACK
al hacer commit se compromete esta transacción y se procede al rollback.

Ahora intentaremos borrar una tupla que no este ocupada por la sesión 2 ni por alguna referencia en prueba04
sesión 2
postgres=# begin;
BEGIN
postgres=# INSERT into prueba04 VALUES (21,'VEINTIUNO');
INSERT 0 1

session 1
postgres=# BEGIN;
BEGIN
postgres=# DELETE FROM prueba01 WHERE id_n =25;
DELETE 1
postgres=# end;
COMMIT
Como vemos en este caso ni siquiera espero, se puede hacer el commit de inmediato.

session 2
postgres=# end;
COMMIT
Publicar un comentario