DB2 - pobieranie wyniku z SELECT'a
Kolszew - 28-08-2007 00:08
DB2 - pobieranie wyniku z SELECT'a
Zaczynam dopiero z DB2 LUW ...
Mam problem. Jeżeli ktoś zmodyfikuje wiersz i nie zakończy transakcji to na innym stanowisku zapytanie SELECT pobierające listę z tej tabeli na ekran (do przeglądania) blokuje się (czeka). Chodzi to jak mniemam o blokadę wiersza która uniemożliwia założenie blokady "shared" wymaganej do odczytania wiersza przy domyślnym poziomie separacji transakcji.
Czy nie da się tego ominąć? Czy czytane danych tylko do przeglądania nie może nie zakładać blokady "shared"? Słyszałem coś o kursorach "readonly", jak zrobić aby aplikacja w Javie (via JDBC) otwierała takie kursory dla ResultSet'ów?
Pozdro Krzysiek
Artur - 28-08-2007 00:08
On Aug 27, 1:04 pm, Kolszew <WYTNIJTOkrzysiekWYTNIJTO...@stream.com.pl> wrote: > Zaczynam dopiero z DB2 LUW ... > > Mam problem. > Jeżeli ktoś zmodyfikuje wiersz i nie zakończy transakcji to > na innym stanowisku zapytanie SELECT pobierające listę > z tej tabeli na ekran (do przeglądania) blokuje się (czeka). > Chodzi to jak mniemam o blokadę wiersza która uniemożliwia > założenie blokady "shared" wymaganej do odczytania wiersza > przy domyślnym poziomie separacji transakcji. > > Czy nie da się tego ominąć? Czy czytane danych tylko do > przeglądania nie może nie zakładać blokady "shared"? > Słyszałem coś o kursorach "readonly", jak zrobić aby > aplikacja w Javie (via JDBC) otwierała takie kursory dla > ResultSet'ów? > > Pozdro > Krzysiek
Blokady zakładane są po to by odczytać spójne dane -- zapytanie czeka na zatwierdzenie lub wycofanie zmian.
Jeśli nie chcesz czekać na blokady, wtedy możesz przeczytać aktualną zawartość poprzez poziom izolacji uncommited read -- ale czytanie niezatwierdzonych danych nie zawsze jest dobrym rozwiązaniem. Poziom izolacji możesz określić na poziomie danego zapytania SQL lub jako parametr połączenia.
W DB2 powinno się projektować aplikacje tak, by modyfikacje były wysyłane do bazy danych jako paczka. Np. kiepskim rozwiązaniem jest modyfikowanie części danych (transakcja rozpoczęta), a potem oczekiwanie na dalsze decyzje użytkownika. DB2 w miarę dobrze będzie kolejkowało żądania do danych, więc ewentualne zapytania przy takiej organizacji nie będą wstrzymywane zbyt długo (milisekundy).
Ogólnie spójność danych jest jednym z poważniejszych zagadnień,jakie powinien zaadresować twórca aplikacji. Zwykle w przypadku aplikacji bazodanowych chcemy czytać spójne dane (spójny odczyt), ale także chcemy odczytane dane potem wykorzystać do dalszych modyfikacji (spójny zapis). Np. jeśli pan X wypłaca pieniądze z konta, to jego żona robiąc to samo chwilę później z innej części kraju poczeka by dowiedzieć się, ile zostało po operacji, ponieważ na tej podstawie zwykle podejmuje decyzję "ile wypłacić".
W DB2 masz do dyspozycji: -- poziomy izolacji ANSI pozwalające na zablokowanie odczytanych danych (w trybie do odczytu bądź na wyłączność), tak by możnabyło potem zrobić odpowiednie modyfikacje -- poziomy izolacji możesz ustawić na poziomie danego zapytania, sesji bądź programu (tu: pakietu). -- masz do dyspozycji specjalne zmienne rejestrowe, które zmieniają zachowanie poziomów izolacji ANSI (DB2_SKIPINSERTED, DB2_SKIPDELETED, DB2_EVALUNCOMMITTED) -- w 9.5 (jeśli dopiero tworzysz aplikację) masz do dyspozycji, tzw. optymistyczne blokowanie rekordów (czytasz zestaw rekordów; przetwarzasz w aplikacji; i dopiero w momencie modyfikacji sprawdzasz, czy ktoś w międzyczasie nie zmienił zestawu rekordów -- jeśli tak musisz powtórzyć operację). -- masz też do dyspozycji tzw. selekt z insert, delete lub update, które pozwolą ci spójnie zrobić jakąś operację w jednym kroku.. Np. instrukcja poniżej usuwa z tabeli rekord, który jest najstarszy a następnie zwraca usunięty rekord do aplikacji (zamiast 3 instrukcji, tylko 1):
SELECT ordernum, ... INTO :ordernum, ... FROM OLD TABLE(DELETE FROM (SELECT * FROM orders ORDER BY ordernum FETCH FIRST ROW ONLY));
Ogólnie najlepiej tak projektować aplikacje, by różni użytkownicyjak najmniej pracowali na tych samych zestawach danych w tym czasie (ważne są kryteria wyszukiwania oraz indeksy).
-- Artur Wroński
Link do dokumentacji 9.5 (poszukaj, isolation level, optimistic locking): https://publib.boulder.ibm.com/infoc.../starthere.htm
Kolszew - 29-08-2007 00:11
> Blokady zakładane są po to by odczytać spójne dane -- zapytanie czeka > na zatwierdzenie lub wycofanie zmian. > > Jeśli nie chcesz czekać na blokady, wtedy możesz przeczytać aktualną > zawartość poprzez poziom izolacji uncommited read -- ale czytanie > niezatwierdzonych danych nie zawsze jest dobrym rozwiązaniem. Poziom > izolacji możesz określić na poziomie danego zapytania SQL lub jako > parametr połączenia. > >
Dzięki. Rozumiem kwestię i sprawa dla mnie jest dosyć jasna, przy przetwarzaniu danych jak najbardziej oczekiwany jest spójny obraz bazy, więc blokady są jak najbardziej ok. Chodzi mi natomiast o taki banalny aspekt aplikacji jak tabelki (np. JTable) z danymi które służą do przeglądania danych (są read only) na ekranie. Ktoś przeglądający listę towarów ich, nazwy, cechy, stany nie ma potrzeby aby czekał aż ktoś inny zakończy transakcję sprzedaży zmniejszającą stan jednego z towarów, bo i tak dane w tej tabeli (ekran) pochodzą z momentu zapytania do bazy czyli z definicji po chwili są nieaktualne. Problem ten rozwiązuje poziom transakcji ReadComited dostępnym w innych RDBMS'ach w DB2 go nie ma.
Znalazłem Twoją odpowiedź na jeden w wcześniejszych postów, cytuję:
"W domyślnym poziomie izolacji (cursor stability) utrzymywana jest blokada SHARED na wierszu, który aktualnie jest przetwarzany. SHARED, tzn. inni nie mogą zmienić wiersza, ale mogą go zobaczyć. Przy czym taka blokada jest zakładana jeśli kursor jest for UPDATE. Jeśli kursor jest FOR READ ONLY, wtedy tak naprawdę pracuje się na kopii danych."
jak dobrze rozumiem to dla kursorów ReadOnly nie zakładana jest blokada SHARED, czyli można czytać wiersze zmodyfikowane w niezatwierdzonych jeszcze transakcjach, dobrze myślę?
Krzysiek
Artur - 29-08-2007 00:11
On Aug 28, 1:55 pm, Kolszew <WYTNIJTOkrzysiekWYTNIJTO...@stream.com.pl> wrote: > > Blokady zakładane są po to by odczytać spójne dane -- zapytanieczeka > > na zatwierdzenie lub wycofanie zmian. > > > Jeśli nie chcesz czekać na blokady, wtedy możesz przeczytać aktualną > > zawartość poprzez poziom izolacji uncommited read -- ale czytanie > > niezatwierdzonych danych nie zawsze jest dobrym rozwiązaniem. Poziom > > izolacji możesz określić na poziomie danego zapytania SQL lub jako > > parametr połączenia. > > Dzięki. Rozumiem kwestię i sprawa dla mnie jest dosyć jasna, > przy przetwarzaniu danych jak najbardziej oczekiwany jest spójny > obraz bazy, więc blokady są jak najbardziej ok. > Chodzi mi natomiast o taki banalny aspekt aplikacji jak tabelki (np. > JTable) z danymi które służą do przeglądania danych (są read only) na > ekranie. Ktoś przeglądający listę towarów ich, nazwy, cechy, stany nie > ma potrzeby aby czekał aż ktoś inny zakończy transakcję sprzedaży > zmniejszającą stan jednego z towarów, > bo i tak dane w tej tabeli (ekran) pochodzą z momentu zapytania do bazy > czyli z definicji po chwili są nieaktualne. Problem ten rozwiązuje > poziom transakcji ReadComited dostępnym w innych RDBMS'ach w DB2 go niema. > > Znalazłem Twoją odpowiedź na jeden w wcześniejszych postów, > cytuję: > > "W domyślnym poziomie izolacji (cursor stability) utrzymywana jest > blokada SHARED na wierszu, który aktualnie jest przetwarzany. SHARED, > tzn. inni nie mogą zmienić wiersza, ale mogą go zobaczyć. Przy czym > taka blokada jest zakładana jeśli kursor jest for UPDATE. Jeśli kursor > jest FOR READ ONLY, wtedy tak naprawdę pracuje się na kopii danych." > > jak dobrze rozumiem to dla kursorów ReadOnly nie zakładana jest blokada > SHARED, czyli można czytać wiersze zmodyfikowane w niezatwierdzonych > jeszcze transakcjach, dobrze myślę? > > Krzysiek
W DB2 nie ma poziomu izolacji Read Commited.
Opisywany przeze mnie fragment dotyczy sytuacji, gdy ktoś czyta kursorem tabelę w trybie Cursor Stability. Jeśli zapytanie jest typu Read Only, to wtedy mimo odczytania rekordu i spozycjonowaniu kursora na tym rekordzie inni użytkownicy będą mogli zmodyfikować dokładni ten sam rekord. Natomiast jeśli już ktoś inny już go zmodyfikował a my potem zabieramy się za czytanie rekordów (inna kolejność), to w tym poziomie izolacji trzeba będzie poczekać na zatwierdzenie transakcji modyfikującej rekord.
[Tak na marginesie, jeśli kursor nie byłby For Read Only wtedy po odczytaniu rekordu, bieżący, przetwarzany rekord nie może być zmodyfikowany przez innych, ze względu na blokadę shared]
Jeśli modyfikacje wystartowane przed uruchomieniem selekta są krótkie, to opóźnienie w selekcie nie będzie większe niż przy wykonywaniu zapytania w trybie Read Commited, który musi wykonać trochę pracy związanej z wersjonowaniem rekordu.
Jeśli przewidujesz długie transakcje a nie interesuje Cię dokładna wartość, wtedy możesz zastosować tryb uncommited read -- oczywiście czytasz dane niezatwierdzone, ale w opisanym przez Ciebie przypadku i tak to nie ma większego znaczenia.
-- Artur Wroński
Kolszew - 30-08-2007 00:01
> W DB2 nie ma poziomu izolacji Read Commited. > > Opisywany przeze mnie fragment dotyczy sytuacji, gdy ktoś czyta > kursorem tabelę w trybie Cursor Stability. Jeśli zapytanie jest typu > Read Only, to wtedy mimo odczytania rekordu i spozycjonowaniu kursora > na tym rekordzie inni użytkownicy będą mogli zmodyfikować dokładni ten > sam rekord. Natomiast jeśli już ktoś inny już go zmodyfikował a my > potem zabieramy się za czytanie rekordów (inna kolejność), to w tym > poziomie izolacji trzeba będzie poczekać na zatwierdzenie transakcji > modyfikującej rekord. > > [Tak na marginesie, jeśli kursor nie byłby For Read Only wtedy po > odczytaniu rekordu, bieżący, przetwarzany rekord nie może być > zmodyfikowany przez innych, ze względu na blokadę shared] > > Jeśli modyfikacje wystartowane przed uruchomieniem selekta są > krótkie, to opóźnienie w selekcie nie będzie większe niż przy > wykonywaniu zapytania w trybie Read Commited, który musi wykonać > trochę pracy związanej z wersjonowaniem rekordu. > > Jeśli przewidujesz długie transakcje a nie interesuje Cię dokładna > wartość, wtedy możesz zastosować tryb uncommited read -- oczywiście > czytasz dane niezatwierdzone, ale w opisanym przez Ciebie przypadku i > tak to nie ma większego znaczenia. > > -- Artur Wroński
Dzięki za szczegółowe wyjaśnienia. Ostatnie pytanie, czy w DB2 nie jest planowany jakiś mechanizm który zrekompensował by brak ReadComited? Czy ten brak w praktyce jest w ogóle dotkliwy, czytałem kilka razy posty osób opisujących problemy lawinowego przyrostu blokad w DB2, czytałem też artykuł gościa z ORACLE'a który jawnie określił sposób blokowania w DB2 jako największą wadę tej bazy.
Krzysiek.
Artur - 01-09-2007 00:17
On Aug 29, 10:20 am, Kolszew <WYTNIJTOkrzysiekWYTNIJTO...@stream.com.pl> wrote: > > W DB2 nie ma poziomu izolacji Read Commited. > > > Opisywany przeze mnie fragment dotyczy sytuacji, gdy ktoś czyta > > kursorem tabelę w trybie Cursor Stability. Jeśli zapytanie jest typu > > Read Only, to wtedy mimo odczytania rekordu i spozycjonowaniu kursora > > na tym rekordzie inni użytkownicy będą mogli zmodyfikować dokładni ten > > sam rekord. Natomiast jeśli już ktoś inny już go zmodyfikowała my > > potem zabieramy się za czytanie rekordów (inna kolejność), to wtym > > poziomie izolacji trzeba będzie poczekać na zatwierdzenie transakcji > > modyfikującej rekord. > > > [Tak na marginesie, jeśli kursor nie byłby For Read Only wtedy po > > odczytaniu rekordu, bieżący, przetwarzany rekord nie może być > > zmodyfikowany przez innych, ze względu na blokadę shared] > > > Jeśli modyfikacje wystartowane przed uruchomieniem selekta są > > krótkie, to opóźnienie w selekcie nie będzie większe niż przy > > wykonywaniu zapytania w trybie Read Commited, który musi wykonać > > trochę pracy związanej z wersjonowaniem rekordu. > > > Jeśli przewidujesz długie transakcje a nie interesuje Cię dokładna > > wartość, wtedy możesz zastosować tryb uncommited read -- oczywiście > > czytasz dane niezatwierdzone, ale w opisanym przez Ciebie przypadku i > > tak to nie ma większego znaczenia. > > > -- Artur Wroński > > Dzięki za szczegółowe wyjaśnienia. > Ostatnie pytanie, czy w DB2 nie jest planowany jakiś mechanizm > który zrekompensował by brak ReadComited? Czy ten brak w > praktyce jest w ogóle dotkliwy, czytałem kilka razy posty osób > opisujących problemy lawinowego przyrostu blokad w DB2, czytałem > też artykuł gościa z ORACLE'a który jawnie określił sposób > blokowania w DB2 jako największą wadę tej bazy. > > Krzysiek.
W praktyce sposób blokowania nie jest problem. Oczywiście trzeba być świadomym faktu, że blokowanie ogranicza dostępność i dlatego transakcje powinny być możliwie krótkie. Przy czym tak naprawdę wiele osób pisze aplikacje na żywioł, nie zastanawiając się nad tym, jak chcą obsłużyć przypadki, gdy wielu użytkowników chce pracowaćna tych samych danych. W przypadku Oracle, mamy możliwość czytania starej wersji danych, nie mamy problemów z oczekiwaniem na blokady przy zapytaniach, ale nieprzemyślane użycie tego poziomu izolacji może doprowadzać do niespójności przy zapisie danych. Przykład: w systemach transakcyjnych, zwykle czyta się dane po to, by potem na podstawie odczytanych wartości wykonać odpowiedni zapis. Wielu deweloperów, z którym rozmawiałem tworzą aplikację pod Oracle wykorzystując blokady dokładnie w taki sam sposób jak w DB2. Czytasz blokując jednocześnie do zapisu, zapisujesz, zwalniasz blokady.
Zwróć też uwagę, że wersjonowanie rekordów jest stosunkowo kosztowną operacją. W efekcie finalnym zapytanie oczekujące na zakończenie update, niekoniecznie wykona się dłużej niż zapytanie które nie oczekuje, ale baza zajęta jest przygotowywaniem starej wersji rekordu (może zły przykład, ale weź kopiowanie dwóch plik z dysku na dysk. Jeśli to oba pliki zaczniesz kopiować w tym samym czasie, masz wrażenie, że wszystko dzieje się współbieżnie, ale w praktyce byłoby dużo szybciej, by system zaczął kopiować pierwszy plik (drugi czekaw kolejce) a potem drugi).
Co do "rekompensaty" to mogę tylko powtórzyć, to co już napisałem. Zmienne DB2_SKIPINSERTED, DB2_SKIPDELETED, DB2_EVALUNCOMMITTED pozwalają nie oczekiwać na blokady (dla poziomy izolacji Cursor Stability) dla rekordów wstawionych bądź usuniętych (są niewidoczne dla drugiej sesji). DB2_EVALUNCOMMITTED pozwala ci zignorować zablokowany wiersz, jeśli dane w środku wiersza nie pasują do twojego kryterium wyszukiwania.
Innymi technikami jest optymistyczny sposób blokowania danych dostępny w DB2 9.5 oraz delete z selekta, selekt z delete, update, insert. W jednym kroku czytasz i zmieniasz rekordy (albo zmieniasz i zwracasz to co było zmienione), np zobacz na to:
SELECT ordernum, ... INTO :ordernum, ... FROM OLD TABLE(DELETE FROM (SELECT * FROM orders ORDER BY ordernum FETCH FIRST ROW ONLY));
Pewnie w przyszłości także pojawi się taki poziom izolacji (2008?), ale jak powiedziałem w praktyce nie jest to problemem (patrz testy wydajnościowe TPC, czy testy aplikacji SAP -- produkcyjne i laboratoryjne. Wypadają bardzo dobrze na tle Oracle).
-- Artur
Kolszew - 06-09-2007 00:04
> > Pewnie w przyszłości także pojawi się taki poziom izolacji (2008?), > ale jak powiedziałem w praktyce nie jest to problemem (patrz testy > wydajnościowe TPC, czy testy aplikacji SAP -- produkcyjne i > laboratoryjne. Wypadają bardzo dobrze na tle Oracle). >
Dzięki.
Krzysiek
PS Twoje posty w tym wątku to jedne z najlepszych merytorycznie odpowiedzi jakie widziałem na tej liście.
zanotowane.pldoc.pisz.plpdf.pisz.pleffulla.pev.pl
|
[help] Illustrator CS - =?ISO-8859-2?Q?znikn=B1=B3_Selection_?==?ISO-8859-2?Q?Tool_=28V=29?=
[mysql 4.0] SELECT t1.id, t1.foo FROM t1 oraz COUNT t2 w jednym zapytaniu.
SELECT MAX(nazwaPola) FROM tabela WHERE .... i ORA-01405: pobran? warto?ci? kolumny jest NULL
=?iso-8859-2?q?select_sum_i_dwie_tabele..._b=B3=EAdna_agregac ja?=
=?iso-8859-2?Q?=5BMySql=5D_-_select_po_5_rekordow_mniejssych_i_wi=EAkszych?=
=?iso-8859-2?Q?=5BMySql=5D_Select_wed=B3ug_nazwy_pola?=
=?ISO-8859-2?Q?[mysql]_Nie_potrafi=EA_zgrupowa=E6_selecta_(proste)?=
=?ISO-8859-2?Q?[MS_SQL]_update_wielu_p=F3l_na_raz_z_selecta?=
Wstawianie nowego wiersza w przypadku jego braku podczas SELECT w PostgreSQL
[pgsql] jak =?ISO-8859-2?Q?zrobi=E6_taki_select_=3F?=
zanotowane.pldoc.pisz.plpdf.pisz.plfantazia.htw.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 |
|