konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Witam,
Mam taką tabelkę:
CREATE TABLEserver_commands"(
"id" serial,
"idcudaka" int4 ,
"idpolecenia" int4 ,
"czas" timestamp ,
"status" char(10) ,
"command" varchar(50) ,
"odpowiedz" varchar(80) ,
"czas2" timestamp ,
PRIMARY KEY ("id")
)

Potrzebuję następującego zachowania kolumny idpolecenia w tabeli server_commands.

Przy każdym dodaniu rekordu do tabeli przydzielony jest mu kolejny numer idpolecenia, ale numeracja jest w ramach każdego cudaka osobno, np.

dodajemy rekord dla cudaka "A" - otrzymuje on numer 1 (id polecenia)
dodajemy rekord dla cudaka "A" - otrzymuje on numer 2 (id polecenia)
dodajemy rekord dla cudaka "B" - otrzymuje on numer 1 (id polecenia)
dodajemy rekord dla cudaka "A" - otrzymuje on numer 3 (id polecenia)
dodajemy rekord dla cudaka "B" - otrzymuje on numer 2 (id polecenia)
dodajemy rekord dla cudaka "C" - otrzymuje on numer 1 (id polecenia)
dodajemy rekord dla cudaka "B" - otrzymuje on numer 3 (id polecenia)
dodajemy rekord dla cudaka "B" - otrzymuje on numer 4 (id polecenia)

Numer jest inkrementowany od 0 do MAX_NUMBER. Po osiągnięciu MAX_NUMBER kolejnym przydzielonym numerem jest 0.
Przewiduję docelowo MAX_NUMBER jako 99999.

W bazie nie mogą się powtórzyć dwa rekordy, które będą miały jednakowy id_cudaka i idpolecenia. W szczególności przy próbie dodania takiego powtórzonego rekordu - można usuwać ten stary.


Wiecie może jak to zrobić??


Z góry dzięki za pomoc,
pozdrawiam Łukasz

Temat: PostgreSQL - automatyzacja tabeli

Jak cudaków nie ma za dużo, to może osobna tabela z id'ami?

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

właśnie jest ich dość dużo, i dobrze byłoby to oprzeć na 1 tabeli...

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Łukasz Peta:
właśnie jest ich dość dużo, i dobrze byłoby to oprzeć na 1 tabeli...

W Oracle najprościej byłoby w triggerze BEFORE ROW wypełniać ID za pomocą różnych sekwencji wybieranych zależnie od tej wartości, ale czy tak można w PostgreSQL to nie wiem ...

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

