Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

postgresql - transakcje, procedury i zerwane połączenia

443 views
Skip to first unread message

pluton

unread,
Jan 10, 2012, 12:30:36 PM1/10/12
to
Witam,

Mam taki problem: muszę przepisać z dwóch tabel pomocniczych do głównych :

insert into g1(a) select a from pom1;
insert into g2(b) select b from pom2;

Zapytania są w 100% wykonywalne: zgadzają się nazwy tabel, zgadzają się
nazwy pól,
nie ma mowy o constraintach w tabelach głównych, które mogły by zakłócić
wstawianie.
Mam taką pewność, ponieważ wykonałem te zapytania setki o ile nie tysiące
razy.
Czas wykonania jest rzędu 1 sekundy.
Są to proste atomowe operacje, jest więc spora szansa, że nic nie muszę
robić, żeby było ok.
Chyba że pomiędzy wysłaniem tych zapytań do bazy padnie mi aplikacja (C++).

Jednak muszę mieć pewność, że wykonają się obie instrukcje , albo wcale.
Niestety kiedy obejmę je transakcją, to commit trwa nawet kilka sekund,
w każdym razie 3 razy dłużej niż mogę czekać.
Zatem nie mogę użyć transakcji.

Wykombinowałem sobie, że wsadzę to wszystko w procedurę wbudowaną o logice
takiej:
1) zrób pierwszy insert
2) nie udało się - to spadaj
3) zrób drugi insert
4) nie udało się - to odszczekaj pierwszy (delete) i spadaj

I pytanie mam takie: czy jest mozliwe, żeby raz odpalona procedura wbudowana
nie wykonała się do końca?
Nie chodzi mi o błędy po drodze, bo te przechwycę wszystkie i obsłużę.

Chodzi mi o taką sytuację, że np. po odpaleniu procedury zerwie mi się
połaczenie z bazą, aplikacja mi padnie
itp. itd.

Czy raz odpalona procka pójdzie jak czołg aż zrobi co ma zrobić (zakładając
że nie będzie błędów) , czy też engine
bazy może z jakichkolwiek powodów przerwać prockę ?

pozdrawiam
pluton



Sławomir Szyszło

unread,
Jan 10, 2012, 1:09:10 PM1/10/12
to
Dnia Tue, 10 Jan 2012 18:30:36 +0100, "pluton" <zielon...@gazeta.pl>
wklepał(-a):

>Jednak muszę mieć pewność, że wykonają się obie instrukcje , albo wcale.
>Niestety kiedy obejmę je transakcją, to commit trwa nawet kilka sekund,
>w każdym razie 3 razy dłużej niż mogę czekać.
>Zatem nie mogę użyć transakcji.

No to obejmij je transakcją. Myślisz, że jak tego nie zrobisz, to zatwierdzanie
danych będzie trwało krócej? Przecież i tak gdzieś ten commit potem będzie
musiał być, żeby zapisać te dane w sposób trwały.

>I pytanie mam takie: czy jest mozliwe, żeby raz odpalona procedura wbudowana
>nie wykonała się do końca?
>Nie chodzi mi o błędy po drodze, bo te przechwycę wszystkie i obsłużę.
>
>Chodzi mi o taką sytuację, że np. po odpaleniu procedury zerwie mi się
>połaczenie z bazą, aplikacja mi padnie
>itp. itd.
>
>Czy raz odpalona procka pójdzie jak czołg aż zrobi co ma zrobić (zakładając
>że nie będzie błędów) , czy też engine
>bazy może z jakichkolwiek powodów przerwać prockę ?

Skończy się RAM, dysk, prąd... proces zostanie zabity.

Zrób tak jak to się robi poprawnie, a nie kombinuj, bo nie zrobisz tego lepiej
niż mechanizm transakcyjny bazy.
--
Sławomir Szyszło
Primus inter FAQires & Grand Inquisitor no.0 of pl.comp.bazy-danych
FAQ pl.comp.bazy-danych http://www.dbf.pl/faq/
Archiwum http://groups.google.com/groups?group=pl.comp.bazy-danych

Paweł Matejski

unread,
Jan 10, 2012, 1:05:33 PM1/10/12
to
W dniu 10.01.2012 18:30, pluton pisze:
1. Oczywiście, że może przerwać.
2. Twoje rozwiązanie jest niepotrzebne, bo wystarczy obydwa inserty dać w funkcji (*).
3. Działa to dlatego, że każde zapytanie, które nie jest w transakcji, jest automatycznie objęte transakcją, która jest
commitowana po jego zakończeniu.
4. Więc nie ominiesz problemu z długim commitem.


*
madej=> CREATE TABLE test (id integer);
CREATE TABLE
Czas: 2,573 ms
madej=> CREATE UNIQUE INDEX test_id_uniq on test (id);
CREATE INDEX
Czas: 3,512 ms
madej=> CREATE FUNCTION foo(a1 integer, a2 integer) returns bool AS
$f$
begin
insert into test values (a1);
insert into test values (a2);
return true;
end;
$f$
LANGUAGE 'plpgsql';
CREATE FUNCTION
Czas: 1,990 ms
madej=> SELECT foo(1,2);
foo
-----
t
(1 wiersz)

