[MS SQL] System transakcyjny wybieranie kolejnych rekordow
Krzysztof - 25-11-2006 00:07
[MS SQL] System transakcyjny wybieranie kolejnych rekordow
Witam jestem tu nowy i nie wiem czy temat juz byl omawiany jesli tak to prosze o info jak szukac bo sam nie znalazlem. A teraz do rzeczy.
Mam baze danych w ktorej w pojedynczych rekordach przechowywane sa unikalne kody. Dzialanie systemu polega na wydawaniu unikalnych kodow. Kody naleza do "paczkek" i maja byc wydawane zgodnie z zasada FIFO ale w obrebie paczek. Czyli najpierw wydajemy kody z paczki pierwszej ale nie musimy juz kontrolowac ktory to byl kod w paczce. Wazne zeby nie wydac dwa razy tego samego kodu. System wydaje kody kilkadziesiat razy w ciagu doby. A problemem jest to ze zdarzaja mi sie sytuacje zglaszane jako "deadlock" polega to na wydaniu wewnatrz procedury tego samego kodu (rekordu) dla dwoch roznych procesow. Moje rozwiazanie ktore ma zabezpieczac (choc nie zawsze to robi) nie wybranie tego samego kodu jest pole "satus" w rekordzie z kodem ktore jest updatowane po wybraniu kodu. Prosze po podsunieci pomyslu jak cos takiego powinno wygladac bo jak widac moje rozwiazanie jest niedoskonale.
Z gory dziekuje Krzysztof
-- Wysłano z serwisu OnetNiusy: http://niusy.onet.pl
Grzesiek G. - 25-11-2006 00:07
Krzysztof napisał(a): > Witam jestem tu nowy i nie wiem czy temat juz byl omawiany jesli tak to prosze o > info jak szukac bo sam nie znalazlem. A teraz do rzeczy. > > Mam baze danych w ktorej w pojedynczych rekordach przechowywane sa unikalne > kody. Dzialanie systemu polega na wydawaniu unikalnych kodow. Kody naleza do > "paczkek" i maja byc wydawane zgodnie z zasada FIFO ale w obrebie paczek. Czyli > najpierw wydajemy kody z paczki pierwszej ale nie musimy juz kontrolowac ktory > to byl kod w paczce. Wazne zeby nie wydac dwa razy tego samego kodu. System > wydaje kody kilkadziesiat razy w ciagu doby. A problemem jest to ze zdarzaja mi > sie sytuacje zglaszane jako "deadlock" polega to na wydaniu wewnatrz procedury > tego samego kodu (rekordu) dla dwoch roznych procesow. > Moje rozwiazanie ktore ma zabezpieczac (choc nie zawsze to robi) nie wybranie > tego samego kodu jest pole "satus" w rekordzie z kodem ktore jest updatowane po > wybraniu kodu. > Prosze po podsunieci pomyslu jak cos takiego powinno wygladac bo jak widac moje > rozwiazanie jest niedoskonale.
Ciężko coś poradzić bez znajomości schematu. W sumie chodzi o odpowiednie blokady. Spróbuj coś takiego: 1. Oznaczenie kodu jako wydanego jednym updatem, bez wcześniejszych selectów: UPDATE tabela SET Status=Wydany,PID=@P@PID WHERE NumerPaczki=@Numer paczki, NrKodu=(SELECT MAX(NrKodu)+1 FROM tabela WHERE NumerPaczki=@NumerPaczki AND Status=Wydany) 2. Pobranie numeru paczki: SELECT NumerPaczki FROM tabela WHERE NumerPaczki=@NumerPaczki AND PID = @@PID. 3. Wyzerowanie PIDa po pobranym numerze paczki.
Oczywiście możne też zablokować tabelę na początku transakcji.
Pozdrawiam
PS: Deadlock to coś innego:-)
-- Grzegorz Gruza Odpowiadając usuń "spamerom_nie." z adresu!!!
Grzesiek G. - 25-11-2006 00:07
Zamiast @@PID miało być @@PROCID.
-- Grzegorz Gruza Odpowiadając usuń "spamerom_nie." z adresu!!!
Artur - 25-11-2006 00:07
By uniknąć deadloków możesz zrobić tak:
tabela ------------- id kod 1 kod1 2 kod2 3 kod3 .......... gdzie id jest kolejnym numerem, a kod twoim kodem, który pobierasz.
Utworz indeks na id.
Utworz sekwencję w bazie, np. sekw1, która rozpoczyna się od 1 (np. z parametrem cache np. 20, co będzie generowało paczki co 20-ścia wartości).
w procedurze udpstępniającej kody pobierz następna wartość z sekwencji (będzie unikatowa) i dla niej pobierz odpowiedni kod z bazy o takim id -- masz gwartancję, że kolejne wywołania nie będą pobierały tych samych rekordów. Po pobraniu rekordu uaktualnij status, by później wiedzieć, czy rzeczywiście kod został pobrany. Rekord powinieneś pobierać w trybie izolacji ANSI Repeatable Read, co będzie oznaczało, że rekord odczytany będzie automatycznie zablokowany do modyfikacji -- najpierw upewnisz się, czy rzeczywiście kod nie został już wydany, a następnie zrobisz update. Ten poziom izolacji gwarantuje, że nikt ci nie zmodyfikuje rekordu pomiędzy odczytaniem a zapisem statusu dla tego rekordu. Tak na wszelki wypadek, choć pewnie nie będzie to konieczne.
Jedyn problem to taki, że jeśli wycofasz transakcję, wtedy licznik sekwencji będzie się kręcił dalej, a dany kod nie będzie wydany. W takiej sytuacji co jakiś czas będziesz musiał zrobić coś z kodami, które nie zostały wydane z tego powodu (znasz statusy), np zwiększysz id na max(id) +1, wtedy będą wydane na samym końcu.
To tylko przykład, tak naprawdę nie wiem jakie sa założenia "paczek" i znaczenie twoich kodów, ale jeśli są to np. kody do telefonów na kartę, wtedy będzie działało szybko i bez deadloków.
-- Artur Wroński
Krzysztof - 26-11-2006 00:15
Witam {ciach} > Ciężko coś poradzić bez znajomości schematu. W sumie chodzi o > odpowiednie blokady. Spróbuj coś takiego: > 1. Oznaczenie kodu jako wydanego jednym updatem, bez wcześniejszych > selectów: > UPDATE tabela SET Status=Wydany,PID=@P@PID WHERE NumerPaczki=@Numer > paczki, NrKodu=(SELECT MAX(NrKodu)+1 FROM tabela WHERE > NumerPaczki=@NumerPaczki AND Status=Wydany) > 2. Pobranie numeru paczki: > SELECT NumerPaczki FROM tabela WHERE NumerPaczki=@NumerPaczki AND PID = > @@PID. > 3. Wyzerowanie PIDa po pobranym numerze paczki. >
Nie bardzo rozumiem jak to dziala, mozesz mi to wytlumaczyc? > > Oczywiście możne też zablokować tabelę na początku transakcji. > Nie wchodzi w gre.System jest na tyle obciazony ze spowodowaloby to totalna zapasc.
> Pozdrawiam > > PS: Deadlock to coś innego:-)
Tak wiem i tez najpierw szukalem klasyczneo deadlock'a szukalem trzy dni i nie znalazlem i okazalo sie ze blad zglaszany jako deadlock to sytuacja gdy dwa rozne procesy wybiora ten sam kod, Sam tego nie rozumiem ale tak jest.
Krzysztof
-- Wysłano z serwisu OnetNiusy: http://niusy.onet.pl
Krzysztof - 26-11-2006 00:15
Witam
> By uniknąć deadloków możesz zrobić tak: > > tabela > ------------- > id kod > 1 kod1 > 2 kod2 > 3 kod3 > ......... > gdzie id jest kolejnym numerem, a kod twoim kodem, który pobierasz. > > Utworz indeks na id. > > Utworz sekwencję w bazie, np. sekw1, która rozpoczyna się od 1 (np. > z parametrem cache np. 20, co będzie generowało paczki co 20-ścia > wartości). > > > w procedurze udpstępniającej kody pobierz następna wartość z > sekwencji (będzie unikatowa) i dla niej pobierz odpowiedni kod z bazy > o takim id -- masz gwartancję, że kolejne wywołania nie będą > pobierały tych samych rekordów. Po pobraniu rekordu uaktualnij > status, by później wiedzieć, czy rzeczywiście kod został pobrany. > Rekord powinieneś pobierać w trybie izolacji ANSI Repeatable Read, co > będzie oznaczało, że rekord odczytany będzie automatycznie > zablokowany do modyfikacji -- najpierw upewnisz się, czy rzeczywiście > kod nie został już wydany, a następnie zrobisz update. Ten poziom > izolacji gwarantuje, że nikt ci nie zmodyfikuje rekordu pomiędzy > odczytaniem a zapisem statusu dla tego rekordu. Tak na wszelki wypadek, > choć pewnie nie będzie to konieczne. > > Jedyn problem to taki, że jeśli wycofasz transakcję, wtedy licznik > sekwencji będzie się kręcił dalej, a dany kod nie będzie wydany. W > takiej sytuacji co jakiś czas będziesz musiał zrobić coś z kodami, > które nie zostały wydane z tego powodu (znasz statusy), np > zwiększysz id na max(id) +1, wtedy będą wydane na samym końcu. >
Prezentowany tu przyklad byl juz brany pod uwage i staam go obok wybierania nie kolejnego ale losowego kodu z paczki. Nie zdecydowalem jeszcze ktory bedzie lepszy. Losowanie kodu nie powoduje koniecznosci pisania po tablelach co chyba w moim przypadku bedzie szybsze.
> To tylko przykład, tak naprawdę nie wiem jakie sa założenia > "paczek" i znaczenie twoich kodów, ale jeśli są to np. kody do > telefonów na kartę, wtedy będzie działało szybko i bez deadloków.
Zagadnienie o ktore pytam sprowadza sie bo prostego schematu:
tKody: id_kodu | kod | nr packi | status | dodatkowe_dane ------------------------------------- 1 | k1 | 1 | 1 | dane1 2 | k2 | 1 | 1 | dane1 3 | k3 | 1 | 1 | dane1 4 | k4 | 1 | 1 | dane1
dane dodatkowe sluza do usciclenia jaki kod ma zostac wybrany.
i tak jak wybieram
SELECT kod FROM tKody WHERE dodatkowe_dane = dane1 AND nr paczki = 1 AND status = 1
to dostaje kod k1
i chce osognac taki stan zeby kolejny proces ktory pyta o kod nie dostal juz k1 tylko k2. A dzis mam taki san ze zdarza sie ze dwa procesy dostaja tn sam kod.
Dzis kody pobieram tak:
UPDATE tKody SET status=2, kod = '-1', @code=kod WHERE id_kodu IN ( SELECT TOP 1 id_kodu FROM tKody WHERE tKody.dodatkowe_dane = dane1 AND (tKody.status=1) )
Jak mozna latwo zauwazyc @code zawiera ko ktory wybieram. Informacja dodatkowa po pobraniu zmienim wartosc kodu na "-1" tak zeby\u juz nigdy nie byl uzyty, co oznacza ze dwa procesy odpytuja baz na tyle szybko ze "ten drugi" trafia jeszcze w kod przed zmiana jego wartosci na "-1"
Pozdrawiam Krzysztof
-- Wysłano z serwisu OnetNiusy: http://niusy.onet.pl
Grzesiek G. - 14-12-2006 16:08
Krzysztof napisa?(a): > Witam > {ciach} > >>Ci??ko co? poradzi? bez znajomo?ci schematu. W sumie chodzi o >>odpowiednie blokady. Spróbuj co? takiego: >>1. Oznaczenie kodu jako wydanego jednym updatem, bez wcze?niejszych >>selectów: >>UPDATE tabela SET Status=Wydany,PID=@P@PID WHERE NumerPaczki=@Numer >>paczki, NrKodu=(SELECT MAX(NrKodu)+1 FROM tabela WHERE >>NumerPaczki=@NumerPaczki AND Status=Wydany) >>2. Pobranie numeru paczki: >>SELECT NumerPaczki FROM tabela WHERE NumerPaczki=@NumerPaczki AND PID = >>@@PID. >>3. Wyzerowanie PIDa po pobranym numerze paczki. >> > > > Nie bardzo rozumiem jak to dziala, mozesz mi to wytlumaczyc? >
W sumie to niedok?adny kod, tak?e pewnie nie dzia?a :-. Moja idea by?a taka, ?eby oznacza? zarówno, ?e paczka jest zaj?ta (aktualizacja statusu) jak i kto zaj?? (ustawienie @@PROCID). W powi?zaniu, z odpowiednim poziomem izolacji transakcji (read uncomited) i granulacj? blokad (ROWLOCK) nie b?dzie trzeba czeka? na pobieranie kolejnych numerów. Oczywi?cie, dopuszcza to mo?liwo?? powstawania dziur - jak przy identity:-(.
Dodanie aktualizacji @@PROCID umo?liwi pó?niejsze znalezienie numeru, który zosta? przez proces zarezerwowany.
>>Oczywi?cie mo?ne te? zablokowa? tabel? na pocz?tku transakcji. >> > > Nie wchodzi w gre.System jest na tyle obciazony ze spowodowaloby to totalna zapasc. >
Tak my?la?em. Rzuci?em tak? oczywist? propozycj?, bo blokowanie od razu ca?ej tabeli pozwala unikn?? problemu eskalacji blokad i bywa rozwi?zaniem wystarczaj?co wydajnym.
> >>Pozdrawiam >> >>PS: Deadlock to co? innego:-) > > > Tak wiem i tez najpierw szukalem klasyczneo deadlock'a szukalem trzy dni i nie > znalazlem i okazalo sie ze blad zglaszany jako deadlock to sytuacja gdy dwa > rozne procesy wybiora ten sam kod, Sam tego nie rozumiem ale tak jest.
Rzeczywi?cie dziwne. Mo?e by nale?a?o zg?osi? problem do M$?
Pozdrawiam
-- Grzegorz Gruza Odpowiadaj?c usu? "spamerom_nie." z adresu!!!
zanotowane.pldoc.pisz.plpdf.pisz.pleffulla.pev.pl
|
jak to =?ISO-8859-2?Q?zrobi=E6=2E=2E=2E=3F_TSQL_sql_server?==?ISO-8859-2?Q?_?=
=?iso-8859-2?Q?=5BMS_SQL=5D_Czy_mo=BFna_wywo=B3a=E6_funkcje_t ylko_raz_dla?==?iso-8859-2?Q?_ca=B3ego_zbioru_=BCr=F3d=B3owego=3F?=
[MSSQL] =?ISO-8859-2?Q?zgodno=B6ci_z_licencjami_Microsoft_?==?ISO-8859-2?Q?SQL_Server?=
Oracle PL/SQL Wstawianie =?ISO-8859-2?Q?wynik=F3w_kolekcji_d?==?ISO-8859-2?Q?o_tabeli?=
[MSSQL] ACCESS - SQL =?ISO-8859-2?Q?B=B3ad_w_konwersji_lic?==?ISO-8859-2?Q?zb?=
=?iso-8859-2?Q?=5Bmssql=5D_Zapytania_rekurencyjne__-_czy_sk=B3adnia_sql?==?iso-8859-2?Q?_co=B6_takiego_przewiduje_=3F?=
=?iso-8859-2?Q?=5BMySQL=5D_Co_minimalnie_potrzebne_zeby_mie=E 6_klienta_My?==?iso-8859-2?Q?SQL_na_Linuxie=3F?=
[oracle] - Oracle SQL Developer - co to jest SID?
=?ISO-8859-2?Q?[Oracle]_Wywo=B3anie_skryptu_sh_z_PL/SQL-a=3F=3F?=
[oracle] Baza danych do kursy Introduction to Oracle9i:PL/SQL ? Skąd ją pobrać ?
zanotowane.pldoc.pisz.plpdf.pisz.plautwywalczyl.opx.pl
Cytat
Decede mihi sole - nie zasłaniaj mi słonca. Gdy kogoś kochasz, jesteś jak stworzyciel świata - na cokolwiek spojrzysz, nabiera to kształtu, wypełnia się barwą, światłem. Powietrze przytula się do ciebie, choćby był mróz, a ty masz w sobie tyle radości, że musisz ją rozdawać wokoło, bo się w tobie nie mieści Hoc fac - tak czyń. A tergo - od tyłu; z tyłu. I czarne włosy posiwieją. Safona |
|