noo ja właśnie mam z tym problem - muszę zrobić, a kompletnie nie wiem jak :((( a Oracle nie ma takiej samej składni jak Postgres??

Temat: PostgreSQL - automatyzacja tabeli

Musiałbyś wtedy porobić mnóstwo sekwencji. I jest jescze problem, że w razie rollbacku sekwencja nie jest cofana(postgresql 8.1).
Widzę jeszcze 2 dodatkowe możliwości:
1. Dzielisz id'y na porcje po max_number i ręcznie zarządzasz nimi. Coś jak stronicowanie pamięci. Wada: problem przy częstym dodawaniu usuwaniu cudaków no i nadmiarowa pamięć.
2. Za każdym razem select z ostatniej komendy cudaka, ale znowu problem indeksów.Włodzimierz Kołodenny edytował(a) ten post dnia 16.11.08 o godzinie 15:09

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

qurcze... :/ a jakieś funkcje (bo postgres ma coś takiego - może tym się da)??
Piotr Ziemian

Piotr Ziemian Starszy Projektant,
Zatrudnienie w
jednej firmie
[1997-ob...

Temat: PostgreSQL - automatyzacja tabeli

Ja zrobiłbym to tak (to nie jest język programowania, tylko zarys rozwiązania):
a) na początek dodałbym indeks co by baza się "pilnowała":
CREATE UNIQUE INDEX i00server_commands ON server_commands(idcudaka,idpolecenia)

b) w procedurze wykonałbym sekwencję poleceń (najlepiej w transakcji)
1. SELECT MAX(idpolecenia) INTO <IDPOLECENIA> FROM server_commands WHERE idcudaka = <IDCUDAKA>
2. <IDPOLECENIA> += 1
3. INSERT INTO server_commands (idpolecenia,idcudaka) VALUES (<IDPOLECENIA>, <IDCUDAKA>)
Jeśli powyższe wykonałoby się z błędem (szczególnie INSERT), to prawdopodobnie trzeba powtórzyć procedurę, bo ktoś inny (w procesie równoległym) "zajął" nam pracowicie określony numer idpolecenia.

c) jeśli postgress ma możliwość tworzenia procedur/funkcji, to może zadziała coś takiego:
INSERT INTO server_commands (idpolecenia,idcudaka) VALUES (getNextIdCudaka(<IDCUDAKA>), <IDCUDAKA>)
gdzie, getNextIdCudaka(a_idcudaka) jest procedurą/funkcją SPL realizującą pierwsze dwa punkty.

Nad wydajnością rozwiązania pomyślałbym dopiero jak powyższe okazałoby się wąskim gardłem.

Pozdrawiam,
Piotr

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Piotr Ziemian:
Nad wydajnością rozwiązania pomyślałbym dopiero jak powyższe okazałoby się wąskim gardłem.

Bardzo szybko zacząłbyś o tym myśleć, bo wydajność będzie spadać niemal wykładniczo :)

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Ja mam jeszcze jedno pytanie z gatunku pomocniczych:
Czy dopuszczalne są dziury w numeracji?
Tak czy siak - zrobiłbym na triggerach i osobnej tabeli z listą "cudaków". Trigger stawiałby appication-locka i w ten sposób zagwarantowałbym synchronizację. Proste select max(idpolecenia) + 1 from server_commands. PG trzyma locka do końca transakcji, więc problem z rollbackiem odpada. Można trzymać ostatnią wartość w tej powiązanej - zależy jak komu wygodniej / optymalniej.

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

noo właśnie jest takie założenie ze to musi być na tej 1 tabeli... numeracja powinna się nie pokrywać - chyba że skończy się "pula", to wtedy usuwa stary wpis, i daje nowy...

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Na jednej tabeli też się da, ale jest wolniej - można stawiać locka na wszystkich rekordach z danego cudaka. Dlatego osobna tabela z cudakami. Jeżeli jest osobna tabela z tymi cudakami i do tego są klucze obce - to i tak locki są stawiane, bo to tak baza zapewnia więzy integralności.

Niezależnie od tego jak to wygląda w żeczywistości - trzeba zrobić triggery na tej tabelce sever_commands. Wiadomo, że będą BEFORE - jakie i jak działające - zależy od projektu. Te triggery albo będą stawiać locka na tabelce z cudakami, albo na server_commands. Skoro nie ma / nie można operować na tabelce z "cudakami" - proszę zrobić trigger BEFORE INSERT robiący select ... for update na tabelce server_commands i na tym testować. Jak zadziała - to po kłopocie ;)Michał Z. edytował(a) ten post dnia 17.11.08 o godzinie 09:41

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

a mógbyś mi pokazać jak to zrobić na 1 tabeli??:)
Igor Piotr I.

Igor Piotr I. IT manager/Senior
Oracle Developer

Temat: PostgreSQL - automatyzacja tabeli

insert into tablica 
(id,cudak,polecenie)
values
(seq_tab.nextval,'A',(select nvl(max(polecenie),0)+1 from tablica where cudak = 'A'));


wydajność i tak będzie lipna
[edit]

NVL(expr1,expr2)
If expr1 is null, NVL returns expr2; if expr1 is not null, NVL returns expr1. The arguments expr1 and expr2 can have any datatype.
Igor Piotr Idzior edytował(a) ten post dnia 17.11.08 o godzinie 11:01

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Łukasz Peta:
noo właśnie jest takie założenie ze to musi być na tej 1 tabeli... numeracja powinna się nie pokrywać - chyba że skończy się "pula", to wtedy usuwa stary wpis, i daje nowy...