Czas: 2,523 ms
madej=> SELECT * from test ;
id
----
1
2
(2 wiersze)

Czas: 0,939 ms
madej=> SELECT foo(3,3);
BŁĄD: podwójna wartość klucza narusza ograniczenie unikalności "test_id_uniq"
SZCZEGÓŁY: Klucz (id)=(3) już istnieje.
KONTEKST: wyrażenie SQL "insert into test values (a2)"
PL/pgSQL function "foo" line 4 at wyrażenie SQL
madej=> SELECT * from test ;
id
----
1
2
(2 wiersze)

Czas: 0,817 ms


--
P.M.

pluton

unread,
Jan 10, 2012, 2:27:20 PM1/10/12
to
>>Zatem nie mogę użyć transakcji.
>
> No to obejmij je transakcją. Myślisz, że jak tego nie zrobisz, to
> zatwierdzanie
> danych będzie trwało krócej? Przecież i tak gdzieś ten commit potem będzie
> musiał być, żeby zapisać te dane w sposób trwały.

puszczam aplikację, która 500 razy przygotowuje tabele pomocnicze,
i za każdym razem robi

insert into g1(a) select a from pom1;
insert into g2(b) select b from pom2;

to wszytko trwa 600 sekund;

puszczam aplikację, która 500 razy przygotowuje tabele pomocnicze,
i za każdym razem robi
start transaction
insert into g1(a) select a from pom1;
insert into g2(b) select b from pom2;
commit

i to wszytko trwa 1600 sekund;


>
> Skończy się RAM, dysk, prąd... proces zostanie zabity.
>

RAM - nie obsłużę, fakt.
Dysk obsłużę
prąd - zależy gdzie. u klienta - chciałbym, żeby mnie to nie obchodziło (o
to właśnie pytal w moim poście); na serwerze ? jest UPS.
zabity proces - u klienta - chciałbym, żeby mnie to nie obchodziło (o to
właśnie pytal w moim poście); na serwerze ? Nikt się nie ośmieli, ew.
dostanie instrukcje,
jak czyścić bazę po zabiciu procesu.

pozdrawiam
pluton


Sławomir Szyszło

unread,
Jan 10, 2012, 4:25:15 PM1/10/12
to
Dnia Tue, 10 Jan 2012 20:27:20 +0100, "pluton" <zielon...@gazeta.pl>
wklepał(-a):

>puszczam aplikację, która 500 razy przygotowuje tabele pomocnicze,
>i za każdym razem robi
>
>insert into g1(a) select a from pom1;
>insert into g2(b) select b from pom2;
>
>to wszytko trwa 600 sekund;
>
>puszczam aplikację, która 500 razy przygotowuje tabele pomocnicze,
>i za każdym razem robi
>start transaction
>insert into g1(a) select a from pom1;
>insert into g2(b) select b from pom2;
>commit
>
>i to wszytko trwa 1600 sekund;

A z czego wynika potrzeba wielokrotnego wstawiania tych danych?
Ile rekordów wstawia taki insert?

pluton

unread,
Jan 11, 2012, 2:05:04 AM1/11/12
to


> A z czego wynika potrzeba wielokrotnego wstawiania tych danych?
> Ile rekord�w wstawia taki insert?

Tak po prostu te dane sp�ywaj�.
Przychodzi pierwsza porcja i trzeba j� pobra�, przychodzi kolejna
i zn�w trzeba ja pobra�...

Inserty wstawiaj� od kilku (pojedyncze sztuki) do 200-300 tysi�cy.
Zazwyczaj s� skorelowane w obydwu tabelach: je�eli w jednej jest kilka,
to i w drugiej podobnie, ale je�eli w pierwszej jest np. 200 tysi�cy, to w
pierwszej jest po�owa tego.

pozdrawiam
pluton


pluton

unread,
Jan 11, 2012, 2:10:06 AM1/11/12
to

> 1. Oczywi�cie, �e mo�e przerwa�.

W jakich okoliczno�ciach ? Zak�adaj�c �e sewrwer bazy si� nie wykolei�.

> 2. Twoje rozwi�zanie jest niepotrzebne, bo wystarczy obydwa inserty da� w
> funkcji (*).

No ja w�a�nie chc� dac oba inserty w funkcji (procedurce wbudowanej)

> 3. Dzia�a to dlatego, �e ka�de zapytanie, kt�re nie jest w transakcji,
> jest automatycznie obj�te transakcj�, kt�ra jest commitowana po jego
> zako�czeniu.

wiem, ale chyba ten fakt nie ma tu nic do rzeczy :)

> 4. Wi�c nie ominiesz problemu z d�ugim commitem.

Musz�, nie mam wyj�cia.


