[Python] [Python e PostgreSQL] All'interno delle eccezioni, le transazioni si comportano diversamente?

Daniele Varrazzo piro a develer.com
Lun 25 Ott 2010 15:37:51 CEST


On Mon, 25 Oct 2010 14:53:05 +0200, Matteo Mattsteel Vitturi
<mattsteel a hotmail.it> wrote:

>> > L'alternativa potrebbe essere quella di disabilitare ...
>> Creare la fkey non è gratis: il database deve fare un full scan della
>> tabella per verificare che tutti i record verifichino la condizione,
>> altrimenti si rifiuta di creare il vincolo. In più droppare/creare la
>> fkey
>> richiede lock che possono essere ostacolati da altre query concorrenti.
>> La
>> soluzione di Giovanni è quella giusta.
> 
> ... hai perfettamente ragione: creare/riabilitare una foreign è molto
> dispendioso.
> 
> Il mio ragionamento voleva focalizzare il fatto che non è ragionevole 
> modificare il valore di una chiave primaria, soprattutto quando questa è
>  una chiave-fisica come un ID ma piuttosto converrebbe disporre di una
>  colonna aggiuntiva che rappresenti la
> "chiave-logica" senza intrigarsi nelle chiavi-fisiche.

Certo, hai ragione. Anche io sono convinto che Marco può organizzare
meglio quel lavoro, in maniera da non incocciare l'errore in primo luogo.
Visto che non sempre si può fare, gli ho mostrato come funzionano le
transazioni annidiate, ma i suggerimenti dati dagli altri sono altrettanto
validi.

(...anche se, quando uno ha un problema con una libraria di base,
suggerire di usare una libreria di livello superiore può servire ad
aggirarlo, ma non credo sia un modo di capire il problema originale. Non
sono contrario alle librerie di livello superiore: uso spesso SQLAlchemy
come scorciatoia per avere le query noiose scritte, ma sarebbe un guaio non
sapere l'effetto delle query generate)

> Credo però che la soluzione di Giovanni sia dello stesso tenore della
mia,
> in quanto la modifica (ancorché in cascade) della primary-key di una
riga
> di questo tipo richiede l'esame di tutte le foreign-key che referenziano
la
> primary-key che sto alterando ed implica, quindi, tutti i lock del caso
su
> tutte le tabelle coinvolte (quella della primary e quelle della
foreign).
>
> Speravo si notasse che la mia proposta era volutamente provocatoria...
> dato che il medesimo gruppetto di lock verrebbe applicato anche per la
> cancellazione.

Non è proprio la stessa cosa: per modificare la pkey di T1 a cui T2 si
riferisce, il database fa qualcosa tipo:

    update T2 set fkey = new where fkey = old

e può usare un indice per farlo. Creare una fkey da zero implica qualcosa
tipo:

    select * from T2 where fkey is not null and fkey in (select id from
T1)

per dare errore in caso ci sia qualche record che non verifica la
condizione. Quindi serve ad esempio un nested loop: prima il db seleziona
tutti gli id in T1, ne crea un hash, quindi per ogni record di T2: verifica
che fkey sia nell'hash. E questo al di là del lock che un ALTER TABLE
richiede (che diventa un discorso più specifico postgres: per farla breve,
gli update non bloccano nè le select nè gli update concorrenti su record
diversi; alter table blocca anche le select)

La soluzione di Giovanni non verteva solo sull'usare cascade nella
definizione di fkey: posporre il check della fkey alla fine della
transazione consente di sporchettare con i dati come si vuole, passando
attraverso stati inconsistenti, per poi avere una verifica della
consistenza quando la transazione è finita. Tanta roba!

A presto, ciao.

-- 
Daniele Varrazzo - Develer S.r.l. 
http://www.develer.com


Maggiori informazioni sulla lista Python