Ja zrobiłbym dokładnie tak jak napisał Michał, czyli osobną tabelę z "cudakami".

Wydaje mi się, że te założenie z jedną tabelą jest bez sensu. Możesz napisać kto Cię ogranicza z tą jedną tabelą i dlaczego?
Piotr Ziemian

Piotr Ziemian Starszy Projektant,
Zatrudnienie w
jednej firmie
[1997-ob...

Temat: PostgreSQL - automatyzacja tabeli

Krzysztof P.:
Piotr Ziemian:
Nad wydajnością rozwiązania pomyślałbym dopiero jak powyższe okazałoby się wąskim gardłem.

Bardzo szybko zacząłbyś o tym myśleć, bo wydajność będzie spadać niemal wykładniczo :)
Dlaczego wykładniczo ? Według mnie obciążenie będzie stałe. Wystarczy zauważyć, że zapytanie zwracające ostatni zapis dla cudaka praktycznie wyciąga dane z indeksu, który pilnuje spójności tablicy. Używałem kilku motorów bazy danych (INFORMIX, ORACLE, SQLServer), i w takich przypadkach motor bardzo sprawnie wybiera dane. Niestety nie potrafię powiedzieć jak powyższe zachowuje się w POSTGRESQL, bo nie znam tego silnika. Po za tym nie wiemy jaką wydajność docelową ma przyjąć rozwiązanie. Jeśli powyższych INSERT'ów jest niewiele, to rozwiązanie które wskazałem może być wystarczające dla pytającego.

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Pewnym rozwiązaniem jest dodanie tabeli:

create table nextvals(
idcudaka int4,
nextval int4
)

PK: idcudaka

a potem:

-- 1
@newid = select nextval from nextvals where idcudaka = @x
-- 2
update nextvals set nextval = nextval + 1
where idcudaka = @x and nextval = @newid
-- 3 jesli rows affected = 0 to skok do 1
-- 4
insert into server_commands(idcudaka, idpolecenia...)
values(x, @newid...)


Zalety:
A) Update nie zostawi blokady na rekordzie jeśli się nie powiedzie akwizycja ID
B) tabela server_commands jest odciążona od dodatkowych blokad / lock'ów i "select max()"

Tyle teoria. Jak to w praktyce będzie spróbuj.

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Piotr Likus:

-- 1
@newid = select nextval from nextvals where idcudaka = @x
-- 2
update nextvals set nextval = nextval + 1
where idcudaka = @x and nextval = @newid
-- 3 jesli rows affected = 0 to skok do 1
-- 4
insert into server_commands(idcudaka, idpolecenia...)
values(x, @newid...)

W kroku 1 możesz dodać FOR UPDATE i usunąć krok 3 albo w kroku 2 dodać RETURNING i usunąć kroki 1 i 3:


update nextvals
set nextval = case when nextval = 999999 then 0
else nextval + 1
end
where idcudaka = @x
returning nextval
Wojciech Malinowski edytował(a) ten post dnia 17.11.08 o godzinie 20:19

konto usunięte

Temat: PostgreSQL - automatyzacja tabeli

Wojciech Malinowski:
Piotr Likus:

-- 1
@newid = select nextval from nextvals where idcudaka = @x
-- 2
update nextvals set nextval = nextval + 1
where idcudaka = @x and nextval = @newid
-- 3 jesli rows affected = 0 to skok do 1
-- 4
insert into server_commands(idcudaka, idpolecenia...)
values(x, @newid...)

W kroku 1 możesz dodać FOR UPDATE i usunąć krok pierwszy albo w kroku 2 dodać RETURNING i usunąć kroki 1 i 3:

Pewnie to lepsze, ale pracuje na wielu bazach równolegle, więc nie znam dokładnie wszystkich funkcji/zalet tej konkretnej bazy.

Pozdrawiam przy okazji wszystkich którzy rozpoczynają wypowiedź od "bo u nas w Oracle'u..." ;-)



Wyślij zaproszenie do