> $f$
> begin
> insert into test values (a1);
------------------------------------czy engine bazy mo�e z jakichkolwiek
przyczyn (np. zerwanie polaczenia z klientem wywolujacym)
------------------------------------przerwac wykonanie procedury w tym
miejscu ???
> insert into test values (a2);
> return true;
> end;

pozdrawiam
pluton


wojte...@gmail.com

unread,
Jan 11, 2012, 2:23:19 AM1/11/12
to
On Tuesday, January 10, 2012 6:30:36 PM UTC+1, pluton wrote:
> Czy raz odpalona procka pójdzie jak czo³g a¿ zrobi co ma zrobiæ (zak³adaj±c
> ¿e nie bêdzie b³êdów) , czy te¿ engine
> bazy mo¿e z jakichkolwiek powodów przerwaæ prockê ?

Procedury w PL/pgSQL-u są domyślnie wykonywane w transakcji,
AFAIK procedury w SQL-u już nie. Więc jak coś pójdzie nie tak,
to wszystkie zmiany z procedury zostaną wycofane.

Tu masz demonstrację: http://pl.wikibooks.org/wiki/Procedury_sk%C5%82adowane_w_PostgreSQL/Transakcje

w.

pluton

unread,
Jan 11, 2012, 3:05:34 AM1/11/12
to

> Tu masz demonstracj�:
> http://pl.wikibooks.org/wiki/Procedury_sk%C5%82adowane_w_PostgreSQL/Transakcje

Bardzo ciekawe informacje. Teraz musz� sobie poprzestawia� w g�owie, bo
mia�em troch� inny obraz.

wielkie dzi�ki.

pozdrawiam
pluton


hubert depesz lubaczewski

unread,
Jan 11, 2012, 5:22:35 AM1/11/12
to
On 2012-01-11, wojte...@gmail.com <wojte...@gmail.com> wrote:
> Procedury w PL/pgSQL-u są domyślnie wykonywane w transakcji,
> AFAIK procedury w SQL-u już nie. Więc jak coś pójdzie nie tak,

te w sql'u też.

depesz

--
The best thing about modern society is how easy it is to avoid contact with it.
http://depesz.com/

pluton

unread,
Jan 12, 2012, 8:10:57 AM1/12/12
to

>> Procedury w PL/pgSQL-u są domyślnie wykonywane w transakcji,
>> AFAIK procedury w SQL-u już nie. Więc jak coś pójdzie nie tak,
>
> te w sql'u też.
>

Dzięki wielkie, wszystko działa po mojej myśli.
Procka zachowuje się tak, jakby po BEGIN było start trans
a przed END - commit;

Jeżeli w pierwszym wywołaniu wstawię do tabeli wartość x,
a w równoległym wywołaniu wstawię to samo i naruszę unikalność
indeksu, to drugie wywołanie pod koniec wykonania wywala błąd.

Tylko ciekawostka taka, że to samo wykonane 'po stronie klienta'
działa 3 razy dłużej, niż wywołane w procedurce wbydowanej :)

pozdrawiam
pluton


wojte...@gmail.com

unread,
Jan 14, 2012, 7:14:07 AM1/14/12
to dep...@depesz.com
On Wednesday, January 11, 2012 11:22:35 AM UTC+1, depesz wrote:
> On 2012-01-11, wojte...@gmail.com <wojte...@gmail.com> wrote:
> > Procedury w PL/pgSQL-u są domyślnie wykonywane w transakcji,
> > AFAIK procedury w SQL-u już nie. Więc jak coś pójdzie nie tak,
>
> te w sql'u też.

Planer może niektóre procedury SQL-owe inlinować, wówczas
chyba transakcja odpada.

w.

hubert depesz lubaczewski

unread,
Jan 14, 2012, 8:04:07 AM1/14/12
to
On 2012-01-14, wojte...@gmail.com <wojte...@gmail.com> wrote:
> Planer może niektóre procedury SQL-owe inlinować, wówczas
> chyba transakcja odpada.

nie. każde zapytanie jest w transakcji - albo explicite podanej albo
zaczynanej/kończonej automatycznie. więc nieważne co się stanie - czy
będzie rule przepisujący zapytanie, czy będzie funkcja - całość jest
zawsze w transakcji.

wojte...@gmail.com

unread,
Jan 14, 2012, 9:59:08 AM1/14/12
to dep...@depesz.com
On Saturday, January 14, 2012 2:04:07 PM UTC+1, depesz wrote:
> On 2012-01-14, wojte...@gmail.com <wojte...@gmail.com> wrote:
> > Planer może niektóre procedury SQL-owe inlinować, wówczas
> > chyba transakcja odpada.
>
> nie. każde zapytanie jest w transakcji - albo explicite podanej albo
> zaczynanej/kończonej automatycznie. więc nieważne co się stanie - czy
> będzie rule przepisujący zapytanie, czy będzie funkcja - całość jest
> zawsze w transakcji.

Dzięki za wyjaśnienie. :)

w.
0 new messages