You are on page 1of 84

SDJ Extra 35

Spis treści 40 <XML> w praktyce


Marcin Molak
W ramach artykułu przedstawione zostają przykładowe zastoso-
wania dokumentów XML i ich pełna obsługa w bazie danych IBM
Przegląd funkcjonalności DB2. Kolejne przykłady wprowadzają czytelnika w świat technolo-
4 Nowości IBM DB2 9.7 gii IBM pureXML.
Artur Wroński, Marcin Molak
Artykuł wprowadza w nowe funkcjonalności, które pojawiły się w 50 Poziomy izolacji w DB2
wersji IBM DB2 9.7. Artur Wroński, Krzysztof Mikołajewski
W ramach artykułu autorzy poruszają tematykę właściwego wy-
Integracja danych korzystania poziomów izolacji celem zapewnienia maksymal-
nej współbieżności aplikacji. Przedstawiona jest również koncep-
8 Integracja DB2 z bazami danych Oracle cja optymistycznego blokowania, coraz bardziej popularna wśród
Paweł Drzymała, Henryk Welfle programistów.
Mechanizm federacji w IBM DB2 pozwala na wirtualny dostęp do
danych zarządzanych przez serwery baz danych różnych produ-
centów. Artykuł przedstawia kolejne kroki w konfiguracji środo- Administracja
wiska, które pozwalają na zintegrowanie bazy danych IBM DB2 z 60 Backup od A do Z
Oracle DB. Artur Wroński
W artykule autor opisuje dostępne w DB2 techniki tworzenia kopii
Tworzenie aplikacji zapasowych. Szczegółowo omawia backup online i offline. Porusza
także bardziej zaawansowane zagadnienia, takie jak odtwarzanie
14 Procedury składowane w DB2 9 obszarów tabel przy pracującej bazie danych, czy backup bardzo
Dariusz Depta dużych baz danych.
Artykuł przybliża tworzenie procedur składowanych w bazach IBM
DB2. Autor koncentruje się nie tylko na podstawowych konstruk- 70 Mechanizm zarządzania obciążeniem w DB2
cjach języka SQL PL, ale porusza również tematy zaawansowane, Rafał Stryjek, Przemysław Kantyka
takie jak wykonywanie kodu dynamicznego czy obsługa błędów. Autorzy prezentują poszczególne etapy związane z uruchamia-
niem menadżera obciążeń w IBM DB2.
34 DB2 COBRA – Converting Oracle Becomes Re-
ally Affordable 78 Kompresja w DB2
Marcin Molak Artur Wroński
Autor opisuje nowe funkcjonalności, wprowadzone w wersjach Autor na przykładzie przedstawia mechanizmy kompresji danych
IBM DB2 9.5 i 9.7, ułatwiające proces migracji aplikacji opartych na w IBM DB2 9.7, m.in mechanizm kompresji tabel, indeksów, bac-
serwerze Oracle DB. kup-ów i dokumentów XML

Miesięcznik Software Developer’s Journal (12 numerów w roku) Dołączoną do magazynu płytę CD przetestowano programem AntiVirenKit
jest wydawany przez Software Press Sp. z o.o. SK firmy G DATA Software Sp. z o.o.

Dyrektor wydawniczy: Anna Adamczyk Redakcja dokłada wszelkich starań, by publikowane w piśmie i na towarzyszących
mu nośnikach informacje i programy były poprawne, jednakże nie bierze
Redaktor naczelny: Łukasz Łopuszański lukasz.lopuszanski@software.com.pl odpowiedzialności za efekty wykorzystania ich; nie gwarantuje także poprawnego
Redaktor merytoryczny i opracowanie CD: działania programów shareware, freeware i public domain.
Artur Wroński artur.wronski@pl.ibm.com
Marcin Molak marcin.molak@pl.ibm.com Uszkodzone podczas wysyłki płyty wymienia redakcja.
Redaktor prowadzący: Tomasz Łopuszański
tomasz.lopuszanski@software.com.pl Wszystkie znaki firmowe zawarte w piśmie są własnością odpowiednich firm.
Korekta: Tomasz Łopuszański tomasz.lopuszanski@software.com.pl Zostały użyte wyłącznie w celach informacyjnych.

Projekt okładki: Agnieszka Marchocka Redakcja używa systemu automatycznego składu


Skład i łamanie: Przemysław Banasiewicz, Ireneusz Pogroszewski
Osoby zainteresowane współpracą prosimy o kontakt:
Dział produkcji i kolportażu: Alina Stebakow alina.stebakow@software.com.pl cooperation@software.com.pl
Nakład: 6 000 egz.
Druk: Artdruk www.artdruk.com
Adres korespondencyjny:
Software Press Sp. z o.o. SK, Wysokość nakładu obejmuje również dodruki. Redakcja nie udziela pomocy
ul. Bokserska 1, 02-682 Warszawa, Polska technicznej w instalowaniu i użytkowaniu programów zamieszczonych na płycie
tel. +48 22 427 36 91, fax +48 22 224 24 59 CD-ROM dostarczonej razem z pismem.
www.sdjournal.org cooperation@software.com.pl
Sprzedaż aktualnych lub archiwalnych numerów pisma po innej cenie niż
Dział reklamy: adv@software.com.pl wydrukowana na okładce – bez zgody wydawcy – jest działaniem na jego
Obsługa prenumeraty: EuroPress Polska software@europress.pl szkodę i skutkuje odpowiedzialnością sądową.

www.sdjournal.org 
/2009 (5)

Nowości IBM DB2 9.7


Artur Wroński, Marcin Molak

Dla projektantów wersji DB2 9.7 głównym priorytetem było obniżenie


kosztów użytkowania bazy danych, zapewnienie maksymalnego
bezpieczeństwa i niezawodności oraz maksymalne ułatwienie
wykonywanych czynności administracyjnych. Wprowadzając nowe
funkcjonalności, pamiętali również o programistach, tworzących
aplikacje bazodanowe. W artykule zestawiliśmy wybrane
funkcjonalności, które pojawiły się w wersji 9.7.

Kompresja indeksów i tabel tymczasowych bazie danych pracuje wielu użytkowników o różnej charakterystyce
Mechanizmy kompresji tabel wprowadzone w wersji 9.1 zawsze były przetwarzania (np. raportowanie miesięczne, krótkie raporty opera-
bardzo mocną stroną DB2. W ciągu ostatniego roku ponad 100 klien- cyjne, operacje online), równomierny przydział zasobów może nie od-
tów SAP na świecie zdecydowało się zmigrować bazę na DB2 głów- zwierciedlać priorytetów biznesowych. Udoskonalony w wersji DB2
nie ze względu na tę funkcjonalność. Mniejsza baza jest szybszą ba- 9.7 menadżer obciążenia (ang. workload manager) pozwala w łatwy
zą, szybciej wykonuje się backup, a mniej zajętego miejsca na dysku sposób kontrolować moc maszyny przydzielaną poszczególnym zada-
oznacza mniejsze koszty. W wersji 9.5 wprowadzono mechanizmy niom. W DB2 9.7 wprowadzono koncepcję starzenia się przetwarza-
automatycznej kompresji pozwalające na kompresję ładowanych da- nia. Wykonywana instrukcja SQL (bądź sesja) po przekroczeniu okre-
nych bez konieczności reorganizacji danych. W 9.7 kompresję tabel ślonych progów (np. czasu wykorzystanego procesora) może być prze-
uzupełniono o kompresję indeksów, obiektów BLOB i dokumentów niesiona do innej klasy przetwarzania, o zupełnie innych priorytetach
XML oraz o automatyczną kompresję obiektów tymczasowych. Zmie- wykorzystania zasobów sprzętowych. Dzięki takiemu podejściu baza
niono także format zapisu do dziennika transakcji, tak by informacja danych może automatycznie zlokalizować bardzo obciążające zapyta-
o operacjach na skompresowanych obiektach mogła być wykorzystana nia i podjąć stosowne akcje (np. zmniejszyć priorytet bądź zakończyć
przez mechanizmy replikacji. Więcej na temat kompresji dowiesz się zadanie), tak by zagwarantować określoną wydajność dla najważniej-
w artykule Kompresja w DB2. szych zadań. W DB2 9.7 można śledzić ilość czytanych wierszy, czas
wykorzystanego procesora, łączny czas przetwarzania czy miejsce wy-
Język PL/SQL korzystane w obszarze tymczasowym. Menadżer obciążenia DB2 mo-
Zalety procedur składowanych i funkcji zdefiniowanych przez użyt- że na starcie traktować wszystkie sesje jako równoważne i podejmo-
kownika sprawiają, że wiele działających dziś systemów opiera część wać określone akcje w wyniku śledzenia aktywności. Istnieje także
logiki aplikacji na kodzie proceduralnym baz danych. Jednak brak możliwość podejmowania określonych akcji jeszcze przed urucho-
jednolitego standardu sprawił, że producenci serwerów danych roz- mieniem zapytania. DB2 może wyznaczyć koszt danej operacji i za-
wijali przez lata własne implementacje języków. Podczas gdy środo- leżnie od kosztu umieścić zadanie w określonej klasie przetwarzania
wiska deweloperskie związane z bazą DB2 mogły korzystać z języ- bądź zabronić wykonania danej operacji. Taka funkcjonalność może
ka SQL PL, programiści serwera danych Oracle DB opierali swój kod być szczególnie przydatna w dużych systemach hurtowni danych, w
na PL/SQL. Konieczność przepisywania linii kodu do nowego dialek- których użytkownicy końcowi mogą wygenerować zapytania dopro-
tu stawała się często długotrwałym elementem procesów migracyj- wadzające do zatkania się systemu (np. złączenie dwóch terabajto-
nych. Mając to na uwadze, w ramach DB2 9.7 udostępniono progra- wych tabel bez warunku ograniczającego). Mechanizmy zarządzania
mistom Oracle DB obsługę języka PL/SQL. Należy podkreślić, iż kod obciążeniem w DB2 pozwalają wprowadzić pełną kontrolę nad zacho-
stworzony w tym języku nie jest konwertowany do języka SQL PL. waniem się bazy w takich sytuacjach. Menadżer obciążenia jest wbu-
Jest on bowiem traktowany w sposób równorzędny i bezpośrednio dowany w jądro DB2 9.7 i jest zintegrowany menadżerem obciążenia
kompilowany do kodu wykonawczego DB2. Wraz z obsługą składni systemu operacyjnego Linux oraz AIX. Więcej na temat tego mecha-
DB2 zapewnia również możliwość debugowania i profilowania kodu nizmu dowiesz się w artykule Mechanizm zarządzania obciążeniem w
PL/SQL. A dzięki udostępnieniu nowych typów danych oraz modu- DB2
łów procedur składowanych i funkcji (np. DBMS_OUTPUT) przepisywa-
nie kodu staje się wyjątkiem, a nie regułą procesu migracyjnego. Inlining obiektów BLOB i XML
Duże obiekty, takie jak dane typu BLOB, CLOB, w DB2 standardowo
Udoskonalony menadżer obciążenia przechowywane są poza stronami z danymi. W ich obrębie przechowy-
Większość dostępnych na rynku baz danych równomiernie przydziela wany jest jedynie znacznik wskazujący na faktyczne położenie obiek-
zasoby poszczególnym sesjom aplikacji. W sytuacji, w której na jednej tu. Takie podejście jest optymalne do dużych obiektów. Czasami jed-


03/2009 (5)
/2009 (5)

nak w praktyce do pól typu BLOB, CLOB wstawiane są dane nieznacz- nione określone własności obszarów tabel, np. rozmiar strony. W DB2
nych rozmiarów i wtedy dużo rozsądniej umieścić je razem z pozostały- 9.7 wprowadzone zostały specjalne procedury składowane umożli-
mi danymi. Taka metoda przechowywania obiektów określana jest jako wiające przeniesienie tabel do nowych obszarów, z gwarancją ciągłego
inline-ing. Wersja 9.7 pozwala określić próg inline-ingu. Obiekty mniej- dostępu użytkowników do danych (tryb online). Ta czynność admini-
sze od założonego rozmiaru będą przechowywane na stronach razem z stracyjna została w pełni zautomatyzowana, odciążając administrato-
danymi. Po przekroczeniu zadeklarowanego progu (np. w wyniku aktu- rów od konieczności ręcznej migracji danych.
alizacji danych) obiekt jest automatycznie przenoszony do dedykowa-
nego obszaru tabel. Takie podejście można stosować nie tylko w przy- Przenoszalne przestrzenie tabel
padku obiektów typu BLOB, CLOB, ale także dokumentów XML. Inli- O ile przeniesienie jednej tabeli do nowej bazy nie jest zadaniem spe-
ne-ing pozwala na znaczne przyspieszenie aplikacji w przypadku dużych cjalnie trudnym, o tyle przeniesienie całej przestrzeni tabel, obejmu-
obiektów o małym rozmiarze. Pozwala także skorzystać z mechanizmów jącej tysiące obiektów, może być już operacją uciążliwą. Serwer DB2
kompresji w odniesieniu do BLOB-ów i dokumentów XML. zapewnia w tym zakresie narzędzia: db2look do generowania plików
DDL ze strukturą obiektów oraz db2move do eksportowania danych
Koncentrator wyrażeń do plików i ich ładowania do bazy. Wykorzystanie tych narzędzi wy-
Bardzo dobrym nawykiem programowania jest wykorzystywanie w maga przygotowania nowych przestrzeni tabel, przypisania im odpo-
zapytaniach SQL tzw. znaczników parametrów (ang. parameter mar- wiednich kontenerów, a także kontrolowania procesów eksportu i im-
ker). By wstawić określoną liczbę rekordów, dużo lepiej jest przygoto- portu danych. Wersja 9.7 przynosi w tym zakresie znaczące uspraw-
wać jedną generyczną instrukcję, w której zamiast wartości podaje się nienie. Wbudowany mechanizm przenoszalnych przestrzeni tabel
znak pytajnika. Instrukcję taką należy skompilować (PREPARE) i do- (ang. transportable tablespaces) pozwala na migracje całej przestrzeni
piero podczas wykonywania podawać określone wartości (EXECUTE tabel do nowej bazy i automatyczne dowiązanie jej kontenerów. Dzię-
... USING). Takie podejście bardzo korzystnie wpływa na wydajność, ki temu skraca się czas migracji i przygotowania nowych środowisk.
ponieważ wielokrotne wykonywanie instrukcji z różnymi wartościa-
mi wymaga tylko jednokrotnej kompilacji zapytania. We wcześniej- Zmiana metody zarządzania obszarem tabel
szych wersjach DB2 korzystanie z tego mechanizmu wymagało odpo- Podczas tworzenia obszaru tabel administrator musi zdecydować się,
wiedniego napisania aplikacji. DB2 9.7 automatycznie rozpoznaje po- czy obszar będzie zarządzany automatycznie przez bazę danych (Au-
dobne do siebie instrukcje SQL i wewnętrznie kompiluje jawnie po- tomatic Storage), czy przez administratora (DMS). Obydwa rodzaje ob-
dane wartości do postaci z wykorzystaniem znaczników parametrów szarów tabel dają możliwość automatycznego powiększania plików.
(ang. statement concentrator). Główną różnicą pomiędzy tymi obszarami tabel jest to, że w przy-
padku Automatic Storage baza samoczynnie dobiera nazwy, położenie
Odczyt bez blokad oraz wielkość plików. W obszarach typu DMS administrator ma pełną
DB2 9.7 wprowadza nowy poziom izolacji Currently Committed, któ- kontrolę nad tymi elementami. We wcześniejszych wersjach DB2 kon-
ry powinien znacznie ułatwić przenoszenie aplikacji pracujących z ba- wersja jednego obszaru w drugi wymagała utworzenia nowego obsza-
zą Oracle. Zapytania wykonane w tym poziomie izolacji nie są wstrzy- ru tabel i powtórnego załadowania danymi. DB2 9.7 udostępnia me-
mywane na blokadach, nawet w sytuacji, gdy inna sesja przetwarza da- chanizmy, które pozwolą taką konwersję wykonać w locie przy pracu-
ny rekord na wyłączność. Jeśli rekord został zmodyfikowany, ale jesz- jącej bazie danych.
cze nie zatwierdzono zmian, wtedy zapytanie wykonujące się w po-
ziomie izolacji Currently Committed automatycznie sięgnie do dzien- Narzędzia do zarządzania
nika transakcji, by pobrać zatwierdzoną wartość sprzed modyfikacji. cyklem życia informacji – Optim
Poziom Currently Committed nie wymaga jawnej deklaracji i jest do- Wraz z wersją DB2 9.7 IBM wprowadził na rynek rodzinę narzędzi
myślnie realizowany dla wszystkich zapytań Cursor Stability wykony- Optim do zarządzania cyklem życia informacji. IBM Optim Databa-
wanych z intencją odczytu. Więcej na temat współbieżności dostępu se Administrator 2.2 jest środowiskiem, które pozwala z jednego miej-
do danych przedstawiliśmy w artykule Poziomy izolacji w DB2. sca zarządzać wieloma zdalnymi instancjami baz danych. Narzędzie
znacząco zwiększa produktywność administratorów, np.: poprzez au-
Proste odzyskiwanie przestrzeni tomatyczne wykrywanie powiązań pomiędzy obiektami, przygoto-
W DB2 9.7 zmieniono wewnętrzny format obszarów tabel, tak by wanie skryptów dla zadanych zmian. IBM Optim Development Stu-
umożliwić łatwe odzyskiwanie miejsca na dysku. Jeśli na skutek reor- dio 2.2 stanowi środowisko deweloperskie dla programistów SQL i Ja-
ganizacji danych, kompresji istniejących rekordów, bądź po prostu w va. Umożliwia nie tylko tworzenie skryptów SQL/XML i XQuery, ale
wyniku usunięcia części danych w obszarze tabel zostało zwolnione również tworzenie funkcji zdefiniowanych przez użytkownika oraz
miejsce, wtedy jednym poleceniem ALTER TABLESPACE REDUCE procedur SQL PL, PL/SQL i Java, a także ich profilowanie i debugo-
miejsce to może być zwrócone do systemu plików. W instrukcji zmie- wanie. Narzędzie w prostych krokach pozwala przygotować usługi sie-
niającej obszar tabel można podać określony rozmiar, o który mają być ciowe bez konieczności programowania aplikacji: od stworzenia zapy-
zmniejszone pliki bazy danych, ale można także wymusić maksymal- tań SQL na testowaniu wdrożonej na serwer aplikacyjny usługi skoń-
ne możliwe pomniejszenie. Zmniejszanie plików bazy danych może czywszy. Dodatkowo programiści Javy mogą skorzystać z API IBM
być wykonywane w trakcie pracy bazy danych (operacja online) i mo- pureQuery. Umożliwia ono mapowanie tabel relacyjnych do obiek-
że być realizowane zarówno na przestrzeniach Database Managed Spa- tów, z zachowaniem wysokiej wydajności. Dzięki zamienianiu litera-
ce (DMS), jak i Automatic Storage. Nowy format obszarów tabel pozwa- łów znacznikami parametrów, określeniu dozwolonych zapytań, a na-
la także na proste odzyskiwanie przestrzeni z pustych bloków MDC wet konwersji na statyczny kod maksymalnie ograniczone są możli-
(Multidimesional Clustering) bez konieczności reorganizacji tabeli. wości ataków bazodanowych. Na dodatkową optymalizację instrukcji
SQL, zapisanych w skryptach bądź zagnieżdżonych w obiektach języ-
Przenoszenie tabel w trybie on-line ka Java, pozwala z kolei IBM Optim queryTuner. Analizując środowi-
Czasami administratorzy stoją przed koniecznością eksportu danych sko oraz plany poszczególnych zapytań, narzędzie pozwala wychwycić
do plików tekstowych oraz powtórnego załadowania ich do bazy. Taka nieoptymalne zapytania i zmodyfikować je do wydajnej postaci. Dzię-
operacja może być wymuszona w sytuacji, w której muszą być zmie- ki oparciu produktów rodziny Optim na platformie Eclipse 3.4 moż-


03/2009 (5)
Rysunek 1. IBM Optim DataBase Administrator 2.2

liwa jest integracja środowisk dla administratorów baz danych i zespo- DB2 9.7 już certyfikowana dla SAP
łów deweloperskich (wykorzystujących także narzędzia rodziny Ratio- DB2 przechodzi zestaw rygorystycznych testów na zgodność z syste-
nal). Dodatkowe wsparcie dla pracy grupowej zapewnia również ze- mami SAP (ERP, BI) jeszcze przed oficjalną premierą. Zaangażowa-
staw wtyczek dla systemów zarządzania wersją. nie inżynierów SAP w proces projektowania i testowania DB2 prak-
tycznie eliminuje ryzyko przejścia na nową wersję. Nowe wersje DB2
Niejawna konwersja typów standardowo dostępne są do wykorzystania z SAP-em w przeciągu 4
Podobnie do klasycznych języków programowania, DB2 wymusza- do 8 tygodni, co pozwala bardzo szybko skorzystać z nowych tech-
ła na programistach używania jawnej konwersji typów w ramach za- nologii. Tak było w przypadku wersji DB2 8.2, 9.1, 9.5. Wersja 9.7
pytań SQL. Jednak olbrzymi rozwój języków dynamicznych, takich nie jest tutaj wyjątkiem - posiada już certyfikat na zgodność z syste-
jak: PHP, Ruby czy Groovy, sprawił, iż programiści zaczęli coraz czę- mami SAP! Najwyższy poziom integracji DB2 i SAP, a także dużo
ściej wykorzystywać słabą konwersję typów w ramach aplikacji. IBM, niższe koszty utrzymania czynią DB2 bardzo atrakcyjną nie tylko w
dostrzegając ten trend, wprowadził w wersji DB2 9.7 niejawną kon- przypadku instalacji nowych systemów,ale także dla klientów posia-
wersję typów. Obejmuje ona swoim zakresem konwersje pomiędzy ty- dających już inne bazy danych. W ciągu ostatniego roku ponad 100
pami numerycznymi oraz typami czasowymi a łańcuchami znaków. dużych klinetów SAP na świecie zmigrowało swoją bazę do DB2.
Zmiana typów dotyczy nie tylko operacji przypisania czy porównania Proces migracji należy do stosunkowo prostych i jest bardzo dobrze
wartości, ale obejmuje również większość standardowych funkcji SQL zdefiniowany.
(np. konkatenacje). Co ważne, konwersja odbywa się na typ zmiennej Cennym źródłem informacji w tym zakresie może być bezpłat-
znajdującej się po lewej stronie operatora, dzięki temu programista ma na książka DB2 Optimization Techniques for SAP Database Migra-
pełną kontrolę nad kodem. Jednocześnie czas przygotowania nowych tion And Unicode Conversion, dostępna na stronach http://www.redbo-
zapytań ulega skróceniu. oks.ibm.com (klucz do wyszukania: SG24 – 7774 – 00).

Ewolucja schematów i rewalidacja obiektów Artur Wroński


Ciągły rozwój aplikacji wymusza na projektantach systemów bazodano- Od piętnastu lat specjalizuje się w rozwiązaniach przetwarzania danych.
wych modyfikacje struktury pojedynczych obiektów bądź całych sche- Aktualnie pracuje jako kierownik zespołu technicznego IBM Information
matów. Zależności pomiędzy obiektami często wymuszały wykona- Management Software.
nie takich operacji w ściśle określony sposób. W ramach DB2 9.7 udo- Kontakt z autorem: artur.wronski@pl.ibm.com
stępniono mechanizm automatycznej rewalidacji obiektów zależnych.
Dzięki temu możliwe jest w jednym kroku usunięcie obiektu i zastą- MARCIN MOLAK
pienie go nowym. Dzięki instrukcji CREATE OR REPLACE taką czynność Specjalista w zakresie zarządzania danymi w dziale oprogramowania IBM
można wykonać dla funkcji, procedur, widoków oraz aliasów. Z kolei Polska i ambasador programu inicjatywy akademickiej IBM. Odpowiada za
polecenie ALTER wzbogaciło się o zmianę nazwy i typu (w ramach do- wsparcie serwerów danych DB2 i solidDB oraz narzędzi z rodzin Optim i Da-
stępnych konwersji) kolumny oraz o możliwość jej usunięcia w trybie ta Studio. Absolwent Wydziału Fizyki Politechniki Warszawskiej. Prywatnie
online. Sprawia to, że zarówno codzienne prace administratorów, jak i pasjonat nowych technologii oraz miłośnik fantastyki.
procesy migracji do nowych wersji aplikacji są dużo bardziej wydajne. Kontakt z autorem: marcin.molak@pl.ibm.com

3D Methods of Display Objects 


/2009 (5)

Integracja DB2 z bazami danych Oracle

In the expanded version of AS3 that ships with Flash CS4, every Display
Object is embedded in 3D space, with x, y and z coordinates as well as
properties that allow rotation about any of the three coordinate axes
and more advanced manipulations.

O
dpowiednikiem linków bazodano- ny DB2}\cfg\db2dj.ini. Jeżeli na danym kom- ORACLE_HOME= C:\oracle\product\10.2.0\
wych Oracle są w DB2 tzw. pseu- puterze zainstalowanych jest kilka aplikacji client_1
donimy (ang. nicknames) . Aplika- klienckich Oracle (klient: 10g, 11g, Develo-
cja wykorzystująca pseudonimy odwołuje się per), w pliku tym można określić, z którego Mając już skonfigurowanego klienta Oracle,
do zdalnych zasobów w zupełnie przezroczy- TNSnames.ora brana będzie nazwa serwisu. możemy przystąpić do konfiguracji mecha-
sty sposób. Zanim jednak będziemy mogli Przykładowy wpis w pliku db2dj.ini: nizmu federacji.
sięgnąć do bazy Oracle z DB2, musimy odpo-
wiednio skonfigurować środowisko.
Pierwszym krokiem konfiguracji jest zain- Listing 1. Przykładowa konfiguracja pliku tnsnames.ora
stalowanie w środowisku DB2 odpowiednich
bibliotek dostępu do bazy Oracle. Biblioteki, # tnsnames.ora Network Configuration File:
czyli tzw. opakowania (ang. wrappers), udo- # C:\oracle\product\10.2.0\client_1\NETWORK\ADMIN\tnsnames.ora
stępniane są w pakiecie hurtowni danych # Generated by Oracle configuration tools.
DB2 (produkt InfoSphere Warehouse) bądź
w niezależnym produkcie InfoSphere Fede- HW10 =
ration Server. Po zainstalowaniu bibliotek i
wgraniu odpowiedniego klucza licencyjne- (DESCRIPTION =
go powinniśmy uaktywnić obsługę federacji (ADDRESS_LIST =
poprzez aktualizację parametru instancji FE- (ADDRESS = (PROTOCOL = TCP)(HOST = soltek)(PORT = 1521))
DERATED, tak jak poniżej (zmiana parame- )
tru wymaga restartu instancji): (CONNECT_DATA =
(SERVICE_NAME = hw)
db2 update dbm cfg using federated yes )
)
Do zestawienia natywnej metody komuni-
kacji z bazą Oracle należy w środowisku in- Listing 2. Utworzenie przykładowej procedury stowarzyszonej
stancji DB2 dodatkowo zainstalować opro-
gramowanie klienta Oracle oraz odpowied- CREATE PROCEDURE HENRYK.TESTOWA SOURCE SCOTT.TESTOWA
nio skonfigurować uchwyt TNS do bazy da- NUMBER OF PARAMETERS 3 FOR SERVER HW10 MODIFIES SQL DATA
nych ORACLE. Konfigurację TNS możemy NOT DETERMINISTIC EXTERNAL ACTION
przeprowadzić z użyciem środowiska gra-
ficznego ORACLE NetManager (patrz Ry- Listing 3. Właściwa definicja procedury na serwerze Oracle
sunek 1), który dokonuje wpisu do pliku
tnsnames.ora znajdującego się przy aplika- CREATE OR REPLACE PROCEDURE TESTOWA
cji klienta. (a1 IN NUMBER, a2 IN VARCHAR2, a3 IN VARCHAR2 DEFAULT 'Lodz') AS
Wpis taki można także dokonać ręcznie. BEGIN
Na Listingu 1 zamieściliśmy przykładową za- insert into scott.dept values (a1,a2,a3);
wartość pliku tnsnames.ora wygenerowaną exception
narzędziem NetManager z Rysunku 1. when others then rollback;
W środowisku DB2 należy także ustawić END;
zmienną ORACLE_HOME, by DB2 było
świadome, gdzie zainstalowany jest klient
Oracle. Zmienną ORACLE_HOME moż-
na także ustawić w pliku {katalog instalacyj-

 SDJ Extra 35
3D Methods of Display Objects in Flash Player 10

Zdefiniowanie opakowań
Konfigurując mechanizm federacji w DB2,
musimy określić, z której biblioteki dostę-
pu będziemy korzystać – czyli musimy zde-
finiować opakowanie. Poniżej przedstawili-
śmy instrukcję tworzącą opakowanie o na-
zwie NET8, które będzie korzystało z biblio-
teki db2net8.dll:

db2 create wrapper net8 library


‘db2net8.dll’;

Biblioteka db2net8.dll korzysta z klienta


Oracle. Nazwę NET8 później wykorzysta-
my przy definiowaniu parametrów serwera
Oracle. Z każdym opakowaniem dostępne są
odpowiednie opcje. Ustawienia opakowania
dla Oracle zostały przedstawione w Tabeli 1.
Listing 5. ?????????????????
Definicja serwera

Po utworzeniu opakowania następnym kro-


kiem jest zdefiniowanie serwera, czyli okre-
ślenie, z którą bazą danych będziemy się łą-
czyć. Serwer definiuje się instrukcją CRE-
ATE SERVER, tak jak w przykładzie poniżej:

db2 create server hw type oracle version


‘10g’ wrapper net8 options( add
node ‘HW’)

Najlepiej definicję serwera określić przy wyko-


rzystaniu narzędzi graficznych, ponieważ na-
rzędzie zaproponuje nam listę dostępnych opcji
oraz od razu będziemy mieli możliwość spraw-
dzenia połączenia ze zdalną bazą. Przykładowy
ekran konfiguracji serwera pokazaliśmy na Ry-
sunku 2. Warto kliknąć w przycisk „Właściwo-
ści”, by określić dodatkowe opcje definiowanego
serwera. W Tabeli 2 pokazaliśmy możliwe do
ustawienia zmienne środowiskowe wykorzy-
Listing 1. xxxxxxxxxxx
stywane przez definiowany serwer.

Opcje specyficzne dla serwera Oracle przed-


stawione zostały w Tabeli 3.

Odwzorowanie użytkowników
W środowisku sfederowanym należy zdefi-
niować, w jaki sposób lokalni użytkownicy
DB2 będą mapowani na zdalnych użytkow-
ników bazy Oracle. Odwzorowanie określa
się przy wykorzystaniu instrukcji CREATE
USER MAPPING, tak jak poniżej:

CREATE USER MAPPING FOR DB2ADMIN SERVER HW


OPTIONS (ADD REMOTE_AUTHID ‘scott’
, ADD REMOTE_PASSWORD ‘tiger’ ) ;
CREATE USER MAPPING FOR HENRYK SERVER HW
OPTIONS (ADD REMOTE_AUTHID ‘scott’
, ADD REMOTE_PASSWORD ‘tiger’ ) ;

Po pomyślnym wykonaniu powyższych in-


strukcji, w momencie połączenia się z serwe-
Listing 3. xxxxxxxxxx rem Oracle, DB2 będzie automatycznie ma-

www.sdjournal.org 
/2009 (5)

Tabela 1. Opcje opakowania dla biblioteki db2net8.dll


Parametr Wart Opis
DB2_FENCED N Określa, czy opakowanie działa w trybie chronionym, czy w trybie zaufanym. Wartością domyślną jest 'N' -
opakowanie działa w trybie zaufanym.
DB2_UM_PLUGIN_LANG JAVA Określa język dla wtyczki odwzorowania użytkowników. Poprawne wartości to 'Java' i 'C'. Wartością domyśl-
ną jest 'Java'.
DB2_UM_PLUGIN Określa łańcuch, w którym jest rozróżniana wielkość liter, dla nazwy klasy, która odpowiada odwzorowaniu
klasy repozytorium przez użytkownika. Na przykład "UżytkownikOdwzorowanieRepozytoriumLDAP".

Tabela 2. Zmienne środowiskowe dla serwera.


Parametr Wartość Opis
ORACLE_BASE Określa katalog główny drzewa katalogów klienta Oracle. Zmienna ta jest opcjonalna. Jeśli zmienna
ORACLE_BASE została ustawiona podczas instalowania oprogramowania klienta Oracle, na serwerze sto-
warzyszonym należy również ustawić zmienną środowiskową ORACLE_BASE.
ORA_NLS33 Określa lokalizację plików danych NLS dla bazy Oracle wersja 8.0, 8.1, 9.0.1 i 9.2. Ta opcja jest opcjonalna.
TNS_ADMIN Określa lokalizację pliku tnsnames.ora, jeśli nie znajduje się on w ścieżce domyślnej. Na platformach Win-
dows klient Oracle szuka pliku tnsnames.ora w katalogu \NETWORK\ADMIN. Na platformach UNIX klient
szuka pliku tnsnames.ora w katalogu /etc.
ORACLE_HOME C:\oracle\ Określa pełną ścieżkę do katalogu, w którym zainstalowane jest oprogramowanie klienta Oracle. Ta
product\10.2.0\ opcja jest wymagana.
client_1
NLS_LANG Opakowanie używa tej wartości do konwersji strony kodowej Oracle. Opakowanie określa terytorium
oraz stronę kodową stowarzyszonej bazy danych. Opakowanie ustawia wartość zmiennej NLS_LANG tak,
aby jak najbardziej odpowiadała ona ustawieniom narodowym programu Oracle. Jeśli nie istnieje odpo-
wiednie zbliżone ustawienie narodowe, zmiennej NLS_LANG nadawana jest wartość American_Ameri-
ca.US7ASCII. Aby uzyskać dostęp do źródła danych, które zawiera dane korzystające z chińskiej strony ko-
dowej GB 18030, stowarzyszona baza danych musi używać strony kodowej UTF-8.

Słownik systemowy dla obiektów sfederowanych baz danych


Obsługa środowisk stowarzyszonych wymaga od administratorów baz danych nie tylko przygotowywania nowych, ale również wyszukiwa-
nia i aktualizacji istniejących obiektów sfederowanych. Funkcje, potrzebne do realizacji powyższych zadań, dostępne są w narzędziu graficz-
nych DB2 Control Center w postaci dedykowanych widoków i kreatorów. Pracując jednak w środowisku tekstowym, możemy wykorzystać słow-
nik bazodanowy. Schemat SYSCAT udostępnia bowiem widoki na tabele systemowe, zawierające metadane obiektów sfederowanych. Poniżej
przedstawiliśmy listę wybranych widoków z krótkim opisem:

• SYSCAT.WRAPPERS – zawiera definicje opakowań;


• SYSCAT.WRAPOPTIONS – określa opcje dla każdego z opakowań;
• SYSCAT.SERVERS – reprezentuje definicje serwerów (zdalnych źródeł danych);
• SYSCAT.SERVEROPTIONS – obejmuje opcje dla każdego z serwerów;
• SYSCAT.USEROPTIONS – określa odwzorowania użytkowników;
• SYSCAT.NICKNAMES – zawiera definicje pseudonimów;
• SYSCAT.FUNCMAPPINGS – reprezentuje mapowanie funkcji;
• SYSCAT.FUNCMAPOPTIONS – obejmuje opcje dla zdalnych funkcji;
• SYSCAT.TYPEMAPPINGS – określa odwzorowania typów;
• SYSCAT.ROUTINESFEDERATED – zawiera definicje stowarzyszonych procedur składowanych;
• SYSCAT.COLUMNS – prezentuje definicje kolumn, m.in. dla pseudonimów;
• SYSCAT.COLOPTIONS – obejmuje definicje kolumn w zdalnych tabelach.

Celem wyświetlenia informacji (na bazie słownika systemowego) na temat zdefiniowanego w ramach artykułu opakowania posłużyliśmy się za-
pytaniem:

SELECT varchar(wrapname,30) as wrapname,


char(wraptype, 1) as wraptype,
varchar(library,20) as library
FROM syscat.wrappers

WRAPNAME WRAPTYPE LIBRARY


-------------------- -------- --------------------
NET8 R libdb2net8.dll

IBM dostarcza również narzędzia db2look, które przygotowuje instrukcje DDL dla obiektów zdefiniowanych w bazie obiektów stowarzyszo-
nych. Poniżej przedstawiliśmy komendę tworzącą zapytania w pliku hw.sql dla obiektów sfederowanych w bazie PD:

db2look –d PD –e –fedonly –o hw.sql

Tak przygotowane instrukcje należy jedynie uzupełnić o hasła dla zdalnych użytkowników. Możliwe jest również zawężenie zakresu obiektów sto-
warzyszonych do określonego opakowania (przełącznik –wrapper) bądź serwera zdalnego (przełącznik –server).

10 SDJ Extra 35
3D Methods of Display Objects in Flash Player 10

Tabela 3. Opcje ustawień dla definicji serwera Oracle


Parametr War- Opis
tość
PASSWORD Y Określa, czy do źródła danych mają być wysyłane hasła. 'Y' oznacza, że hasła są zawsze wysyłane do źró-
dła danych i poddawane sprawdzaniu poprawności.
DB2_TWO_PHASE_COMMIT Określa, czy na serwerze stowarzyszonym jest włączone dwufazowe zatwierdzanie transakcji z serwe-
rem źródła danych.
DB2_MAXIMAL_PUSHDOWN N Określa, czy optymalizator zapytań wybiera plan dostępu przekazujący więcej operacji zapytań do źró-
dła danych. Wartością domyślną jest 'N'. Optymalizator zapytań nie przekazuje niżej więcej operacji za-
pytań, a zamiast tego wybiera plan o najmniejszym szacowanym koszcie.
PUSHDOWN Y Określa, czy serwer stowarzyszony umożliwia wartościowanie operacji przez źródło danych. Wartością
domyślną jest 'Y' (Tak). Wartość 'N' oznacza, że serwer stowarzyszony pobiera kolumny ze zdalnego źró-
dła danych i nie zezwala na wartościowanie operacji przez źródło danych.
IUD_APP_SVPT_ENFORCE Y Określa, czy serwer stowarzyszony wymusza korzystanie z punktów zapisu aplikacji. Wartość 'Y' ozna-
cza, że serwer stowarzyszony wymusza punkty zapisu i zapobiega wykonywaniu operacji INSERT, UPDA-
TE i DELETE na pseudonimach, gdy źródło danych nie obsługuje punktów zapisu aplikacji.
COLLATING_SEQUENCE N Określa, czy źródło danych oraz stowarzyszona baza danych korzystają z tej samej, domyślnej kolejności
zestawiania. Aby zagwarantować poprawne wyniki z serwera stowarzyszonego, należy podać wartość 'I',
która oznacza, że w źródle danych nie jest rozróżniana wielkość liter.
CPU_RATIO 1.0 Określa, o ile szybciej lub wolniej działa procesor źródła danych w porównaniu z procesorem serwera
stowarzyszonego. Dopuszczalne są wartości większe od 0 i mniejsze od 1x10 23. Ustawienia mogą być
wyrażane z użyciem dowolnego zapisu stosowanego dla liczb rzeczywistych, na przykład: 123E10, 123
lub 1.21E4.
IO_RATIO 1.0 Określa, o ile szybciej lub wolniej działa procesor źródła danych w porównaniu z procesorem serwera
stowarzyszonego. Dopuszczalne są wartości większe od 0 i mniejsze od 1x10 23. Ustawienia mogą być
wyrażane z użyciem dowolnego zapisu stosowanego dla liczb rzeczywistych, na przykład: 123E10, 123
lub 1.21E4.
FED_PROXY_USER Określa ID autoryzowanego użytkownika używane do nawiązywania wszystkich wychodzących połą-
czeń zaufanych, gdy połączenie przychodzące nie jest zaufane. Użytkownik, którego identyfikator jest
określony w tej opcji, musi mieć odwzorowanie użytkownika określające opcje REMOTE_AUTHID i RE-
MOTE_PASSWORD.
XA_OPEN_STRING_OPTIONS Określa identyfikator menedżera zasobów rejestru serwera Microsoft SQL Server. Ta opcja jest wymaga-
na, gdy opcja DB2_TWO_PHASE COMMIT ma wartość 'Y'.
DB2_UM_PLUGIN_LANG JAVA Określa język dla wtyczki odwzorowania użytkowników. Poprawne wartości to 'Java' i 'C'. Wartością do-
myślną jest 'Java'.
DB2_UM_PLUGIN Określa łańcuch, w którym jest rozróżniana wielkość liter, dla nazwy klasy, która odpowiada odwzoro-
waniu klasy repozytorium przez użytkownika. Na przykład "UżytkownikOdwzorowanieRepozytoriumL-
DAP".
DB2_MAX_ASYNC_REQU- 1 Określa maksymalną liczbę współbieżnych żądań asynchronicznych z zapytania. Poprawne są wartości z
ESTS_PER_QUERY zakresu od -1 do 64000. Wartość -1 oznacza, że liczbę żądań definiuje optymalizator stowarzyszonej ba-
zy danych. Wartość 0 oznacza, że źródło danych nie może obsługiwać dodatkowych żądań.
NODE HW10 Określa nazwę węzła, na którym znajduje się serwer bazy danych Oracle. Nazwę węzła można uzyskać z
pliku tnsnames.ora.
OLD_NAME_GEN N Określa sposób przekształcania nazw kolumn oraz nazw indeksów znajdujących się w źródle danych w
pseudonimy nazw kolumn oraz lokalne nazwy indeksów dla stowarzyszonej bazy danych. Wartość 'N'
oznacza, że generowane nazwy są bardzo zbliżone do nazw w źródle danych. Wartość 'Y' oznacza, że ge-
nerowane nazwy są takie same jak nazwy tworzone w wersji 9 i wcześniejszych. A zatem nazwy mogą
nie być zbliżone do nazw źródła danych. Wartością domyślną jest 'N'.

COMM_RATE 2 Określa szybkość transmisji, w megabajtach na sekundę, między serwerem stowarzyszonym a serwerem
źródła danych. Dopuszczalne są wartości większe od 0 i mniejsze od 2147483648. Wartość musi być wy-
rażona jako liczba całkowita, na przykład 12.

FOLD_PW Określa wielkość liter hasła wysyłanego do źródła danych. Jeśli nie została określona żadna wartość, ser-
wer stowarzyszony wysyła hasło z użyciem wielkich liter, a następnie, jeśli takie hasło nie zostanie zaak-
ceptowane, serwer wysyła je z użyciem małych liter.

FOLD_ID Określa wielkość liter identyfikatora użytkownika wysyłanego do źródła danych. Jeśli nie została okre-
ślona żadna wartość, serwer stowarzyszony wysyła identyfikator użytkownika z użyciem wielkich liter, a
następnie, jeśli taki identyfikator nie zostanie zaakceptowany, serwer wysyła identyfikator użytkownika
z użyciem małych liter.
VARCHAR_NO_TRAILING_ N Opcja ta ma zastosowanie dla źródeł danych zawierających dane znakowe o zróżnicowanej długości bez
BLANKS uzupełniania spacjami na końcu. Opcję tę należy ustawić w przypadku, gdy ma mieć ona zastosowanie
do wszystkich kolumn typu VARCHAR i VARCHAR2 w obiektach źródeł danych dostępnych ze wskazane-
go serwera.

www.sdjournal.org 11
/2009 (5)

pować lokalnego użytkownika db2admin na DB2 (istnieje także możliwość przechowania ników. Dostępne opcje dla odwzorowań użyt-
zdalnego użytkownika scott, oraz użytkow- hasła w wybranym, centralnym systemie uwie- kowników przedstawiliśmy w Tabeli 4.
nika henryk także na użytkownika scott. Dla rzytelniania). Na Rysunku 3 przedstawiliśmy
zdalnego użytkownika należy także podać ha- widok graficznego narzędzia wykorzystywa- Definicja pseudonimów
sło, które będzie przechowane w lokalnej bazie nego do definiowania odwzorowań użytkow- Określenie definicji pseudonimów dla do-
wolnych tabel ze zdalnej bazy danych realizu-
je się instrukcją CREATE NICKNAME . Po-
niżej przedstawiamy przykładowe instrukcje
definicji pseudonimów dla tabel ze zdalnego
schematu SCOTT:

CREATE NICKNAME HENRYK.DEPT1 FOR


HW.SCOTT.DEPT;
CREATE NICKNAME HENRYK.EMP1 FOR
HW.SCOTT.EMP;
CREATE NICKNAME HENRYK.BONUS1 FOR
HW.SCOTT.BONUS;
CREATE NICKNAME HENRYK.SALGRADE1 FOR
HW.SCOTT.SALGRADE;

Listing 4. xxxxxxxxxxx Do pseudonimów można odwoływać się do-


kładnie w taki sam sposób jak do lokalnych
obiektów. Wykonanie lokalnego zapytania na
tabeli HENRYK.DEPT1 spowoduje automa-
tyczne podłączenie się do zdalnej bazy HW i
wykonanie zapytania na tabeli SCOTT.DEPT,
wykorzystując użytkownika scott i jego hasło
wcześniej zapisane w lokalnej bazie.

Stowarzyszone
procedury składowane
Udostępnienie zdalnej procedury składowanej
w lokalnym środowisku realizuje się instruk-
cją CREATE PROCEDURE z odpowiednimi
parametrami wskazującymi na zdalny serwer
Oracle. Na Listingu 2 przedstawiliśmy przy-
Figure 3. A Rotating Cube kładową instrukcję definicji procedury stowa-
rzyszonej HENRYK.TESTOWA, będącej od-
wołaniem do zdalnej procedury TESTOWA
na serwerze Oracle (Listing 3).
Uruchamianie zdalnej procedury w lokal-
nym środowisku DB2 wygląda dokładnie tak
samo jak uruchamianie innych lokalnych pro-
cedur:

call testowa(12,’aaa’,’bbb’);

Definiowanie zdalnych tabel


Mechanizmy federacji DB2 umożliwiają tak-
że tworzenie tabel i ograniczeń integralnościo-
wych na zdalnym serwerze. Na Rysunkach 4
oraz 5 przedstawiliśmy ekrany narzędzia gra-
ficznego DB2 Control Center (widok: Obiek-
ty stowarzyszonej bazy danych, Tabele Zdalne),
które wykorzystaliśmy do utworzenia zdalnej
tabeli. Na Listingu 4 przedstawiliśmy właściwą
instrukcję SQL tworzenia tabeli, która została
wygenerowana przez to narzędzie. Warto zwró-
cić uwagę, że parametry lokalizacji danej tabeli,
takie jak nazwa serwera czy schemat w zdalnej
bazie, podaje się w sekcji OPTIONS. Na Listin-
gu 5 pokazaliśmy, że ograniczenia itegralnościo-
we na zdalnym obiekcie tworzy się w podobny
Figure 4. The Cube Sides sposób jak dla lokalnych tabel.

12 SDJ Extra 35
3D Methods of Display Objects in Flash Player 10

Przykłady ny. Pobierając szczegóły danej tabeli, dostęp- nego serwera mamy możliwość określenia,
rozproszonych operacji ne w planie wykonania zapytania (np. klika- czy dla danego źródła obsługiwane będzie
Tak jak wspomnieliśmy, dostęp do zdalnych jąc na element HENRYK.EMP1 z Rysunku dwufazowe zatwierdzanie (parametr DB2_
tabel odbywa się poprzez lokalnie zdefiniowa- 6), będziemy mogli sprawdzić fizyczne po- TWO_PHASE_COMMIT z Tabeli 3). Do-
ne pseudonimy. Dla deweloperów aplikacji nie łożenie tabeli. myślnie włączone jest tylko jednofazowe za-
ma różnicy, czy odwołują się do lokalnej tabe- W ramach sfederowanej bazy danych mo- twierdzanie, co oznacza, że w danej transak-
li, czy do pseudonimu, który w rzeczywistości żemy nie tylko wykonywać zapytania roz- cji można modyfikować tylko obiekty z jed-
jest tabelą zarządzaną przez zewnętrzną bazę proszone, ale także realizować rozproszone nego serwera (zdalnego albo lokalnego). By
danych. Poniżej przedstawiliśmy zapytanie, transakcje. Poniżej przedstawiliśmy przykład przedstawiony powyżej kod zakończył się z
które realizuje złączenie dwóch tabel: HEN- transakcji, która wstawia rekord do lokalnej sukcesem, należy wcześniej włączyć dwufa-
RYK.EMP1 oraz HENRYK. DOSTAWCY. tabeli DEPT oraz zdalnej DEPT1: zowe zatwierdzanie.

SELECT ENAME, SAL, DNAME update command options using c off; Posumowanie
FROM HENRYK.EMP1 E W artykule przedstawiliśmy podstawowe
INNER JOIN HENRYK.DOSTAWCY D insert into dept1 kroki, jakie należy podjąć, by zintegrować ba-
values (100,’dept1’,’W-wa’); zę DB2 z bazą Oracle. Mechanizm federacji
ON E.DEPTNO=D.DEPTNO ORDER BY 2 DESC; insert into dept DB2 pozwala wirtualnie włączyć do lokalnej
values (101,’dept2’,’W-wa’); bazy danych obiekty pochodzące od zdalnych
Analizując treść zapytania, trudno jest po- commit; baz DB2, Oracle czy baz innych producen-
wiedzieć, czy mamy do czynienia z lokal- tów. Wykorzystanie mechanizmów federacji
nymi, czy zdalnymi tabelami. Dopiero po Pierwsze polecenie wyłącza opcję auto- DB2 może znacznie przyspieszyć tworzenie
sprawdzeniu planu wykonania zapytania matycznego zatwierdzania, więc obie in- aplikacji, ponieważ ukrywa przez programi-
(patrz Rysunek 6) można dojść do wniosku, strukcje INSERT będą wykonane jako jed- stami różnice interfejsów i dodatkowo opty-
że tabela EMP1 jest zdalnym obiektem, po- na transakcja (instrukcje należy przekopio- malizuje rozproszone operacje odczytu i zapi-
nieważ w planie zapytania pojawia się blok wać do pliku, a następnie uruchomić db2 – su. Mechanizmy federacji DB2 wykorzystuje
SHIP, który oznacza, że ta część przetwa- tvf nazwa_pliku). W tym miejscu musimy się bardzo często w hurtowniach danych do
rzania jest przekazana na serwer zewnętrz- wspomnieć, że podczas definiowania zdal- szybkiego prototypowania transformacji da-
nych. Mechanizm ten jest używany także do
Listing 4. Przykład instrukcji utworzenia zdalnej tabeli realizacji rozproszonej hurtowni danych, w
której część danych celowo pozostaje w syste-
CREATE TABLE HENRYK.DEPT_REMOTE ( mach źródłowych, przy zachowaniu dostępu
DEPTNO BIGINT NOT NULL , do tych danych.
DEPTNAME VARCHAR (20) NOT NULL,
LOC VARCHAR (18) WITH DEFAULT 'Lodz')
OPTIONS (
REMOTE_SERVER 'HW10', REMOTE_SCHEMA 'SCOTT', Paweł Drzymała
REMOTE_TABNAME 'DEPARTMENT1'); Henryk Welfle
Paweł Drzymała i Henryk Welfle są pracownika-
COMMENT ON TABLE HENRYK.DEPT_REMOTE IS 'tabela na Oraclu'; mi Politechniki Łódzkiej. Od 12 lat zajmują się sys-
temami relacyjnych baz danych oraz integracją
Listing 5. Przykład instrukcji tworzącej klucz podstawowy na zdalnej tabeli środowisk heterogenicznych baz danych. Ich za-
interesowania obejmują również tworzenie za-
awansowanych aplikacji klient-serwer z dostę-
ALTER TABLE HENRYK.DEPT_REMOTE pem do wydajnych źródeł bazodanowych.
ADD CONSTRAINT PK_DEPT_REMOTE PRIMARY KEY ( DEPTNO) ; Kontakt z autorami:
pdrzymal@p.lodz.pl;
welfle@p.lodz.pl;
Tabela 4. Opcje ustawień odwzorowania użytkownika
Parametr Wartość Opis
USE_TRUSTED_CONTEXT N Określa, czy odwzorowanie użytkownika jest zaufane. Wartość 'Y' oznacza, że odwzorowa-
nie użytkownika jest zaufane i może być wykorzystane zarówno dla zaufanych, jak i niezau-
fanych połączeń wychodzących. Domyślnie odwzorowania użytkownika nie są zaufane i
mogą być wykorzystywane tylko dla niezaufanych połączeń wychodzących.
REMOTE_PASSWORD ******** Określa hasło dla opcji REMOTE_AUTHID. Poprawnym ustawieniem jest dowolny łańcuch o
długości 32 znaków lub mniejszej. Jeśli opcja ta nie jest określona, do źródła danych nie zo-
stanie przesłane żadne hasło.
FED_PROXY_USER Określa ID autoryzowanego użytkownika używane do nawiązywania wszystkich wychodzą-
cych połączeń zaufanych, gdy połączenie przychodzące nie jest zaufane. Użytkownik, któ-
rego identyfikator jest określony w tej opcji, musi mieć odwzorowanie użytkownika określa-
jące opcje REMOTE_AUTHID i REMOTE_PASSWORD. Jeśli zostanie określona opcja odwzo-
rowania użytkownika FED_PROXY_USER, należy określić również opcję.
REMOTE_AUTHID scott Określa identyfikator użytkownika zdalnego do odwzorowania na identyfikator użytkow-
nika lokalnego. Poprawnym ustawieniem jest dowolny łańcuch o długości 255 znaków lub
mniejszej. Jeśli ta opcja nie jest określona, zostanie użyty zdalny identyfikator łączący się ze
stowarzyszoną bazą danych.

www.sdjournal.org 13
Tworzenie aplikacji

Procedury
składowane w DB2 9
Dariusz Depta

A
rtykuł ten wprowadzi Cię w zagad- przypadku będą to głównie owoce). Każ- minatora @. Nazwa procedury może mieć
nienia związane z tworzeniem pro- dy produkt ma swój identyfikator, nazwę, co najwyżej 128 znaków, a lista parame-
cedur składowanych w języku SQL stan magazynowy, cenę i kod promocyj- trów procedury może być pusta, wtedy
PL na serwerze DB2. Śledząc zamieszczo- ny. Przy tej okazji chciałbym zwrócić Two- nawiasy okrągłe można pominąć. Klauzu-
ne w artykule przykłady, poznasz podstawo- ją uwagę na typ pola price. Typ DECFLOAT, la SPECIFIC definiuje dodatkową, unikal-
we zasady tworzenia procedur, dowiesz się, dostępny w DB2 od wersji 9.5, jest specjal- ną nazwę procedury, którą można wyko-
jak definiować parametry i zmienne oraz nie zaprojektowany do obliczeń waluto- rzystać do rozróżniania procedur, które
jak używać instrukcji blokowych i sterują- wych, nie powoduje błędów zaokrągleń i mają taką samą nazwę, ale różnią się licz-
cych. Ponadto dowiesz się, jak stosować kur- automatycznie rozszerza swój zakres. Uży- bą parametrów. Nazwę specyficzną mo-
sory oraz zapoznasz się z obsługą błędów i dy- łem tego typu, ponieważ w kilku przypad- żesz wykorzystać do usunięcia procedu-
namicznym SQL-em. Zamieszczone w arty- kach podczas testowania procedur otrzy- ry składowanej poleceniem DROP SPECIFIC
kule przykłady są przygotowane dla serwe- mywałem błędy przekroczenia zakresu i PROCEDURE , na przykład:
ra DB2 w wersji 9.5 oraz 9.7. Przed przystą- byłem zmuszony rozszerzać zakres dla ty-
pieniem do dalszych ćwiczeń zainstaluj na pu DECIMAL . db2 drop specific procedure p01
swoim komputerze serwer DB2, najlepiej w
polskiej wersji językowej. Kody źródłowe do Pierwsza procedura co z pewnością przyda Ci się podczas eks-
wszystkich przykładów znajdziesz na dołą- Zacznijmy zatem od utworzenia pierwszej perymentowania z kolejnymi przykłada-
czonej płytce. procedury składowanej. Na Listingu 2 przed- mi. Nazwa specyficzna pozwala także jed-
stawiłem najprostszą procedurę o nazwie noznacznie wskazać procedurę, która ma
Narzędzia simple. Zapisz treść tej procedury w pliku być zaktualizowana przy wykorzystaniu in-
Do tworzenia, uruchamiania i testowa- p01.sql i skompiluj, wydając polecenie: strukcji CREATE OR REPLACE PROCEDURE (DB2
nia przykładowych procedur potrzebny 9.7). Klauzula LANGUAGE wskazuje, że pro-
Ci będzie edytor tekstowy, procesor pole- db2 -td@ -vf p01.sql cedura jest napisana w języku SQL (w DB2
ceń SQL i testowa baza danych. Do edycji procedury składowane mogą być tworzone
procedur możesz użyć swojego ulubionego W efekcie wykonania tego polecenia proce- również w innych językach, takich jak C czy
edytora tekstowego, natomiast do urucha- sor poleceń db2 wczyta plik p01.sql (opcja - Java oraz po włączeniu trybu kompatybilno-
miania procedur składowanych proponu- f), traktując znak @ (opcja -td@) jako zakoń- ści Oracle w PL/SQL).
ję wykorzystać procesor poleceń CLP (ang. czenie treści procedury, a następnie wyświe-
Command Line Processor), który jest dostęp- tli tekst tej procedury (opcja -v) oraz komu- SQL w procedurze składowanej
ny po zainstalowaniu serwera DB2. Proce- nikat informujący o rezultacie kompilacji. Na Listingu 3 przedstawiłem kod, który po-
sor poleceń pod systemem Windows uru- Jeśli kompilacja się powiodła, to możesz uru- kazuje, jak w procedurze składowanej moż-
chomisz, wydając w oknie komend polece- chomić tę procedurę poleceniem: na stosować instrukcje SQL-owe. W wier-
nie db2cmd. Pod systemem Linux procesor szu {1} za pomocą instrukcji DELETE usuwa-
poleceń działa bezpośrednio w oknie ter- db2 call simple() ne są wszystkie rekordy z tabeli stock, a w
minala. Do testowania procedur będzie Ci wierszu {2} instrukcją INSERT są dodawa-
również potrzebna baza danych. Skrypt do Jedynym efektem jej działania jest komu- ne nowe rekordy. Zwróć uwagę na instruk-
utworzenia testowej bazy danych zamieści- nikat: cję INSERT, która w jednym wywołaniu do-
łem na Listingu 1. Zapisz treść tego skryptu daje sześć rekordów produktów do naszego
w pliku baza.sql, a następnie wywołaj na- Status powrotu= 0 magazynu. Przy tej okazji chciałbym rów-
stępujące polecenia w oknie procesora po- nież zwrócić Twoją uwagę na sposób użycia
leceń CLP: Przyjrzyjmy się treści tej procedury. De- komentarzy. W SQL PL masz do dyspozycji
klarację procedury składowanej rozpo- dwa rodzaje komentarzy: jednowierszowe i
db2 create database stock czyna instrukcja CREATE PROCEDURE, po wielowierszowe. Komentarze jednowierszo-
db2 connect to stock której następuje jej nazwa i lista parame- we zaczynają się od podwójnego myślnika i
db2 –tf baza.sql trów ujęta w nawiasy okrągłe. Dalej znaj- mogą wystąpić w dowolnym miejscu proce-
dują się opcjonalne klauzule SPECIFIC oraz dury. Komentarze wielowierszowe zaczyna-
Po utworzeniu testowa baza danych bę- LANGUAGE, a po nich w instrukcji bloko- ją się od znaków /* i kończą znakami */ tak
dzie zawierała jedną tabelę, która symu- wej BEGIN/END następuje ciało procedu- jak w języku C, ale mogą wystąpić tylko w
luje mini magazyn produktów (w naszym ry. Deklarację procedury kończy znak ter- ciele procedury.

14 SDJ Extra 35
Procedury składowane w DB2 9

Jak już się pewnie domyślasz, procedu- Wartości parametrów wyjściowych Zmienne
ra clean będzie nam często służyła do przy- -------------------------- W języku SQL PL każda zmienna przed
gotowywania początkowych danych do eks- Nazwa parametru: P_VALUE użyciem musi być zadeklarowana instrukcją
perymentów z procedurami składowanymi. Wartość parametru: 120,00 DECLARE. Deklaracje muszą wystąpić na po-
Zapisz treść procedury z Listingu 3 do pliku Nazwa parametru: P_TOTAL czątku instrukcji blokowej po słowie BEGIN,
p02.sql i skompiluj, wywołując: Wartość parametru: 320,00 a typy zmiennych powinny odpowiadać ty-
Status powrotu= 0 pom bazy danych DB2. Domyślnie zmien-
db2 -td@ -vf p02.sql ne są inicjalizowane wartością nieokreślo-
Zgodnie z oczekiwaniami, wartość towaru ną NULL, chyba że w deklaracji występuje
Po uruchomieniu tej procedury poleceniem: wynosi 120, a suma częściowa 320. Zwróć klauzula DEFAULT, która ustawia inną war-
uwagę, że w wywołaniu procedury para- tość początkową zmiennej. Zwyczajowo na-
db2 call clean() metr wyjściowy został zastąpiony znakiem zwy zmiennych poprzedza się przedrost-
zapytania. Procesor CLP zinterpretował i kiem v_ dla łatwiejszego odróżnienia ich
w tabeli stock powinno pojawić się sześć wyświetlił wartości wszystkich parametrów od nazw parametrów i nazw kolumn. Do
różnych rodzajów owoców, co łatwo spraw- wyjściowych i wejściowo-wyjściowych prze- ustawiania wartości zmiennych możesz wy-
dzisz, wywołując polecenie: kazanych w wywołaniu procedury. Zauważ, korzystać szereg instrukcji, takich jak SET,
że procedura calc _ value do obliczeń wy- VALUES, SELECT lub GET DIAGNOSTICS. Przy-
db2 select * from stock korzystuje wyłącznie przekazane parame- kłady użycia trzech pierwszych instrukcji
try. Bardziej skomplikowane obliczenia mo- do ustawiania zmiennych przedstawiłem
Parametry procedur gą jednak wymagać użycia zmiennych, więc w procedurze z Listingu 5. Instrukcję GET
Do procedury składowanej możesz przeka- przyjrzyjmy się, w jaki sposób możesz je sto- DIAGNOSTICS opisałem nieco później, przy
zać listę parametrów. Parametry mogą być sować. okazji omawiania obsługi błędów. Zapisz
wejściowe IN, wejściowo-wyjściowe INOUT
oraz wyjściowe OUT. Typy przekazywanych Listing 1. Testowa baza danych
parametrów muszą być zgodne z typami da-
nych języka SQL, a poszczególne parametry -- baza.sql
muszą być od siebie oddzielone przecinka- CREATE TABLE stock
mi. Zwyczajowo nazwy parametrów poprze- (
dzamy prefiksem p_, tak aby nie myliły się z id BIGINT NOT NULL,
nazwami zmiennych i nazwami kolumn. Na name VARCHAR(12) NOT NULL,
Listingu 4 przedstawiłem procedurę, która amount INTEGER NOT NULL DEFAULT 0,
przyjmuje cztery parametry: dwa wejścio- price DECFLOAT DEFAULT 0.0,
we w wierszach {1} i {2}, jeden wyjściowy w promo SMALLINT DEFAULT 0
wierszu {3} i jeden wejściowo-wyjściowy w );
wierszu {4}. Procedura calc_value oblicza
wartość produktu zwracaną w parametrze ALTER TABLE stock ADD CONSTRAINT stock_name_pk
wyjściowym p_value na podstawie podanej PRIMARY KEY (name);
na wejściu ilości p_amount i ceny jednostko- ALTER TABLE stock ALTER COLUMN id
wej p_price. Dodatkowo wartość produktu SET GENERATED BY DEFAULT AS IDENTITY (START WITH 7);
jest dodawana do sumy częściowej p_total, ALTER TABLE stock ADD CONSTRAINT stock_amount_chk
która jest aktualizowana przy każdym wy- CHECK (amount >= 0);
wołaniu procedury. Obliczenia są wykony- ALTER TABLE stock ADD CONSTRAINT stock_price_chk
wane w wierszach {5} i {6}, a na koniec w CHECK (price >= 0.0);
wierszu {7}, za pomocą instrukcji RETURN ALTER TABLE stock ADD CONSTRAINT stock_promo_chk
zwracany jest status wykonania procedury CHECK (promo in (0,1,2,3));
(tzw. status powrotu). Przyjmuje się, że war-
tość zero oznacza poprawne wykonanie pro- CREATE TYPE NAME_ARRAY AS VARCHAR(30) array[100];
cedury, wartości ujemne oznaczają błąd in- CREATE TYPE AMOUNT_ARRAY AS INTEGER array[100];
strukcji SQL, natomiast wartości dodatnie CREATE TYPE PRICE_ARRAY AS INTEGER array[100];
oznaczają umowny błąd wynikający z logiki
przetwarzania. W instrukcji RETURN pro-
cedura może zwracać tylko liczby całkowite.
Listing 2. Najprostsza procedura
Zapisz treść tej procedury w pliku p03.sql i
skompiluj poleceniem:
-- p01.sql
db2 -td@ -vf p03.sql CREATE PROCEDURE simple()
SPECIFIC p01
Sprawdź jej działanie, podając następujące LANGUAGE SQL
parametry w wywołaniu: BEGIN
END
db2 call calc_value(100,1.2,?,200.0) @

Powinieneś uzyskać rezultat podobny do te-


go poniżej:

www.sdjournal.org 15
Tworzenie aplikacji

treść tej procedury w pliku p04.sql i skom- Nazwa parametru: P_PRICE strukcję SELECT, w której w klauzuli INTO
piluj poleceniem: Wartość parametru: 1.05 podaje się odpowiednie zmienne, do któ-
Nazwa parametru: P_VALUE rych będą zapisane wartości kolumn ze
db2 -td@ -vf p04.sql Wartość parametru: 10.50 znalezionego rekordu. Instrukcja SELECT
Nazwa parametru: P_DATE w takim przypadku musi zwracać tylko je-
Procedura get _ info pobiera informacje o Wartość parametru: 06/21/2009 den rekord. Zauważ, że wartości mogą być
produkcie i zwraca je w parametrach wyj- Nazwa parametru: P_TIME w ten sam sposób zapisywane do zmien-
ściowych. Uruchom tę procedurę, wywołu- Wartość parametru: 00:23:32 nych lokalnych, jak i do parametrów wyj-
jąc na przykład: Status powrotu= 0 ściowych. Do przypisywania wartości do
zmiennych możesz wykorzystać instruk-
db2 call get_info('orange',?,?,?,?,?) Przyjrzyjmy się treści tej procedury. cję SET, tak jak w wierszu {4}. Instrukcja
Zmienne zadeklarowane są na początku VALUES w wierszu {5} posłużyła mi do po-
W efekcie jej działania powinieneś otrzymać instrukcji blokowej, zaraz po słowie BEGIN. brania daty z predefiniowanego rejestru
wynik podobny do poniższego: W wierszu {1} zadeklarowana jest zmienna CURRENT DATE, a w wierszach {6} i {7} do
typu INTEGER z wartością ustawianą do- wyliczenia określonej wartości i przypi-
Wartości parametrów wyjściowych myślnie na NULL . Zmienna w wierszu {2} sania do zmiennej, na przykład CURRENT
-------------------------- jest zainicjowana wartością 0,0 w klau- TIME – 1 HOUR . Polecenia VALUES oraz SET
Nazwa parametru: P_AMOUNT zuli DEFAULT. W wierszu {3} do pobrania mogą również być wykorzystane do jedno-
Wartość parametru: 10 ilości i ceny produktu wykorzystałem in- czesnego przypisania wartości do więcej
niż jednej zmiennej, np.:
Listing 3. SQL w procedurze składowanej
SET (p_amount, v_value) = (10, 12)
-- p02.sql
CREATE PROCEDURE clean() Jak widzisz, DB2 udostępnia szeroki wa-
SPECIFIC p02 chlarz możliwości wykorzystania zmien-
LANGUAGE SQL nych – z większością z nich spotkasz się jesz-
BEGIN cze w kolejnych przykładach procedur.
-– Delete all existing products.
DELETE FROM stock; --{1} Złożony SQL
/* – instrukcja blokowa
Insert initial number of products to stock table. Instrukcja blokowa grupuje pojedyncze in-
All products will be added at once, using single strukcje języka SQL PL, które umieszcza się
INSERT statement. pomiędzy słowami kluczowymi BEGIN i END.
*/ Jeśli przypomnisz sobie pierwszą procedu-
INSERT INTO stock VALUES --{2} rę z Listingu 2, to przekonasz się, że ciało tej
(1, 'orange', 10, 1.05, 0), procedury to po prostu pusta instrukcja blo-
(2, 'lemon', 30, 2.10, 1), kowa. Instrukcje blokowe możesz zagnież-
(3, 'lime', 60, 3.15, 1), dżać – przykład takiej procedury przedsta-
(4, 'grapes', 90, 4.20, 2), wiłem na Listingu 6. W wierszu {1} od sło-
(5, 'apple', 120, 5.25, 2), wa BEGIN rozpoczyna się deklaracja ciała
(6, 'banana', 150, 6.30, 3); procedury, która kończy się słowem END w
END wierszu {12}. Wewnątrz procedury znajdu-
@ je się zagnieżdżona instrukcja blokowa, któ-
ra rozpoczyna się w wierszu {4}, a kończy
w wierszu {11}. Zwróciłeś już pewnie uwa-
gę na to, że w obu instrukcjach blokowych,
Listing 4. Parametry procedur
na ich początku są zadeklarowane zmienne.
Warto pamiętać, że wszystkie zasady doty-
-- p03.sql czące deklarowania zmiennych, kursorów i
CREATE PROCEDURE calc_value( innych obiektów wewnątrz instrukcji blo-
IN p_amount INTEGER, --{1} kowych obowiązują również w blokach za-
IN p_price DECFLOAT, --{2} gnieżdżonych.
OUT p_value DECFLOAT, --{3}
INOUT p_total DECFLOAT) --{4} Złożony SQL – etykiety
LANGUAGE SQL Instrukcja blokowa i dowolne wyrażenie
SPECIFIC p03 SQL-owe mogą być opatrzone etykietą, co
BEGIN również pokazałem na Listingu 6. Etykie-
SET p_value = p_amount * p_price; --{5} ty poprawiają czytelność kodu, ale przede
SET p_total = p_total + p_value; --{6} wszystkim pozwalają przemieścić się w
RETURN 0; --{7} dowolne miejsce wewnątrz procedury. Po-
END nadto etykiety są wykorzystywane w pę-
@ tli LOOP, którą się zajmiemy nieco później.
Instrukcje blokowe w wierszach {1} i {4}
na Listingu 6 zostały opatrzone etykieta-

16 SDJ Extra 35
Procedury składowane w DB2 9

mi o nazwach odpowiednio l_1 i l_2. Za- szej ilości produktu niż jest dostępna na stock _ amount _ chk na Listingu 1). Przed
uważ, że etykiety umieściłem przed sło- magazynie spowoduje wygenerowanie uruchomieniem procedury sell przygotuj
wem BEGIN, a dla przejrzystości kodu te sa- błędu, ponieważ ilość produktu nie mo- dane początkowe, wywołując znaną już z
me etykiety podałem po słowie END dla każ- że być mniejsza od zera (zobacz warunek Listingu 3 procedurę clean:
dego bloku. W wierszach {9} i {10} umie-
ściłem etykiety o nazwach l_3 i l_4 przed Listing 5. Zmienne w procedurze składowanej
instrukcjami SQL-owymi, dzięki czemu
mógłbym przeskoczyć do nich z innego -- p04.sql
miejsca procedury za pomocą instrukcji CREATE PROCEDURE get_info(
GOTO. Zauważ, że na początku każdego blo- IN p_name VARCHAR(12),
ku zadeklarowałem dwie zmienne o takich OUT p_amount INTEGER,
samych nazwach. Zmienne zadeklarowane OUT p_price DECFLOAT,
w zagnieżdżonym bloku w wierszach {5} i OUT p_value DECFLOAT,
{6} przesłoniły zmienne zadeklarowane w OUT p_date DATE,
bloku nadrzędnym w wierszach {2} i {3}. OUT p_time TIME
W takich przypadkach pomocne są właśnie )
etykiety umieszczone przy instrukcjach LANGUAGE SQL
blokowych. Do przesłoniętej zmiennej mo- SPECIFIC p04
żesz odwołać się, używając etykiety z nad- BEGIN
rzędnej instrukcji blokowej jako prefiksu, DECLARE v_amount INTEGER; --{1}
tak jak pokazałem to w wierszach {7} i {8}. DECLARE v_value DECFLOAT DEFAULT 0.0; --{2}
SELECT amount, price --{3}
Złożony SQL – ATOMIC INTO v_amount, p_price
Instrukcja blokowa może być opatrzona FROM stock
klauzulą ATOMIC lub NOT ATOMIC. Użycie WHERE name = p_name;
klauzuli ATOMIC powoduje, że wszystkie SET p_amount = v_amount; --{4}
polecenia SQL-owe wewnątrz bloku będą VALUES CURRENT DATE INTO p_date; --{5}
traktowane jako jedna całość, co oznacza, VALUES (CURRENT TIME – 1 HOUR) INTO p_time; --{6}
że jeśli gdzieś wewnątrz bloku wystąpi nie- VALUES (v_amount * p_price) INTO p_value; --{7}
obsłużony błąd, to wszystkie instrukcje w END
tym bloku zostaną wycofane, nawet te, któ- @
re wykonały się poprawnie. W procedurze
na Listingu 6 instrukcja blokowa rozpoczy- Listing 6. Złożony SQL
nająca się w wierszu {4} ma podaną klauzu-
lę ATOMIC, natomiast blok w wierszu {1} jej -- p05.sql
nie ma, co jest równoznaczne z podaniem CREATE PROCEDURE sell(
klauzuli NOT ATOMIC. Jak się pewnie domy- IN p_name1 VARCHAR(12),
ślasz, klauzula NOT ATOMIC powoduje, że in- IN p_amount1 INTEGER,
strukcje wewnątrz bloku nie są traktowa- IN p_name2 VARCHAR(12),
ne jako jedna całość. Jeśli wewnątrz takie- IN p_amount2 INTEGER
go bloku wystąpi nieobsłużony błąd, to in- )
strukcje, które do miejsca wystąpienia te-
go błędu wykonały się poprawnie, nie zo- LANGUAGE SQL
staną automatycznie wycofane. W takim SPECIFIC p05
przypadku musisz ręcznie anulować je in- l_1: BEGIN --{1}
strukcją ROLLBACK czy też ROLLBACK TO DECLARE v_amount1 INTEGER; --{2}
SAVEPOINT. Jeśli ma to sens, możesz oczy- DECLARE v_amount2 INTEGER; --{3}
wiście zatwierdzić dotychczasowe zmia- SELECT amount INTO v_amount1
ny instrukcją COMMIT. Sprawdźmy działa- FROM stock WHERE name = p_name1;
nie klauzuli ATOMIC w praktyce. W tym ce- SELECT amount INTO v_amount2
lu zapisz procedurę z Listingu 6 w pliku FROM stock WHERE name = p_name2;
p05.sql i skompiluj poleceniem: l_2: BEGIN ATOMIC --{4}
DECLARE v_amount1 INTEGER; --{5}
db2 -td@ -vf p05.sql DECLARE v_amount2 INTEGER; --{6}
SET v_amount1 = l_1.v_amount1 – p_amount1; --{7}
Procedura ta służy do sprzedaży produk- SET v_amount2 = l_1.v_amount2 – p_amount2; --{8}
tów parami, ale jeśli oba produkty nie l_3: UPDATE stock SET amount = v_amount1 --{9}
występują w żądanych ilościach na maga- WHERE name = p_name1;
zynie, to nie możemy sprzedać żadnego l_4: UPDATE stock SET amount = v_amount2 --{10}
z nich. Aby uzyskać taki efekt, instruk- WHERE name = p_name2;
cje SQL-owe w wierszach {9} i {10}, któ- END l_2; --{11}
re aktualizują ilość produktów, są obję- END l_1 --{12}
te instrukcją blokową z klauzulą ATOMIC. @
Dodam tylko, że próba sprzedaży więk-

www.sdjournal.org 17
Tworzenie aplikacji

db2 call clean() Powinieneś uzyskać rezultat podobny do po- niem błędu. Sprawdź zatem, jak wygląda
kazanego poniżej: obecnie stan magazynowy, ponownie wy-
i sprawdź stan magazynowy, wywołując: wołując:
NAME AMOUNT
db2 select name, amount from stock ------------ ----------- db2 select name, amount from stock
orange 0
Ilości dostępnych produktów powinny być lemon 0 Wynik powinien wyglądać tak jak poniżej:
takie jak pokazane poniżej: lime 60
grapes 90 NAME AMOUNT
NAME AMOUNT apple 120 ------------ -----------
------------ ----------- banana 150 orange 0
orange 10 lemon 0
lemon 30 Pomarańcze i cytryny zostały w całości lime 60
lime 60 sprzedane, ich ilości na magazynie są zero- grapes 90
grapes 90 we. Teraz spróbujmy sprzedać wszystkie li- apple 120
apple 120 monki i więcej winogron niż jest dostępnych banana 150
banana 150 na magazynie, wywołując:
Zgodnie z naszymi oczekiwaniami zarów-
Teraz spróbujmy sprzedać wszystkie poma- db2 call sell('lime',30,'grapes',91) no stan ilościowy limonek, jak i winogron
rańcze i cytryny: SQL0545N Żądana operacja nie jest nie uległ zmianie, ponieważ błąd wygenero-
dopuszczalna, ponieważ wiersz nie wany w wierszu {10} spowodował wycofa-
db2 call sell('orange',10,'lemon',30) spełnia ograniczenia sprawdzenia nie zmian dokonanych w wierszu {9}, a sta-
"STOCK.STOCK_AMOUNT_CHK". ło się tak dlatego, że obie instrukcje UPDATE
Ponownie sprawdź stan magazynowy, wy- SQLSTATE=23513 objęte są blokiem z klauzulą ATOMIC. War-
wołując: to pamiętać, że instrukcje blokowe z klau-
Tak jak się spodziewaliśmy, próba sprzeda- zulą ATOMIC nie mogą być zagnieżdżane, a
db2 select name, amount from stock ży winogron zakończyła się wygenerowa- ponadto wewnątrz takiego bloku nie mo-

Listing 7. Instrukcja warunkowa IF SET p_promo3 = p_price * 0.7;


ELSE
-- p06.sql SET p_promo3 = p_price;
CREATE PROCEDURE get_prices( END IF;
IN p_name VARCHAR(12), END
OUT p_price DECFLOAT, @
OUT p_promo1 DECFLOAT,
OUT p_promo2 DECFLOAT, Listing 8. Instrukcja warunkowa CASE – wariant 1
OUT p_promo3 DECFLOAT
) -- p07.sql
LANGUAGE SQL CREATE PROCEDURE get_discount_price(
SPECIFIC p06 IN p_name VARCHAR(12),
BEGIN OUT p_price DECFLOAT,
DECLARE v_amount INTEGER; OUT p_promo3 DECFLOAT
DECLARE v_promo SMALLINT; )
SELECT amount, price, promo LANGUAGE SQL
INTO v_amount, p_price, v_promo SPECIFIC p07
FROM stock WHERE name = p_name; BEGIN
DECLARE v_promo SMALLINT;
IF p_price > 5.0 THEN --{1} SELECT promo, price INTO v_promo, p_price
SET p_promo1 = p_price * 0.95; FROM stock WHERE name = p_name;
END IF; CASE v_promo --{1}
WHEN 1 THEN --{2}
IF v_amount > 50 THEN --{2} SET p_promo3 = p_price * 0.9;
SET p_promo2 = p_price * 0.85; WHEN 2 THEN --{3}
ELSE SET p_promo3 = p_price * 0.8;
SET p_promo2 = NULL; WHEN 3 THEN --{4}
END IF; SET p_promo3 = p_price * 0.7;
ELSE --{5}
IF v_promo = 1 THEN --{3} SET p_promo3 = p_price * 1.0;
SET p_promo3 = p_price * 0.9; END CASE;
ELSEIF v_promo = 2 THEN END
SET p_promo3 = p_price * 0.8; @
ELSEIF v_promo = 3 THEN

18 SDJ Extra 35
Procedury składowane w DB2 9

żesz użyć instrukcji COMMIT, ROLLBACK i słowa kluczowego ELSEIF. Przykład uży- Przygotuj dane początkowe, uruchamiając
SAVEPOINTS. Blok ATOMIC można traktować cia ELSEIF pokazałem w wierszu {3} na procedurę clean:
jak pojedynczą, nierozerwalną instrukcję Listingu 7, gdzie kilkakrotnie sprawdzam
SQL, która zbudowana jest z wielu elemen- kod promocyjny (dla wartości 1, 2 i 3), i db2 call clean()
tów. Na koniec nadmienię, że niezależnie na jego podstawie odpowiednio zmniej-
od rodzaju wykorzystanego bloku ATOMIC szam cenę o 10, 20 i 30 procent. Jeśli kod i sprawdź ceny promocyjne na przykład dla
bądź NOT ATOMIC do programisty należy de- promocyjny ma wartość 0, to na końcu tej bananów, wywołując:
cyzja o finalnym zatwierdzeniu bądź wy- instrukcji IF w klauzuli ELSE ustawiam ce-
cofaniu wykonanych operacji (np. COMMIT nę promocyjną na początkową cenę pro- db2 call get_prices('banana',?,?,?,?)
bądź ROLLBACK w programie po wykona- duktu. Sprawdźmy w takim razie działa-
niu procedury). W analizowanym przykła- nie instrukcji IF w praktyce. Zapisz proce- Powinieneś otrzymać następujący wynik:
dzie wywołanie procedury inicjowane by- durę z Listingu 7 do pliku p06.sql i skom-
ło z tekstowego interpretera, który w do- piluj, wywołując: Wartości parametrów wyjściowych
myślnej konfiguracji automatycznie dodaje --------------------------
COMMIT po każdej interpretowanej instruk- db2 -td@ -vf p06.sql Nazwa parametru: P_PRICE
cji (tu: po wywołaniu procedury instruk-
cją CALL). Listing 9. Instrukcja warunkowa CASE – wariant 2

Instrukcje warunkowe -- p08.sql


Instrukcje warunkowe umożliwiają zmia- CREATE PROCEDURE can_delete_product(
nę działania procedury w zależności od IN p_name VARCHAR(12)
tego, czy jest spełniony określony waru- )
nek. W SQL PL dostępne są dwie instruk- SPECIFIC p08
cje warunkowe: IF oraz CASE. W instruk- LANGUAGE SQL
cji IF jako warunek musisz podać wyraże- BEGIN
nie logiczne (wartość prawda lub fałsz), DECLARE v_amount INTEGER DEFAULT -1;
natomiast w instrukcji CASE jako waru- SELECT amount INTO v_amount
nek możesz wykorzystać wartość pojedyn- FROM stock WHERE name = p_name;
czej zmiennej (na przykład liczbę całko- CASE --{1}
witą). Przykład wykorzystania instrukcji WHEN v_amount = 0 THEN RETURN 0; --{2}
IF zamieściłem na Listingu 7. W przykła- WHEN v_amount > 0 THEN RETURN -1; --{3}
dzie tym obliczane są trzy ceny promocyj- ELSE RETURN -2; --{4}
ne: pierwsza cena p_promo1 zależy od ce- END CASE;
ny jednostkowej, druga p_promo2 od ilości END
towaru na magazynie, a trzecia p_promo3 @
od kodu promocyjnego. W najprostszym
przypadku, tak jak w wierszu {1}, instruk-
cja IF wykonuje określony ciąg czynności,
Listing 10. Pętla WHILE
jeśli podany warunek logiczny jest spełnio-
ny. W wierszu {1}, jeśli cena jednostko-
wa przekracza 5.00 PLN, to pierwsza ce- -- p09.sql
na promocyjna zostanie obniżona o 5%, w CREATE PROCEDURE avg_while(
przeciwnym razie cena nie zostanie zmie- IN p_start INTEGER,
niona i nadal będzie miała wartość NULL. IN p_end INTEGER,
Zwróć uwagę, że warunek został umiesz- OUT p_avg DECFLOAT
czony pomiędzy słowami IF oraz THEN, a )
ciąg instrukcji do wykonania umieszczo- LANGUAGE SQL
ny został pomiędzy słowami THEN oraz END SPECIFIC p09
IF . Z kolei jeśli chcesz, aby pewne instruk- BEGIN
cje zostały wykonane, kiedy warunek jest DECLARE v_sum DECFLOAT DEFAULT 0.0;
spełniony, a inne, gdy warunek nie jest DECLARE v_counter INTEGER DEFAULT 0;
spełniony, to możesz wykorzystać słowo DECLARE v_current INTEGER;
kluczowe ELSE. Instrukcje przed słowem SET v_current = p_start;
ELSE będą wykonane, jeśli warunek jest WHILE (v_current <= p_end) DO --{1}
spełniony, a po słowie ELSE, gdy warunek SET v_sum = v_sum + v_current;
nie jest spełniony. W przykładzie pokaza- SET v_current = v_current + 1;
nym w wierszu {2} na Listingu 7 cena pro- SET v_counter = v_counter + 1;
duktu zostanie obniżona o 15%, jeśli jego END WHILE; --{2}
ilość na magazynie przekracza 50, w prze- SET p_avg = v_sum / v_counter; --{3}
ciwnym razie cena promocyjna p_promo2 END
będzie nieokreślona (wartość NULL). W @
ostatnim przypadku instrukcję IF mo-
żesz wykorzystać do wykonania wielu wy-
stępujących po sobie porównań z użyciem

www.sdjournal.org 19
Tworzenie aplikacji

Wartość parametru: 6.30 Wszystkie ceny promocyjne zostały wyli- sprawdzić sytuacje, kiedy poszczególne in-
Nazwa parametru: P_PROMO1 czone, ponieważ dla przypadku z wiersza strukcje warunkowe się nie wykonają.
Wartość parametru: 5.9850 {1} cena jest większa od 5.0, dla przypad- Jak pewnie zauważyłeś, w ostatnim przy-
Nazwa parametru: P_PROMO2 ku {2} ilość przekracza 50, a w przypadku kładzie w wierszu {3} cena zależy bezpo-
Wartość parametru: 5.3550 {3} kod promocyjny jest równy 3. Możesz średnio od kodu promocyjnego będącego
Nazwa parametru: P_PROMO3 poeksperymentować z pobieraniem cen liczbą całkowitą o wartościach od 0, 1, 2
Wartość parametru: 4.410 promocyjnych dla innych produktów, aby i 3. W takim przypadku do obliczenia ce-
ny promocyjnej możesz użyć instrukcji wa-
Listing 11. Pętla REPEAT runkowej CASE, co pokazałem na Listin-
gu 8. Zauważ, że kod promocyjny v_promo
-- p10.sql występuje tylko jeden raz po słowie CASE w
CREATE PROCEDURE avg_repeat( wierszu {1}, natomiast porównywane war-
IN p_start INTEGER, tości są podawane po słowie WHEN w ko-
IN p_end INTEGER, lejnych wierszach {2}, {3} i {4}. Po słowie
OUT p_avg DECFLOAT THEN w każdym warunku następują in-
) strukcje do wykonania w przypadku gdy
LANGUAGE SQL kod promocyjny ma określoną wartość. In-
SPECIFIC p10 strukcja CASE może mieć podaną klauzu-
BEGIN lę ELSE, tak jak w wierszu {5}, która zosta-
DECLARE v_sum DECFLOAT DEFAULT 0.0; nie wykonana, jeśli nie został spełniony ża-
DECLARE v_counter INTEGER DEFAULT 0; den wcześniejszy warunek. Sprawdźmy za-
DECLARE v_current INTEGER; tem ponownie cenę promocyjną bananów,
SET v_current = p_start; ale z wykorzystaniem procedury z Listin-
REPEAT --{1} gu 8. Zapisz treść tej procedury do pliku
SET v_sum = v_sum + v_current; p07.sql i skompiluj:
SET v_current = v_current + 1;
SET v_counter = v_counter + 1; db2 -td@ -vf p07.sql
UNTIL (v_current > p_end) --{2}
END REPEAT; --{3} a następnie wywołaj:
SET p_avg = v_sum / v_counter;
END db2 call get_discount_price('banana',?,?)
@
Jak można było się spodziewać, wynik bę-
Listing 12. Pętla LOOP dzie taki sam jak poprzednio dla trzeciej ce-
ny promocyjnej:
-- p11.sql
CREATE PROCEDURE avg_loop( Wartości parametrów wyjściowych
IN p_start INTEGER, --------------------------
IN p_end INTEGER, Nazwa parametru: P_PRICE
OUT p_avg DECFLOAT Wartość parametru: 6.30
) Nazwa parametru: P_PROMO3
LANGUAGE SQL Wartość parametru: 4.410
SPECIFIC p11
BEGIN W procedurze na Listingu 9 pokazałem
DECLARE v_sum DECFLOAT DEFAULT 0.0; jeszcze jeden wariant instrukcji CASE, w
DECLARE v_counter INTEGER DEFAULT 0; którym po słowie CASE w wierszu {1} nie
DECLARE v_current INTEGER; występuje liczba całkowita, natomiast po
SET v_current = p_start; każdym słowie WHEN w wierszach {2} i {3}
L1: LOOP --{1} może być użyty dowolny warunek logicz-
SET v_sum = v_sum + v_current; ny. Dla formalności dodam, że procedura
SET v_counter = v_counter + 1; can _ delete _ product sprawdza ilość pro-
IF (v_current >= p_end) THEN duktu na magazynie i jeśli jego ilość wynosi
LEAVE L1; --{2} zero, to zwraca 0, jeśli ilość jest większa od
ELSE zera, to zwraca -1, natomiast jeśli produk-
SET v_current = v_current + 1; tu w ogóle nie ma na magazynie, to zwra-
ITERATE L1; --{3} ca -2. Zwróć uwagę, że jeśli produkt nie wy-
END IF; stępuje na magazynie, to wartość zmiennej
END LOOP; --{4} v _ amount nie zostanie określona przez in-
SET p_avg = v_sum / v_counter; strukcję SELECT INTO (zapytanie nie zwró-
END ci żadnego rekordu) i pozostanie taka sa-
@ ma jak po jej zadeklarowaniu, czyli -1. W
przykładzie z Listingu 9 zademonstrowa-
łem możliwość wykorzystania instrukcji
RETURN do przekazania stanu magazyno-

20 SDJ Extra 35
Procedury składowane w DB2 9

wego. Dobrą praktyką jest jednak wykorzy- jest większa od liczby końcowej p _ end, to zaimplementowany z użyciem pętli REPEAT.
stanie tej instrukcji wyłącznie do celów dia- niestety w wierszu {3} wystąpi błąd dzie- Zapisz procedurę z Listingu 11 do pliku
gnostycznych, a nie aplikacyjnych. Skompi- lenia przez zero, co łatwo sprawdzić, wy- p10.sql i skompiluj:
luj tę procedurę po zapisaniu jej do pliku o wołując:
nazwie p08.sql: db2 -td@ -vf p10.sql
db2 call avg_while(10,1,?)
db2 -td@ -vf p08.sql SQL0801N Próbowano wykonać dzielenie Po uruchomieniu:
przez zero. SQLSTATE=22012
i uruchom dla nieistniejącego produktu, na db2 call avg_repeat(1,10,?)
przykład dla arbuzów: Dzieje się tak dlatego, że licznik v _ counter
ma wartość domyślną 0 i nie jest nigdy otrzymasz ten sam wynik, czyli 5,50.
db2 call can_delete_product('watermelon') zwiększany, gdyż warunek wejścia do pętli Sprawdź, co się stanie, jeśli liczba początko-
nie jest w tym przypadku spełniony. Na Li- wa będzie większa od liczby końcowej, wy-
Wynik będzie oczywiście następujący: stingu 11 przedstawiłem ten sam algorytm wołując:

Status powrotu= -2 Listing 13. Instrukcja GOTO

Pętle -- p12.sql
W języku SQL PL dostępne są pętle WHILE, CREATE PROCEDURE avg_goto(
REPEAT, LOOP oraz FOR. Pętle WHILE i REPEAT IN p_start INTEGER,
wykorzystujemy w przypadkach, kiedy nie IN p_end INTEGER,
wiemy, ile razy będziemy iterować zanim OUT p_avg DECFLOAT
nie wejdziemy do pętli, natomiast pętli FOR )
możesz użyć do iterowania po zbiorze wy- LANGUAGE SQL
nikowym opartym na instrukcji SELECT. SPECIFIC p12
Z kolei instrukcja LOOP może Ci posłużyć BEGIN
do implementacji pętli ogólnego przezna- DECLARE v_sum DECFLOAT DEFAULT 0.0;
czenia. Działanie pętli WHILE, REPEAT oraz DECLARE v_counter INTEGER DEFAULT 0;
LOOP prześledzimy na przykładzie oblicza- DECLARE v_current INTEGER;
nia średniej arytmetycznej. Jako ciekawost- SET v_current = p_start;
kę pokażę Ci również, jak zrealizować pętlę L1: BEGIN
LOOP za pomocą instrukcji GOTO. Na Listin- SET v_sum = v_sum + v_current;
gu 10 zamieściłem procedurę wykorzystują- SET v_counter = v_counter + 1;
cą pętlę WHILE. Zapisz treść tej procedury w IF (v_current >= p_end) THEN
pliku p09.sql i skompiluj poleceniem: GOTO L2;
ELSE
db2 -td@ -vf p09.sql SET v_current = v_current + 1;
GOTO L1;
Sprawdź działanie tej procedury, wydając END IF;
polecenie: END;
L2: SET p_avg = v_sum / v_counter;
db2 call avg_while(1,10,?) END
@
Na konsoli pojawi się wynik przedstawio-
ny poniżej:
Listing 14. Pętla FOR
Wartości parametrów wyjściowych
--------------------------
Nazwa parametru: P_AVG -- p13.sql
Wartość parametru: 5,50 CREATE PROCEDURE get_total(
Status powrotu= 0 OUT p_total DECFLOAT
)
Wyliczona średnia to 5,50. Przyjrzyjmy się SPECIFIC p13
treści procedury z Listingu 10. Składnia LANGUAGE SQL
pętli jest następująca: w wierszu {1} roz- BEGIN
poczyna się słowem kluczowym WHILE, po SET p_total = 0.0;
którym występuje warunek pętli oraz sło- FOR v_row AS SELECT amount, price FROM stock --{1}
wo kluczowe DO, a po nim umieszcza się DO
ciało pętli zakończone słowami END WHILE SET p_total = p_total + v_row.amount * v_row.price; --{2}
– wiersz {2}. Warunek pętli WHILE jest END FOR;
sprawdzany przed wykonaniem jakiejkol- END
wiek instrukcji umieszczonej w ciele pętli. @
W naszym przypadku ma to pewne konse-
kwencje: jeśli liczba początkowa p _ start

www.sdjournal.org 21
Tworzenie aplikacji

db2 call avg_repeat(10,1,?) mi {1} i {2}, więc licznik v _ counter jest słowami END REPEAT {3}. Spójrz teraz na Li-
zwiększany co najmniej raz. Dla formalno- sting 12, na którym przedstawione jest to
Obliczona średnia wynosi 10,0 i nie po- ści dodam, że deklaracja pętli rozpoczyna samo rozwiązanie z wykorzystaniem pętli
jawia się błąd dzielenia przez zero. Dzie- się słowem REPEAT {1}, po którym następu- LOOP. Różni się ono od dwóch poprzednich
je się tak dlatego, że warunek pętli jest ją instrukcje będące ciałem pętli, następ- tym, że nie posiada klauzuli deklarującej
sprawdzany na jej końcu, po wykonaniu nie po słowie UNTIL umieszczamy waru- warunek kończący pętlę. Z założenia LOOP
wszystkich instrukcji pomiędzy wiersza- nek pętli {2}, a całą deklarację kończymy {1} jest nieskończoną pętlą, a do jej stero-
wania służą instrukcje ITERATE {3}, LEAVE
Listing 15. Odczyt danych z użyciem kursora {2} oraz GOTO. Instrukcja ITERATE rozpo-
czyna kolejną iterację od początku pę-
-- p14.sql tli, LEAVE opuszcza daną pętlę, natomiast
CREATE PROCEDURE get_total_value( GOTO pozwala przemieścić się w dowolny
OUT p_value DECFLOAT punkt procedury. Pętla musi być opatrzo-
) na etykietą, jak w wierszu {1}. Ciało pętli
SPECIFIC p14 kończą słowa END LOOP w wierszu {4}. Pętla
LANGUAGE SQL LOOP może okazać się pomocna w sytuacji,
BEGIN gdy musisz zaprogramować kilka różnych
DECLARE v_amount INTEGER DEFAULT 0; metod jej opuszczenia. Trzeba jednak pa-
DECLARE v_price DECFLOAT DEFAULT 0.0; miętać, aby stosować tę pętlę z rozwagą
DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; --{1} i nie dopuścić do sytuacji, w której pętla
DECLARE c_stock CURSOR FOR --{2} nigdy się nie zakończy. Zapisz procedurę
SELECT amount, price FROM stock; z Listingu 12 do pliku p11.sql i skompi-
SET p_value = 0.0; luj poleceniem:
OPEN c_stock; --{3}
FETCH FROM c_stock INTO v_amount, v_price; --{4} db2 -td@ -vf p11.sql
WHILE (SQLSTATE = '00000') DO --{5}
SET p_value = p_value + v_amount * v_price; --{6} Policz ponownie średnią liczb od 1 do 10:
FETCH FROM c_stock INTO v_amount, v_price; --{7}
END WHILE; db2 call avg_loop(1,10,?)
CLOSE c_stock; --{8}
END Otrzymany wynik to oczywiście 5,50. Dla
@ porównania, na Listingu 13 przedstawiłem
tę samą pętlę zrealizowaną za pomocą in-
Listing 16. Modyfikacja danych za pomocą kursora strukcji GOTO. Wywołanie polecenia GOTO po-
woduje przeskok programu do miejsca ozna-
-- p15.sql czonego podaną etykietą. Z racji tego, że
CREATE PROCEDURE sell_bundle( używanie instrukcji GOTO nie należy do do-
IN p_amount INTEGER brych praktyk programistycznych, przykład
) ten potraktuj jako ciekawostkę.
SPECIFIC p15 Do iterowania po zbiorze wynikowym
LANGUAGE SQL opartym na instrukcji SELECT służy pętla FOR,
BEGIN której przykład zastosowania przedstawiłem
DECLARE v_amount INTEGER DEFAULT 0; na Listingu 14. Procedura get_total sumu-
DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; je całkowitą wartość produktów na podsta-
DECLARE c_stock CURSOR FOR wie ich ilości i ceny jednostkowej. Zapisz treść
SELECT amount FROM stock procedury z Listingu 14 do pliku p13.sql i
FOR UPDATE; --{1} skompiluj poleceniem:
OPEN c_stock;
FETCH FROM c_stock INTO v_amount; db2 -td@ -vf p13.sql
WHILE (SQLSTATE = '00000') DO
IF (p_amount >= v_amount) THEN --{2} Wywołanie procedury:
DELETE FROM stock
WHERE CURRENT OF c_stock; --{3} db2 call get_total(?)
ELSE
UPDATE stock SET amount = v_amount – p_amount wyświetli całkowitą wartość towarów, na
WHERE CURRENT OF c_stock; --{4} przykład:
END IF;
FETCH FROM c_stock INTO v_amount; Wartości parametrów wyjściowych
END WHILE; --------------------------
CLOSE c_stock; Nazwa parametru: P_TOTAL
END Wartość parametru: 2215,50
@
Wróćmy do Listingu 14. Deklaracja pętli
rozpoczyna się słowem FOR, po którym na-

22 SDJ Extra 35
Procedury składowane w DB2 9

stępuje nazwa pętli, a po niej definiujemy Przyjrzyjmy się bliżej treści tej procedury. W kursor jest ustawiony przed pierwszym
zapytanie SQL-owe zwracające zbiór wy- wierszu {2} zadeklarowałem kursor o nazwie rekordem, dlatego w wierszu {4} wywo-
nikowy, po którym będziemy iterować. Po- c _ stock, który będzie odczytywał wszyst- łuję instrukcję FETCH, która ustawia kur-
między słowami DO i END FOR umieszcza- kie rekordy zwrócone przez instrukcję: sor na pierwszym rekordzie i jednocześnie
my ciało pętli. Pętla będzie się wykony- przepisuje do zmiennych v _ amount i v _
wała tak długo, dopóki nie zostaną odczy- SELECT amount, price FROM stock; price wartości z kolumn amount i price.
tane wszystkie rekordy zbioru wynikowe- Do odczytywania pozostałych rekordów
go. Zwróć uwagę na to, że dostęp do ko- Zwróć uwagę, że deklarację kursora umie- wykorzystałem w wierszu {5} pętlę WHILE,
lumn bieżącego rekordu w zbiorze wyniko- ściłem po deklaracjach zmiennych – takie w której w wierszu {7} kolejny raz wywo-
wym jest możliwy przez prefiksowanie na- jest wymaganie języka SQL PL. Wykona- łuję polecenie FETCH. W warunku pętli, do
zwy kolumny nazwą pętli, na przykład v _ nie instrukcji SELECT i przygotowanie ze- sprawdzenia, czy kursor osiągnął już ostat-
row.amount. stawu rekordów dla kursora odbywa się ni rekord, użyłem zadeklarowanej w wier-
w momencie, kiedy w wierszu {3} otwie- szu {1} zmiennej SQLSTATE. Po każdym po-
Kursory ram kursor instrukcją OPEN. Po otwarciu prawnym wykonaniu instrukcji FETCH (w
W praktyce często spotykamy się z sytuacją,
kiedy na określonym zbiorze rekordów mu- Listing 17. Zachowanie kursora z COMMIT i ROLLBACK
simy wykonać dość złożoną logikę bizneso-
wą, analizując kolejno rekord po rekordzie. -- p16.sql
W takich przypadkach z pomocą przycho- CREATE PROCEDURE hold_test()
dzą nam kursory. W tym podrozdziale po- SPECIFIC p16
każę, jak można wykorzystać kursor do po- LANGUAGE SQL
bierania danych do obliczeń (w trybie tyl- BEGIN
ko do odczytu), a w kolejnych wyjaśnię, jak DECLARE v_amount INTEGER;
stosować kursory do modyfikacji danych i DECLARE c_stock CURSOR WITH HOLD FOR --{1}
przekazywania danych do procedur wywo- SELECT amount FROM stock
łujących. Kursor możemy sobie wyobrazić ORDER BY id
jako wskaźnik, który przesuwa się kolejno FOR UPDATE OF amount; --{2}
po każdym rekordzie, udostępniając warto- OPEN c_stock;
ści jego kolumn. Przed użyciem musimy za- FETCH FROM c_stock INTO v_amount;
deklarować kursor instrukcją DECLARE, a na- UPDATE stock SET amount = v_amount + 1000
stępnie otworzyć poleceniem OPEN. Otwar- WHERE CURRENT OF c_stock;
cie kursora oznacza przygotowanie zestawu COMMIT; --{3}
rekordów (wykonanie instrukcji SELECT) FETCH FROM c_stock INTO v_amount;
i ustawienie kursora przed pierwszym re- UPDATE stock SET amount = v_amount + 2000
kordem. Do przesuwania się po kolejnych WHERE CURRENT OF c_stock;
rekordach służy polecenie FETCH, które naj- COMMIT; --{4}
częściej wywołuje się w pętli aż do przejścia FETCH FROM c_stock INTO v_amount;
przez wszystkie rekordy. W warunku pętli UPDATE stock SET amount = v_amount + 3000
najczęściej stosujemy zmienną SQLSTATE do WHERE CURRENT OF c_stock;
sprawdzenia, czy został już osiągnięty ostat- ROLLBACK; --{5}
ni rekord. Na koniec, kiedy kursor nie jest FETCH FROM c_stock INTO v_amount; --{6}
już potrzebny, zamykamy go poleceniem END
CLOSE. Na Listingu 15 przedstawiłem proce- @
durę get_total_value, która wykorzystuje
kursor do obliczenia sumarycznej wartości
wszystkich produktów w magazynie (tak, Listing 18. Zwracanie zbioru wynikowego za pomocą kursora
dokładnie to samo, co wcześniej robiliśmy
za pomocą pętli FOR). Skompiluj tę procedu- -- p17.sql
rę poleceniem: CREATE PROCEDURE double_amounts()
SPECIFIC p17
db2 -td@ -vf p14.sql LANGUAGE SQL
DYNAMIC RESULT SETS 1 --{1}
a następnie uruchom, wywołując: BEGIN
UPDATE stock SET amount = amount * 2; --{2}
db2 call get_total_value(?) BEGIN
DECLARE c_stock CURSOR WITH RETURN FOR --{3}
W wyniku działania procedura zwróci w SELECT name, amount FROM stock;
parametrze p _ value sumaryczną wartość OPEN c_stock; --{4}
wszystkich produktów: END;
END
Wartości parametrów wyjściowych @
--------------------------
Nazwa parametru: P_VALUE
Wartość parametru: 2215.50

www.sdjournal.org 23
Tworzenie aplikacji

wierszach {4} i {7}) zmienna SQLSTATE jest ny na ostatnim rekordzie, to wywołanie być sprawdzana zaraz po wykonaniu da-
ustawiana przez DB2 na wartość ‘00000'. FETCH w wierszu {7} spowoduje ustawienie nej instrukcji, dlatego też pomiędzy in-
Jeśli po otwarciu kursora okazałoby się, że SQLSTATE na wartość różną od ‘00000' i na- strukcją FETCH a sprawdzeniem zmiennej
nie ma żadnych rekordów w zestawie bądź stąpi opuszczenie pętli. Wartość zmiennej SQLSTATE nie można umieszczać żadnych
wystąpi błąd dostępu do danych, to po SQLSTATE tak naprawdę oznacza stan po- innych instrukcji, ponieważ wpłyną one
wywołaniu instrukcji FETCH w wierszu {4} prawności wykonania dowolnej instrukcji na wartość SQLSTATE. Dla formalności do-
zmienna SQLSTATE miałaby wartość róż- SQL, gdzie ciąg znaków o wartości ‘00000' dam, że wewnątrz pętli, w wierszu {6}, ob-
ną od ‘00000' i pętla nie wykonałaby się oznacza poprawne wykonanie się danej in- liczam wartość każdego produktu i dodaję
ani razu. Z kolei jeśli kursor jest ustawio- strukcji. Wartość tej zmiennej powinna do parametru p _ value, który zwraca su-
maryczną wartość wszystkich produktów.
Listing 19. Otrzymywanie zbioru wynikowego z kursora Po wyjściu z pętli w wierszu {8} zamykam
kursor poleceniem CLOSE. Dobrą praktyką
-- p18.sql jest zamykanie kursorów, gdy nie są już po-
CREATE PROCEDURE quad_amounts() trzebne, ale nawet jeśli tego nie zrobisz, to
SPECIFIC p18 DB2 zamknie za Ciebie wszystkie otwarte
LANGUAGE SQL wewnątrz procedury kursory tuż przed jej
DYNAMIC RESULT SETS 1 zakończeniem. W powyższym przykładzie
BEGIN pokazałem, jak wykorzystać kursor do od-
DECLARE v_name CHAR(12); czytu danych po kolei ze wszystkich rekor-
DECLARE v_amount INTEGER; dów i jak je wykorzystać do dalszych obli-
DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; czeń. W następnym przykładzie przedsta-
DECLARE rs_amounts RESULT_SET_LOCATOR VARYING; --{1} wię, jak za pomocą kursora możesz mody-
CALL double_amounts(); --{2} fikować i usuwać poszczególne rekordy.
ASSOCIATE RESULT SET LOCATOR (rs_amounts) --{3}
WITH PROCEDURE double_amounts; Kursory – FOR UPDATE
ALLOCATE c_amounts CURSOR FOR --{4} W procedurach składowanych dane najczę-
RESULT SET rs_amounts; ściej są modyfikowane za pomocą instruk-
FETCH FROM c_amounts INTO v_name, v_amount; cji UPDATE lub DELETE. W tych przypadkach
WHILE (SQLSTATE = '00000') DO operacje są wykonywane jednocześnie na
UPDATE stock SET amount = v_amount * 2 --{5} wszystkich rekordach spełniających waru-
WHERE name = v_name; nek podany w klauzuli WHERE. Stosując kur-
FETCH FROM c_amounts INTO v_name, v_amount; sory, możesz selektywnie wykonywać ope-
END WHILE; racje modyfikacji lub usuwania danych w
CLOSE c_amounts; --{6} zależności od wyniku bardziej złożonych
BEGIN --{7} obliczeń, niż te, które są dostępne w klau-
DECLARE c_amounts CURSOR WITH RETURN FOR zuli WHERE. Na Listingu 16 przedstawiłem
SELECT name, amount FROM stock; procedurę, która przy użyciu kursora usu-
OPEN c_amounts; wa rekord lub go modyfikuje w zależności
END; od tego, czy spełniony jest określony waru-
END nek. Aby modyfikacja danych za pomocą
@ kursora była możliwa, w wierszu {1} zade-
klarowałem kursor z klauzulą FOR UPDATE.
W wierszu {2} sprawdzam warunek, czy
Listing 20. Sprawdzanie kodu błędu za pomocą zmiennych SQLSTATE I SQLCODE ilość towaru podana w parametrze p_
amount przekracza ilość towaru z bieżące-
-- p19.sql go rekordu zapisaną w zmiennej v_amount.
CREATE PROCEDURE update_price( Jeśli tak, to w wierszu {3} usuwam cały re-
IN p_name VARCHAR(12), kord. W przeciwnym przypadku w wierszu
IN p_price DECFLOAT, {4} zmniejszam ilość dostępnego towaru,
OUT p_state CHAR(5), modyfikując bieżący rekord. Operacje usu-
OUT p_code INTEGER wania i modyfikacji są zawsze wykonywane
) na rekordzie, na którym jest aktualnie usta-
SPECIFIC p19 wiony kursor. Zwróć uwagę, że w klauzuli
LANGUAGE SQL WHERE w wierszach {3} i {4} występuje klau-
BEGIN zula CURRENT OF z nazwą kursora, które-
DECLARE SQLSTATE CHAR(5) DEFAULT '99999'; --{1} go dotyczy operacja. Operację modyfikacji
DECLARE SQLCODE INTEGER DEFAULT 99999; --{2} wykonuję w pętli dla wszystkich rekordów,
UPDATE stock SET price = p_price --{3} co możemy zinterpretować jako sprzedanie
WHERE name = p_name; wszystkich towarów w ilości mniejszej lub
VALUES (SQLSTATE,SQLCODE) INTO p_state, p_code; --{4} równej tej, którą podajemy w parametrze
END wejściowym procedury. Wypróbujmy za-
@ tem tę procedurę w praktyce. Zapisz treść
procedury z Listingu 16 do pliku p015.sql
i skompiluj poleceniem:

24 SDJ Extra 35
Procedury składowane w DB2 9

db2 -td@ -vf p15.sql zasobów z nim związanych. Jeśli kursor ma i sprawdź zawartość tabeli stock polece-
klauzulę WITH HOLD, to po operacji COMMIT niem:
Przygotuj dane początkowe, wywołując pro- możesz wywołać jedynie polecenia FETCH
cedurę clean: lub CLOSE. Usuwanie lub modyfikowanie db2 select name,amount from stock
rekordu z użyciem kursora nie jest w ta- NAME AMOUNT
db2 call clean() kim przypadku dozwolone, ponieważ po ------------ -----------
zatwierdzeniu transakcji wskaźnik kursora orange 10
Po jej wykonaniu na magazynie powinno być będzie ustawiony przed następnym rekor- lemon 30
sześć produktów, co sprawdzisz zapytaniem: dem, ale nie będzie już wskazywał na po- lime 60
przednio przetwarzany rekord. Sprawdź- grapes 90
db2 select name,amount from stock my w praktyce, jak działa klauzula WITH apple 120
NAME AMOUNT HOLD. Zapisz procedurę z Listingu 17 do banana 150
------------ ----------- pliku p16.sql i skompiluj poleceniem:
orange 10 Teraz uruchom procedurę hold _ test, wy-
lemon 30 db2 -td@ -vf p16.sql dając polecenie:
lime 60
grapes 90 Następnie przygotuj początkowe dane wy- db2 call hold_test()
apple 120 wołaniem:
banana 150 W wyniku działania tej procedury DB2 zgło-
db2 call clean() si błąd, do którego za moment wrócę, a tym-
Teraz wywołaj procedurę sell _ bundle z
wartością 70: Listing 21. Prosta obsługa błędu

db2 call sell_bundle(70) -- p20.sql


CREATE PROCEDURE update_price(
i sprawdź stan magazynowy: IN p_name VARCHAR(12),
IN p_price DECFLOAT,
db2 select name,amount from stock OUT p_result INTEGER
NAME AMOUNT )
------------ ----------- SPECIFIC p20
grapes 20 LANGUAGE SQL
apple 50 BEGIN
banana 80 DECLARE EXIT HANDLER FOR NOT FOUND --{1}
SET p_result = -1;
Procedura zadziałała zgodnie z oczekiwania- UPDATE stock SET price = p_price --{2}
mi. Produkty, których ilość była mniejsza, WHERE name = p_name;
niż 70, zostały usunięte, natomiast w pozo- SET p_result = 0; --{3}
stałych przypadkach ilość produktu została END
pomniejszona o 70. @

Kursory – WITH HOLD


Wewnątrz procedury składowanej mo- Listing 22. Handler i instrukcja RETURN
żesz używać poleceń COMMIT/ROLLBACK do
„ręcznego” sterowania transakcjami. Jeśli -- p21.sql
wraz z tymi poleceniami używasz kurso- CREATE PROCEDURE update_price(
rów, to musisz zwrócić uwagę na to, że za- IN p_name VARCHAR(12),
chowanie kursora będzie różne w zależno- IN p_price DECFLOAT
ści od tego, czy kursor został zadeklarowa- )
ny z klauzulą WITH HOLD, czy też nie. Kur- SPECIFIC p21
sor zadeklarowany bez klauzuli WITH HOLD LANGUAGE SQL
zostanie zamknięty po każdym wywołaniu BEGIN
COMMIT lub ROLLBACK, a wszystkie związa- DECLARE v_result INTEGER DEFAULT 0; --{1}
ne z nim zasoby zostaną zwolnione. Mo- BEGIN
że to być trochę uciążliwe, ponieważ po DECLARE EXIT HANDLER FOR NOT FOUND --{2}
każdym poleceniu COMMIT musiałbyś po- SET v_result = -1;
nownie otwierać kursor i przesuwać się do UPDATE stock SET price = p_price --{3}
określonego rekordu, by wykonać na nim WHERE name = p_name;
kolejne operacje. W tej sytuacji pomocna END;
jest klauzula WITH HOLD. Kursor zadekla- RETURN v_result; --{4}
rowany z klauzulą WITH HOLD po wywoła- END
niu COMMIT pozostanie otwarty i nadal bę- @
dzie wskazywał na bieżący rekord, nato-
miast wywołanie ROLLBACK spowoduje za-
mknięcie kursora i zwolnienie wszystkich

www.sdjournal.org 25
Tworzenie aplikacji

czasem sprawdź, jak zmieniła się zawartość db2 select name,amount from stock ------------ -----------
tabeli, wołając ponownie: NAME AMOUNT orange 1010
lemon 2030
Listing 23. Obsługa specyficznego kodu błędu lime 60
grapes 90
-- p22.sql apple 120
CREATE PROCEDURE add_product( banana 150
IN p_name VARCHAR(12),
IN p_amount INTEGER, Wielkości stanów magazynowych dwóch
IN p_price DECFLOAT pierwszych produktów powiększyły się
) odpowiednio o 1000 i 2000. Prześledź-
SPECIFIC p22 my teraz, dlaczego tak się stało i dlacze-
LANGUAGE SQL go serwer DB2 zgłosił błąd. Przeanalizuj-
BEGIN my treść procedury z Listingu 17. W wier-
DECLARE v_result INTEGER DEFAULT 0; szu {1} zadeklarowałem kursor z klauzu-
DECLARE cnd_upd CONDITION FOR SQLSTATE '23505'; --{1} lą WITH HOLD. Następnie, po jego otwarciu,
BEGIN wywołałem instrukcję FETCH. Kursor usta-
DECLARE CONTINUE HANDLER FOR cnd_upd --{2} wił się na pierwszym rekordzie i pobrał
UPDATE stock ilość towaru do zmiennej v _ amount. W
SET amount = p_amount, price = p_price następnym kroku dodałem 1000 do aktu-
WHERE name = p_name; alnej ilości towaru i w wierszu {3} zatwier-
INSERT INTO stock(name, amount, price) --{3} dziłem zmianę poleceniem COMMIT. Ponie-
VALUES (p_name, p_amount, p_price); waż kursor ma klauzulę WITH HOLD, dlate-
SELECT id INTO v_result FROM stock --{4} go nie został zamknięty i wymienione wy-
WHERE name = p_name; żej czynności mogłem powtórzyć, by w
END; wierszu {4} zatwierdzić powiększenie ilo-
RETURN v_result; --{5} ści drugiego towaru o 2000. Po tej ope-
END racji wykonuję aktualizację ilości trzecie-
@ go towaru o 3000, ale w wierszu {5} wy-
wołuję ROLLBACK . To powoduje cofnięcie
zmiany dokonanej na trzecim rekordzie i
Listing 24. Zaawansowana obsługa błędów zamknięcie kursora. W efekcie, wykona-
nie instrukcji FETCH w wierszu {6} koń-
-- p23.sql czy się niepowodzeniem, ponieważ kur-
CREATE PROCEDURE delete_product( sor jest już zamknięty, a DB2 zgłasza na-
IN p_name VARCHAR(12), stępujący błąd:
OUT p_message VARCHAR(200)
) SQL0501N Kursor określony w instrukcji
SPECIFIC p23 FETCH lub CLOSE nie jest otwarty.
LANGUAGE SQL SQLSTATE=24501
BEGIN
DECLARE v_amount INTEGER DEFAULT NULL; W tej procedurze celowo nie zamykam
DECLARE cnd_err CONDITION FOR SQLSTATE '99001'; --{1} kursora, ponieważ robi to instrukcja
DECLARE EXIT HANDLER FOR cnd_err --{2} ROLLBACK . Jako ćwiczenie proponuję, abyś
GET DIAGNOSTICS EXCEPTION 1 usunął klauzulę WITH HOLD z deklaracji
p_message = DB2_TOKEN_STRING; kursora, ponownie skompilował procedu-
SET v_amount = rę i powtórzył cały scenariusz. Ile rekor-
(SELECT amount FROM stock dów zostanie zmodyfikowanych? Oczy-
WHERE name = p_name); wiście, tylko pierwszy. Pierwsze wywo-
IF (v_amount IS NULL) THEN łanie COMMIT, zgodnie z naszymi oczeki-
SIGNAL cnd_err --{3} waniami, zamknie kursor i następująca
SET MESSAGE_TEXT = 'Product not found'; po nim operacja FETCH zakończy się błę-
ELSEIF (v_amount > 0) THEN dem. Zastosowanie klauzuli WITH HOLD
SIGNAL cnd_err --{4} może być szczególnie użyteczne w pro-
SET MESSAGE_TEXT = 'Product amount > 0'; cesach wsadowych, gdzie dane są pobie-
ELSE rane za pomocą kursora, potem przetwa-
DELETE FROM stock WHERE name = p_name; rzane rekord po rekordzie, a każdy rekord
SET p_message = 'Deleted'; jest przetwarzany w ramach jednej trans-
END IF; akcji. Na koniec jeszcze jedna ciekawost-
END ka. W wierszu {2} procedury, w klauzu-
@ li FOR UPDATE OF podałem nazwę kolum-
ny amount. W ten sposób zadeklarowałem
chęć zmiany za pomocą kursora tylko jed-
nej, konkretnej kolumny. Gdybym w ko-

26 SDJ Extra 35
Procedury składowane w DB2 9

dzie procedury w którejkolwiek instruk- NAME AMOUNT ny do procedury lub programu wywołują-
cji UPDATE opartej na kursorze próbował ------------ ----------- cego, natomiast TO CLIENT oznacza, że zo-
zmodyfikować inną kolumnę niż amount, orange 20 stanie on zwrócony do nadrzędnego pro-
to otrzymałbym błąd już na etapie kompi- lemon 60 gramu wywołującego. Jeśli użyjesz klauzu-
lacji procedury. Stosując takie rozwiąza- lime 120 li WITH RETURN TO CLIENT i wywołasz proce-
nie, możesz się zabezpieczyć przed przy- grapes 180 durę z innej procedury, to procedura wy-
padkową modyfikacją kolumn. apple 240 wołująca nie zobaczy zwracanego wyniku,
banana 300 zostanie on przekazany bezpośrednio do
Kursory – WITH RETURN programu wywołującego.
Do tej pory wykorzystywaliśmy kursor do Chciałbym jeszcze zwrócić uwagę na to, że
odczytu i modyfikacji danych. Za pomocą klauzula WITH RETURN może wystąpić z do- Kursory – odbieranie
kursora możesz również przekazać określo- datkowym modyfikatorem TO CALLER lub zbioru wynikowego
ny zestaw rekordów do procedury lub pro- TO CLIENT. TO CALLER oznacza, że zbiór wy- Wiemy już, jak przekazywać zestaw da-
gramu wywołującego. Aby zobaczyć, jak to nikowy oparty na kursorze będzie zwróco- nych do procedury wywołującej. W kolej-
zrobić, przyjrzyjmy się procedurze z Listin-
gu 18. W wierszu {3} zadeklarowałem kur- Listing 25. Użycie GET DIAGNOSTICS
sor z klauzulą WITH RETURN, co powodu-
je, że otwierany w wierszu {4} kursor nie -- p24.sql
jest zamykany tuż przed wyjściem z pro- CREATE PROCEDURE update_promo(
cedury, tylko pozostaje aktywny i dostęp- IN p_name VARCHAR(12),
ny w procedurze lub programie wywołują- IN p_promo SMALLINT,
cym. Dodatkowo w wierszu {1} za pomocą OUT p_msg VARCHAR(300),
instrukcji DYNAMIC RESULT SETS zadeklaro- OUT p_count INTEGER,
wałem, że procedura zwraca jeden zestaw OUT p_amount INTEGER
danych. W ten sposób program wywołują- )
cy, na przykład procesor poleceń db2, otrzy- SPECIFIC p24
muje zestaw danych, który wyświetla na LANGUAGE SQL
konsoli. W podobny sposób jak na Listin- BEGIN
gu 18 możesz do programu lub procedu- DECLARE v_value DECFLOAT;
ry wywołującej przekazać większą ilość ze- DECLARE EXIT HANDLER FOR NOT FOUND
stawów danych. Chciałbym przy tej okazji GET DIAGNOSTICS EXCEPTION 1 --{1}
zwrócić uwagę na fakt, że deklaracja kur- p_msg = MESSAGE_TEXT; --{2}
sora musi wystąpić po deklaracjach zmien- UPDATE stock SET promo = p_promo
nych (o czym już wspominałem) oraz przed WHERE name LIKE p_name;
instrukcjami SELECT, UPDATE, DELETE oraz GET DIAGNOSTICS p_count = ROW_COUNT; --{3}
CREATE TABLE. Sposób, w jaki można sobie SELECT SUM(amount) INTO v_value FROM stock
poradzić z tym ograniczeniem, pokazałem WHERE name LIKE p_name;
również na Listingu 18. Deklarację kurso- CALL calc_value(v_value,1.0,v_value,v_value);
ra można umieścić w bloku BEGIN/END i w GET DIAGNOSTICS p_amount = RETURN_STATUS; --{4}
ten sposób może się ona znaleźć na końcu END
procedury, po innych instrukcjach SQL- @
owych. Wykorzystałem to rozwiązanie do
napisania procedury, która najpierw po- Listing 26. Dynamiczny SQL – EXECUTE IMMEDIATE
dwaja ilość wszystkich towarów, a następ-
nie za pomocą kursora zwraca nazwę i po- -- p25.sql
dwojoną ilość towaru do procedury wywo- CREATE PROCEDURE change_price(
łującej. Procedurę z Listingu 18 możesz IN p_value DECFLOAT,
skompilować poleceniem: IN p_condition VARCHAR(800),
OUT p_count INTEGER
db2 -td@ -vf p17.sql )
SPECIFIC p25
Ustaw początkowe dane wywołaniem: LANGUAGE SQL
BEGIN
db2 call clean() DECLARE v_sql VARCHAR(1000);
SET v_sql = 'UPDATE stock SET price = price + (' --{1}
i wywołaj kilkakrotnie procedurę double _ || CHAR(p_value)
amounts: || ') WHERE '
|| p_condition;
db2 call double_amounts() EXECUTE IMMEDIATE v_sql; --{2}
GET DIAGNOSTICS p_count = ROW_COUNT; --{3}
Za każdym razem ilość towarów jest po- END
dwajana i wyświetlana na konsoli. Po pierw- @
szym wywołaniu powinieneś uzyskać wynik
przedstawiony w tabelce poniżej:

www.sdjournal.org 27
Tworzenie aplikacji

nym przykładzie pokażę, jak w procedu- durę double_amounts. Aby wykorzystać RESULT SET LOCATOR. Następnie trzeba za-
rze wywołującej odebrać zestaw danych. zestaw danych przekazany z procedury alokować kursor poleceniem ALLOCATE
W tym celu przygotowałem procedurę wywoływanej, trzeba wykonać dwie czyn- CURSOR. Spójrzmy na przykład z Listingu
quad_amounts przedstawioną na Listin- ności. Najpierw należy powiązać tak zwa- 19. W wierszu {1} zadeklarowałem zmien-
gu 19, która zwiększa ilość towaru czte- ny lokator (wskaźnik) z procedurą wywo- ną będącą lokatorem zestawu danych o na-
rokrotnie i wykorzystuje do tego celu po- ływaną i zwracanym przez nią zestawem zwie rs_amounts. Następnie w wierszu {2}
dwojone wartości zwrócone przez proce- danych za pomocą instrukcji ASSOCIATE wywołuję metodę double_amounts, która
zwraca jeden zestaw danych. Dopiero po
Listing 27. Dynamiczny SQL – PREPARE/EXECUTE wywołaniu tej metody, w wierszu {3} mogę
powiązać lokator rs_amounts z zestawem
-- p26.sql danych zwróconym przez tę procedurę. W
CREATE PROCEDURE add( wierszu {4} alokuję kursor c_amounts, któ-
IN p_names NAME_ARRAY, ry będzie oparty na lokatorze rs_amounts,
IN p_amounts AMOUNT_ARRAY, czyli będzie wskazywał zestaw danych
IN p_prices PRICE_ARRAY zwrócony przez double_amounts. Tak za-
) alokowany kursor wykorzystuję do dal-
SPECIFIC p26 szych obliczeń w podobny sposób jak kur-
LANGUAGE SQL sor zadeklarowany jawnie. Przed użyciem
BEGIN zaalokowany kursor nie musi być otwiera-
DECLARE v_name VARCHAR(30); ny instrukcją OPEN. Do zwiększenia ilości
DECLARE v_amount INTEGER; produktu wykorzystuję pętlę WHILE i po-
DECLARE v_price DECIMAL(8,2); lecenie FETCH do iterowania po wszystkich
DECLARE n,i INTEGER; rekordach, a do modyfikacji wykorzystu-
DECLARE v_sql VARCHAR(1000); ję w wierszu {5} instrukcję UPDATE. Zwróć
DECLARE v_stmt STATEMENT; --{1} uwagę, że w klauzuli WHERE nie można wy-
SET v_sql = 'INSERT INTO stock (name,amount,price) korzystywać kursora utworzonego instruk-
VALUES (?,?,?)'; --{2} cją ALLOCATE CURSOR, dlatego jawnie musia-
PREPARE v_stmt FROM v_sql; --{3} łem podać warunek wyszukiwania towaru
SET n = CARDINALITY(p_names); po nazwie. W wierszu {6} zamykam kur-
SET i = 1; sor poleceniem CLOSE, co powoduje zwol-
WHILE (i <= n) DO nienie wszystkich zasobów i zamknięcie
VALUES (p_names[i],p_amounts[i],p_prices[i]) --{4} zestawu danych zwróconego przez me-
INTO v_name,v_amount,v_price; todę double_amounts. W wierszu {7} za-
EXECUTE v_stmt USING v_name,v_amount,v_price; --{5} stosowałem trik z deklarowaniem kursora
SET i = i + 1; na końcu procedury w bloku BEGIN..END,
END WHILE; aby zwrócić zmodyfikowaną listę towa-
END rów. Sprawdźmy zatem procedurę quad_
@ amounts w działaniu. W tym celu skompi-
luj ją poleceniem:
Listing 28. Dynamiczne kursory
db2 -td@ -vf p18.sql
-- p27.sql
CREATE PROCEDURE list( Następnie wyczyść tabelę testową, wołając:
IN p_columns VARCHAR(200),
IN p_condition VARCHAR(800) db2 call clean()
)
SPECIFIC p27 i wywołaj kilkakrotnie procedurę quad _
DYNAMIC RESULT SETS 1 amounts:
LANGUAGE SQL
BEGIN > db2 call quad_amounts()
DECLARE v_sql VARCHAR(1000);
DECLARE v_stmt STATEMENT; --{1} Po pierwszym wywołaniu, ilości towarów
DECLARE c_stock CURSOR WITH RETURN FOR v_stmt; --{2} powinny być takie jak w tabeli poniżej, no
SET v_sql = 'SELECT ' --{3} i oczywiście po każdym kolejnym powinny
|| p_columns zwiększać się czterokrotnie.
|| ' FROM stock WHERE '
|| p_condition; NAME AMOUNT
PREPARE v_stmt FROM v_sql; --{4} ------------ -----------
OPEN c_stock; --{5} orange 40
END lemon 120
@ lime 240
grapes 360
apple 480
banana 600

28 SDJ Extra 35
Procedury składowane w DB2 9

Może wydawać się, że zamiast przekazy- • 100 – pojawiło się ostrzeżenie typu dana została nazwa produktu, którego
wania zbiorów wynikowych lepiej jest od NOT FOUND; nie ma w tabeli stock. W takim przypad-
razu całość pracy wykonać w nadrzędnej • <0 – wystąpił inny błąd. ku instrukcja UPDATE zwróci kody błędów
procedurze. Warto jednak zwrócić uwa- w zmiennych SQLSTATE i SQLCODE , któ-
gę, że procedury mogą być uruchamia- Dla przykładu, jeśli spróbujesz instrukcją re odczytuję w wierszu {4}, zapisując je
ne z różnymi poziomami uprawnień. Bar- UPDATE zmodyfikować rekord, który nie ist- do parametrów wyjściowych p _ state i
dzo często odbiera się użytkownikom bez- nieje, to otrzymasz komunikat: p _ code. Zauważ, że zmienne SQLSTATE
pośredni dostęp do tabel, natomiast udo- i SQLCODE wcześniej zadeklarowałem w
stępnia się prawo wykonywania procedur SQL0100W Nie znaleziono wiersza dla wierszach {1} i {2} i celowo nadałem im
i odbierania zwracanych przez nich zbio- FETCH, UPDATE lub DELETE albo wartości odpowiednio ‘99999' oraz 99999,
rów wynikowych. Zbiory wynikowe mo- rezultatem zapytania jest pusta aby pokazać, że obie zmienne są modyfi-
gą być także odebrane przez aplikację na- tabela. SQLSTATE=02000 kowane przez DB2 zarówno po popraw-
pisaną w innym języku programowania, nym, jak i błędnym wykonaniu instruk-
np. w Java czy C. Dodatkowo zbiór wyni- Wykorzystując procesor poleceń, możesz do- cji UPDATE . Czas sprawdzić działanie tej
kowy może być zbudowany w oparciu o ta- wiedzieć się więcej o kodzie błędu, wywołu- procedury w praktyce. Zapisz procedurę
belę tymczasową, której zawartość może jąc dla SQLCODE polecenie: z Listingu 20 do pliku p19.sql i skompi-
zostać utworzona na podstawie wielu in- luj poleceniem:
nych tabel. db2 ? SQL0100W
db2 -td@ -vf p19.sql
Podstawowa obsługa błędów a dla SQLSTATE polecenie:
Podczas tworzenia i uruchamiania procedur Ustaw dane początkowe w tabeli stock po-
składowanych z pewnością spotkasz się z sy- db2 ? 02000 leceniem:
tuacją, kiedy jedna z instrukcji SQL-owych z
jakiegoś powodu nie wykona się poprawnie, Na Listingu 20 przedstawiłem procedu- db2 call clean()
a wtedy Twoja procedura zostanie przerwa- rę, w której zachodzi taki przypadek. Mo-
na i zakończy swoje działanie. DB2 dostar- że się zdarzyć, że w wierszu {3} będzie Następnie uruchom procedurę, wywołując:
cza kilka mechanizmów pomocnych w ob- modyfikowany rekord, który nie istnie-
słudze takich sytuacji, dzięki czemu możesz je, ponieważ w parametrze p _ name po- db2 call update_price('orange',80.0,?,?)
na nie odpowiednio zareagować. Na kolej-
Ramka 1. Przekazywanie i odbieranie parametrów w procedurach dynamicznych
nych przykładach pokażę, jak sprawdzić, czy
instrukcja SQL-owa wykonała się popraw- USING v_row.amount v_row.price p_out
nie i jak poradzić sobie z ewentualnymi błę-   
dami. Serwer DB2 po wykonaniu każdej in- parametr p_amount p_price p_value p_total
strukcji SQL-owej, ustawia dwie zmienne o
typ IN IN OUT INOUT
nazwach SQLSTATE i SQLCODE. Możesz je wy-
korzystać do sprawdzenia, czy określona in-  
strukcja wykonała się poprawnie. Zmienna INTO v_value p_out
SQLSTATE przechowuje pięcioznakowy kod
zgodny z ISO/ANSI SQL92, którego warto-
ści mają następujące znaczenie: Listing 29. Dynamiczne wywoływanie procedur

• ‘00xxx' instrukcja wykonała się popraw- -- p28.sql


nie; CREATE PROCEDURE calculate_totals(
• ‘01xxx' podczas wykonania pojawiło się OUT p_out DECFLOAT
ostrzeżenie; )
• ‘02xxx' podczas wykonania wystąpił SPECIFIC p28
błąd. LANGUAGE SQL
BEGIN
Znaczenie wartości zmiennej SQLSTATE DECLARE v_value DECFLOAT;
jest takie samo dla całej rodziny produk- DECLARE v_sql VARCHAR(80);
tów DB2, jak i baz danych innych produ- DECLARE v_stmt STATEMENT; --{1}
centów, ale dostarcza dość ogólnych in- SET v_sql = 'CALL calc_value(?,?,?,?)'; --{2}
formacji na temat sytuacji wyjątkowych. PREPARE v_stmt FROM v_sql; --{3}
Bardziej szczegółowe informacje moż- SET p_out = 0.0;
na uzyskać, analizując wartości zmiennej FOR v_row AS SELECT amount,price FROM stock
SQLCODE , która zwraca kod błędu w posta- DO
ci liczby całkowitej. Znaczenie SQLCODE EXECUTE v_stmt --{4}
jest specyficzne dla serwera DB2 i może INTO v_value,p_out --{5}
się różnić pomiędzy poszczególnymi wer- USING v_row.amount,v_row.price,p_out; --{6}
sjami. Ogólnie znaczenie SQLCODE jest na- END FOR;
stępujące: END
@
• 0 – poprawne wykonanie instrukcji;
• >0 – pojawiło się ostrzeżenie;

www.sdjournal.org 29
Tworzenie aplikacji

Procedura powinna zwrócić komunikat: ny z klauzulą ATOMIC. Handlery definiuje a zamiast niej wywołany został handler w
się dla określonych typów zdarzeń. Istnie- wierszu {1}. Do tej pory komunikaty błę-
Wartości parametrów wyjściowych ją trzy predefiniowane ogólne typy zda- dów przekazywaliśmy do programu wy-
-------------------------- rzeń, są to: SQLEXCEPTION, SQLWARNING i wołującego za pomocą parametrów wyj-
Nazwa parametru: P_STATE NOT FOUND. Handler może być również za- ściowych. Status wykonania danej opera-
Wartość parametru: 00000 deklarowany dla konkretnego typu zda- cji możemy przekazać także za pomocą in-
Nazwa parametru: P_CODE rzenia o podanym kodzie SQLSTATE . Prze- strukcji RETURN. Kłopot jednak polega na
Wartość parametru: 0 śledźmy prosty przykład użycia handlera tym, że w handlerze nie można użyć po-
typu EXIT dla zdarzenia typu NOT FOUND, lecenia RETURN (dotyczy wersji DB2 9.5 i
Instrukcja UPDATE zakończyła się popraw- który został przedstawiony na Listingu wcześniejszych; od wersji DB2 9.7 można
nie i cena jednostkowa pomarańczy zosta- 21. Jeśli w parametrze p _ name do proce- już korzystać z instrukcji RETURN w han-
ła zmieniona na wartość 80.0, co możesz dury zostanie przekazana nazwa nieist- dlerze). Aby obejść to ograniczenie, mu-
sprawdzić poleceniem: niejącego produktu, to instrukcja UPDATE simy zadeklarować handler w bloku za-
w wierszu {2} zgłosi ostrzeżenie o kodzie gnieżdżonym BEGIN..END, tak jak to po-
db2 select * from stock +100, czyli NOT FOUND. Ponieważ w proce- kazałem na Listingu 22. Jest to procedu-
durze w wierszu {1} jest zadeklarowany ra z poprzedniego przykładu, ale rezultat
Ponownie uruchom procedurę update _ handler dla zdarzenia NOT FOUND, to ste- wykonania przechowywany jest w zmien-
price, ale tym razem podaj nazwę produktu, rowanie zostanie przekazane do tego han- nej lokalnej zadeklarowanej w wierszu {1}
którego nie ma na magazynie, na przykład: dlera. W handlerze jest zdefiniowana tyl- z wartością domyślną 0. Jeśli w instruk-
ko jedna instrukcja, zostanie ona wykona- cji UPDATE w wierszu {3} wystąpi błąd NOT
db2 call update_price('melon',80.0,?,?) na i nastąpi zakończenie działania proce- FOUND, to sterowanie zostanie przekazane
dury. Tyle teorii, teraz sprawdźmy proce- do handlera w wierszu {2}, zmiennej v _
Wynik działania procedury powinien być durę w działaniu. Zapisz kod procedury result zostanie przypisana wartość -1, a
następujący: z Listingu 21 do pliku o nazwie p20.sql i ponieważ handler jest typu EXIT, to na-
skompiluj ją poleceniem: stępną wykonywaną instrukcją będzie po-
Wartości parametrów wyjściowych lecenie w wierszu {4}. Sprawdźmy działa-
-------------------------- db2 -td@ -vf p20.sql nie tej procedury. Zapisz kod procedury z
Nazwa parametru: P_STATE Listingu 22 do pliku p21.sql i skompiluj
Wartość parametru: 02000 Ustaw dane początkowe wywołaniem: poleceniem:
Nazwa parametru: P_CODE
Wartość parametru: 100 db2 call clean() db2 -td@ -vf p21.sql

Instrukcja UPDATE spowodowała ustawie- a następnie uruchom: Ustaw dane początkowe, wołając:
nie odpowiednio 02000 dla SQLSTATE i
+100 dla SQLCODE , co oznacza, że rekord db2 call update_price('lemon',25.0,?) db2 call clean()
nie został znaleziony. Przedstawiony spo-
sób sprawdzania błędu wykonania, jak- Procedura powinna zwrócić komunikat: a następnie uruchom procedurę, wywołując:
kolwiek poprawny, może być nieprak-
tyczny, jeśli procedura będzie nieco bar- Wartości parametrów wyjściowych db2 call update_price('lemon',25.0)
dziej skomplikowana, a instrukcji SQL- --------------------------
owych będzie kilkadziesiąt. Dlatego też Nazwa parametru: P_RESULT Procedura powinna zwrócić komunikat:
w DB2 dostępny jest mechanizm obsłu- Wartość parametru: 0
gi błędów i wyjątków za pomocą tak zwa- Status powrotu= 0
nych handlerów. Handler jest to wyraże- a cena cytryn powinna zostać zmieniona na
nie SQL-owe, które zostanie wywołane wartość 25.0. Wywołaj jeszcze raz tę proce- Cena cytryn zostanie ustawiona na wartość
w przypadku wystąpienia błędu lub wy- durę, ale podaj nazwę nieistniejącego pro- 25.0, a procedura zwróci wartość 0. Uru-
jątku. Handlery mogą być deklarowane w duktu: chom tę procedurę jeszcze raz z nazwą pro-
obrębie instrukcji blokowej i taki jest ich duktu, którego nie ma w tabeli stock, na
zakres działania. Handlery są trzech ty- db2 call update_price('melon',25.0,?) przykład:
pów: EXIT, CONTINUE i UNDO. W handle-
rze typu EXIT wykonane zostaną wszyst- Cena żadnego towaru nie uległa zmianie, na- db2 call update_price('melon',25.0)
kie jego instrukcje i nastąpi wyjście z blo- tomiast procedura zwróciła komunikat:
ku, w którym został zadeklarowany, a jeśli W wyniku pojawienia się błędu NOT FOUND
taki handler jest zadeklarowany dla pro- Wartości parametrów wyjściowych procedura jako rezultat zwróci wartość -1.
cedury (w nadrzędnym bloku), to nastą- -------------------------- W pracy przy systemach rejestracyjnych
pi wyjście z całej procedury. Handler ty- Nazwa parametru: P_RESULT często spotykamy się z sytuacją, kiedy chce-
pu CONTINUE wykona wszystkie swoje in- Wartość parametru: -1 my dodać nowy rekord, ale okazuje się, że
strukcje i powróci do instrukcji znajdują- rekord o podanym kluczu już istnieje i wte-
cej się zaraz po poleceniu, które spowo- Zauważ, że rezultat wykonania procedu- dy chcielibyśmy ten rekord tylko zaktuali-
dowało błąd lub wyjątek. Handler typu ry jest przekazywany w parametrze wyj- zować. Na Listingu 23 przedstawiłem pro-
UNDO działa podobnie jak EXIT, z tym że ściowym p _ result i o ile w poprzednim cedurę, która do rozwiązania tego proble-
wszystkie instrukcje, które się poprawnie wywołaniu miał wartość 0, teraz ma war- mu wykorzystuje handler typu CONTINUE
wykonały w danym bloku, zostaną wyco- tość -1. Oznacza to, że w przypadku błędu dla specyficznego kodu błędu SQLSTATE o
fane, ale blok ten musi być zadeklarowa- instrukcja w wierszu {3} nie wykonała się, wartości ‘23505' (naruszenie więzów inte-

30 SDJ Extra 35
Procedury składowane w DB2 9

gralności). Jeśli do procedury add_product db2 call add_product('melon',100,8.39) Wartości parametrów wyjściowych
przekazana zostanie nazwa nowego pro- --------------------------
duktu, to zostanie on dodany do tabeli Procedura nie dodała nowego rekordu, tylko Nazwa parametru: P_MESSAGE
wraz z ilością i ceną. Jeśli jednak podana zmodyfikowała cenę jednostkową produktu, Wartość parametru: Product amount > 0
nazwa produktu już istnieje w tabeli stock, który już istnieje w tabeli, zwracając identy-
to w wierszu {3} instrukcja INSERT zakoń- fikator modyfikowanego rekordu. Ponownie wywołaj tę procedurę dla produk-
czy się błędem o kodzie ‘23505' i sterowa- tu, którego ilość na magazynie jest zerowa:
nie zostanie przekazane do handlera zade- Zaawansowana obsługa błędów
klarowanego w wierszu {1}. W kodzie han- W poprzednich przykładach używałem db2 call delete_product('orange',?)
dlera znajduje się instrukcja UPDATE, któ- handlerów dla predefiniowanych kodów
ra zaktualizuje ilość i cenę dla już istnie- błędów, a ich wywoływanie odbywało się Produkt zostanie usunięty z tabeli stock, a
jącego produktu. Ponieważ jest to handler automatycznie po wystąpieniu określonego procedura zwróci komunikat z informacją o
typu CONTINUE, to sterowanie powróci do błędu. W SQL PL istnieje możliwość defi- jego usunięciu:
wiersza {4}, w którym do zmiennej lokal- niowania własnych kodów błędów i „ręczne-
nej jest pobierany identyfikator modyfiko- go” wywołania określonego handlera. Wła- Wartości parametrów wyjściowych
wanego produktu. W wierszu {5} identyfi- sne kody błędów deklaruje się za pomocą in- --------------------------
kator produktu jest zwracany jako rezultat strukcji DECLARE CONDITION, natomiast wy- Nazwa parametru: P_MESSAGE
wykonania procedury. Przykład z Listingu wołanie określonego handlera można wy- Wartość parametru: Deleted
23 pokazuje, jak wykorzystać handler ty- musić poleceniem SIGNAL. Na Listingu 24
pu CONTINUE i jak zadeklarować handler dla przedstawiłem procedurę, w której wyko- Na koniec uruchom procedurę dla produk-
specyficznego kodu błędu, jednak w prak- rzystałem własny kod błędu do zasygnali- tu, który nie istnieje, na przykład:
tyce nie zalecałbym stosowania handle- zowania braku możliwości usunięcia okre-
rów do obsługi sytuacji przedstawionej w ślonego produktu. W wierszu {1} zadekla- db2 call delete_product('watermelon',?)
tym przykładzie, ponieważ obsługa błędów rowałem kod błędu o wartości ‘99001', tak
jest dosyć kosztowna i częste wywoływanie aby nie pokrywał się z predefiniowanymi w Procedura zwróci jedynie komunikat infor-
handlera może mieć negatywny wpływ na DB2 wartościami SQLSTATE, a w wierszu {2} mujący o tym, że produkt nie został znale-
wydajność aplikacji. W tym szczególnym zdefiniowałem dla niego handler typu EXIT. ziony:
przypadku taniej jest sprawdzić, czy pro- Jeśli produkt o podanej nazwie nie istnieje,
dukt o podanej nazwie już istnieje i w za- to w wierszu {3} zgłaszam błąd poleceniem Wartości parametrów wyjściowych
leżności od tego wywołać albo instrukcję SIGNAL, podając nazwę błędu i dodatkowy --------------------------
INSERT, albo UPDATE, bądź wykorzystać go- komunikat informacyjny. W wierszu {4} Nazwa parametru: P_MESSAGE
tową instrukcję MERGE. Sprawdźmy zatem również zgłaszam błąd, jeśli ilość produk- Wartość parametru: Product not found
działanie procedury z Listingu 23. Zapisz tu na magazynie jest większa od zera. Wy-
jej treść w pliku p22.sql i skompiluj, wy- wołanie polecenia SIGNAL w wierszach {3} Przy tej okazji chciałbym jeszcze wspo-
wołując: i {4} powoduje wywołanie handlera z wier- mnieć o instrukcji GET DIAGNOSTICS, uży-
sza {2}, wewnątrz którego ustawiany jest pa- tej w przykładzie z Listingu 24. Instruk-
db2 -td@ -vf p22.sql rametr wyjściowy z komunikatem błędu. cja ta daje dostęp do komunikatów błędów
Do pobrania komunikatu błędu użyłem w w obrębie handlera oraz pozwala spraw-
Ustaw dane początkowe w tabeli stock wy- handlerze instrukcji GET DIAGNOSTICS, któ- dzić ilość rekordów zmodyfikowanych w
wołaniem: rą szczegółowo omówię na następnym przy- ostatniej instrukcji SQL-owej oraz war-
kładzie. Sprawdźmy teraz, jak w praktyce tość zwracaną przez wywoływaną proce-
db2 call clean() działa procedura delete_product dla róż- durę. W przykładzie z Listingu 24 w wier-
nych przypadków. Zapisz kod procedury z szu {2} użyłem instrukcji GET DIAGNOSTICS
a następnie dodaj nowy produkt, urucha- Listingu 24 do pliku p23.sql i skompiluj do pobrania treści komunikatu ustawio-
miając procedurę poleceniem: poleceniem: nej w poleceniu SIGNAL w wierszach {3} i
{4}. Treść tego komunikatu jest ustawia-
db2 call add_product('melon',100,12.50) db2 -td@ -vf p23.sql na przez DB2 w zmiennej o nazwie DB2 _
TOKEN _ STRING . Może to być trochę my-
W wyniku działania tej procedury do tabeli Ustaw dane początkowe, wywołując pole- lące, ponieważ w instrukcji SIGNAL usta-
stock został dodany nowy produkt w ilości cenia: wiam zmienną MESSAGE _ TEXT, więc
100 i cenie jednostkowej 12.50, co możesz mógłbym się spodziewać, że w handle-
sprawdzić, wywołując: db2 call clean() rze w GET DIAGNOSTICS EXCEPTION zmien-
db2 update stock set amount = 0 where name na MESSAGE _ TEXT ma dokładnie tę samą
db2 select * from stock = 'orange' wartość. Okazuje się jednak, że tekst z po-
lecenia SIGNAL trafia do zmiennej DB2 _
Identyfikator produktu powinien być taki Teraz wywołaj procedurę delete _ product TOKEN _ STRING . Z kolei w przykładzie z
sam jak wartość zwrócona przez procedurę dla istniejącego produktu, którego ilość jest Listingu 25 w wierszu {2} użyłem instruk-
– w moim przypadku jest to 7: większa od zera, na przykład: cji GET DIAGNOSTICS do pobrania pełnego
komunikatu błędu ustawianego w zmien-
Status powrotu= 7 db2 call delete_product('lemon',?) nej MESSAGE _ TEXT przez serwer DB2. Do
sprawdzenia ilości rekordów zmodyfiko-
Wywołaj ponownie tę samą procedurę, Wybrany produkt nie zostanie usunięty, a wanych przez ostatnią instrukcję INSERT/
zmieniając tylko cenę jednostkową, na przy- procedura zwróci komunikat informujący o UPDATE trzeba użyć w poleceniu GET
kład: tym, że jego ilość jest większa od zera: DIAGNOSTICS zmiennej ROW _ COUNT, tak jak

www.sdjournal.org 31
Tworzenie aplikacji

w wierszu {3} na Listingu 25, a do spraw- le przedstawię, jak w dynamiczny sposób Wartości parametrów wyjściowych
dzenia wartości zwracanej przez procedu- tworzyć i wywoływać zapytania SQL-owe. --------------------------
rę musisz użyć zmiennej RETURN _ STATUS, Na wstępie chciałbym wyjaśnić, że każde Nazwa parametru: P_COUNT
tak jak to pokazałem w wierszu {4}. Zapisz zapytanie SQL-owe, zarówno statyczne, Wartość parametru: 6
procedurę z Listingu 25 do pliku p24.sql i jak i dynamiczne musi przejść przez dwie
skompiluj poleceniem: fazy, zwane prepare i execute. W fazie prepa- Co oznacza, że zmodyfikowanych zostało
re silnik bazy danych weryfikuje popraw- sześć rekordów – ich ceny możesz sprawdzić
db2 -td@ -vf p24.sql ność składni zapytania, sprawdza, czy za- poleceniem:
pytanie może być w jakiś sposób zopty-
Ustaw dane początkowe, wywołując: malizowane, szuka najlepszej kombina- db2 select * from stock
cji indeksów do użycia w zapytaniu oraz
db2 call clean() optymalizuje kolejność złączeń tabel. W W procedurze change _ price wykorzy-
fazie execute następuje wykonanie zapyta- stałem instrukcję EXECUTE IMMEDIATE do
a następnie wywołaj tę procedurę z parame- nia i pobranie danych. Jak się domyślasz, wykonania dynamicznego zapytania, któ-
trami jak poniżej: w statycznym SQL-u faza prepare jest wy- ra, jak już wspomniałem, uruchamia obie
konywana tylko raz, a wszystkie uzyska- fazy zapytania SQL-owego: prepare i exe-
db2 call update_promo('l%',3,?,?,?) ne w tej fazie informacje są trwale zapi- cute. W praktyce, stosując dynamiczny
sywane w bazie danych. Dla dynamiczne- SQL, często zdarza się sytuacja, kiedy fa-
W efekcie jej działania kody promocyjne go SQL-a faza prepare jest wykonywana za zę prepare można wykonać tylko raz, a na-
produktów, których nazwa zaczyna się na każdym razem, a w celu poprawienia wy- stępnie wielokrotnie wykonuje się fazę
literę ‘l’, zostaną ustawione na wartość 3, a dajności, dla często wykonywanych zapy- execute. Rozwiązanie takie jest optymal-
ponadto procedura zwróci następujące war- tań dynamicznych, efekty działania fazy ne, ponieważ nie powtarza się kosztow-
tości: prepare są przechowywane w dynamicz- nej czasowo fazy prepare. DB2 udostępnia
nym cache’u (tzw. package cache). Użycie dwie instrukcje do wykonania faz prepa-
Wartości parametrów wyjściowych dynamicznego SQL-a wprowadza dodatko- re i execute, które nazywają się nie inaczej
-------------------------- wy narzut związany z kompilacją w trakcie jak właśnie PREPARE i EXECUTE . W proce-
Nazwa parametru: P_MSG wykonywania zapytania, ale za to daje nam durze na Listingu 27 wykorzystałem po-
Wartość parametru: - możliwości, których nie uzyskamy, stosu- lecenie PREPARE do przygotowania dyna-
Nazwa parametru: P_COUNT jąc statyczny SQL, w szczególności w sy- micznego zapytania, a potem wielokrot-
Wartość parametru: 2 tuacjach, kiedy aż do momentu wykona- nie wywołuję polecenie EXECUTE . Proce-
Nazwa parametru: P_AMOUNT nia zapytania nie wiemy, jaki będzie jego dura add z Listingu 27 dodaje do tabeli
Wartość parametru: 90 końcowy kształt. Taki przypadek przedsta- rekordy na podstawie przekazanych pa-
wiłem na Listingu 26. Procedura change_ rametrów, a przy tej okazji chciałem rów-
Pusty komunikat błędu w parametrze P _ price umożliwia zwiększenie lub zmniej- nież pokazać, jak w procedurach składo-
MSG oznacza, że procedura zakończyła się po- szenie ceny dowolnych produktów o do- wanych możesz użyć typów tablicowych.
prawnie, parametr P _ COUNT zawiera liczbę wolną kwotę. Zapytanie SQL-owe jest dy- Prześledźmy zatem treść tej procedury.
zmodyfikowanych rekordów, a P _ AMOUNT namicznie tworzone w wierszu {1} na pod- Procedura przyjmuje jako parametry trzy
zawiera sumę ilości tych produktów, któ- stawie parametrów przekazanych do pro- typy tablicowe: tablicę nazw produktów
rych kod promocyjny został zmieniony. Jeśli cedury (kwota oraz warunek selekcji rekor- p _ names, tablicę ilości produktów p _
wywołasz tę samą procedurę dla produktów, dów). Zapytanie jest zapisywane w zmien- amounts oraz tablicę cen produktów p _
które nie istnieją, na przykład: nej tekstowej, a następnie wykonywane in- prices. Te trzy tablice muszą mieć ten
strukcją EXECUTE IMMEDIATE w wierszu {2}. sam rozmiar, inaczej procedura zakoń-
db2 call update_promo('x%',3,?,?,?) Instrukcja ta wykonuje obie fazy zapytania czy się błędem. W wierszu {1} zadeklaro-
SQL-owego, czyli prepare i execute. Po wy- wałem zmienną typu STATEMENT, w której
to procedura zwróci komunikat błędu, a po- konaniu zapytania w wierszu {3} spraw- zostanie zapisane przygotowywane zapy-
zostałe parametry nie będą ustawione: dzam, ile rekordów zostało zmienionych, a tanie. W wierszu {3} instrukcją PREPARE
wynik zapisuję w parametrze wyjściowym. przygotowuję dynamiczne zapytanie na
Wartości parametrów wyjściowych Przekonajmy się zatem, jak działa ta pro- podstawie tekstu zapisanego w zmiennej
-------------------------- cedura. Zapisz jej treść w pliku p25.sql i tekstowej w wierszu {2}. Następnie w pę-
Nazwa parametru: P_MSG skompiluj poleceniem: tli – tyle razy, ile elementów zawierają ta-
Wartość parametru: SQL0100W Nie blice (wszystkie mają ten sam rozmiar) –
znaleziono wiersza dla FETCH, db2 -td@ -vf p25.sql uruchamiam zapytanie SQL-owe, wyko-
UPDATE lub DELETE albo rezultatem nując instrukcję EXECUTE w wierszu {5}.
zapytania jest pusta tabela. Ustaw dane początkowe poleceniem: Zauważ, że w treści dynamicznego zapy-
Nazwa parametru: P_COUNT tania, w wierszu {2} w klauzuli VALUES,
Wartość parametru: - db2 call clean() umieszczone są znaki zapytania. W ich
Nazwa parametru: P_AMOUNT miejsce podczas wywołania instrukcji
Wartość parametru: - Spróbujmy teraz zwiększyć cenę wszystkich EXECUTE w wierszu {5} zostaną podstawio-
Status powrotu= 0 produktów o 2.50, wywołując: ne wartości zmiennych dokładnie w takiej
kolejności w jakiej występują w klauzu-
Dynamiczny SQL db2 call change_price(2.50,'name like li USING . Ze względu na to, że w klauzuli
Do tej pory we wszystkich przykładach wy- ''%''',?) USING nie mogą wystąpić tablice, w wier-
korzystywaliśmy statyczny SQL, choć jaw- szu {4} musiałem przepisać wartości z ta-
nie o tym nie mówiliśmy. W tym rozdzia- Procedura zwróci następujący rezultat: blic do odpowiednich zmiennych. Podsu-

32 SDJ Extra 35
Procedury składowane w DB2 9

mowując, procedura add tylko raz przygo- db2 call clean() uwagę, że procedura calc _ value przyj-
towuje zapytanie tworzone dynamicznie, muje dwa parametry wejściowe, jeden
które następnie wykonuje tyle razy, ile Uruchom procedurę poleceniem: wyjściowy i jeden wejściowo-wyjściowy,
elementów zostało przekazanych w tabli- dlatego w klauzuli USING w wierszu {6} po-
cach. Sprawdźmy zatem działanie tej pro- db2 call list('name,price','price ">=" daję parametry wejściowe, w klauzuli INTO
cedury w praktyce. Zapisz treść procedu- 4.00') w wierszu {5} podaję parametry wyjścio-
ry z Listingu 27 do pliku p26.sql i skom- we, a parametr wejściowo-wyjściowy wy-
piluj poleceniem: Na ekranie zostaną wyświetlone nazwy i ce- stępuje w obu klauzulach. Przepisywa-
ny wszystkich produktów, których cena jed- nie wartości do/z parametrów wywoływa-
db2 -td@ -vf p26.sql nostkowa jest większa lub równa 4.00: nej procedury odbywa się w kolejności ich
występowania w klauzulach USING i INTO.
Ustaw dane początkowe, wywołując: Tabela wynikowa 1 W Ramce 1 poniżej przedstawiłem sposób
-------------- przekazywania wartości z/do procedury z
db2 call clean() NAME PRICE Listingu 29.
------------ ------------------ Sprawdźmy, jak działa ta procedura. Zapisz
Teraz dodaj nowe trzy produkty, wołając: grapes 4.20 kod z Listingu 29 do pliku p28.sql i skompi-
apple 5.25 luj, wołając:
db2 call add(ARRAY['a', 'b', 'c'], banana 6.30
ARRAY[1, 2, 4], ARRAY[1.0, 2.0, Wybrano 3 rekordów. db2 -td@ -vf p28.sql
3.0])
Omówiliśmy już dynamiczne instrukcje, Ustaw dane początkowe, wywołując:
Sprawdź zawartość tabeli stock poleceniem: dynamiczne kursory, pozostał nam do
omówienia problem dynamicznego wywo- db2 call clean()
db2 select * from stock ływania procedur. W zasadzie dynamicz-
ne wywołanie procedury nie różni się ni- Następnie uruchom procedurę poleceniem:
Oprócz dynamicznych zapytań typu czym od wywołania na przykład instruk-
SELECT, INSERT lub UPDATE, w procedu- cji SELECT, z tym zastrzeżeniem, że wywo- db2 call calculate_totals(?)
rach składowanych możesz również two- ływana procedura może przyjmować para-
rzyć dynamiczne kursory, których zawar- metry wejściowe, wyjściowe i wejściowo- Procedura powinna zwrócić sumaryczną
tość będzie oparta na zapytaniu tworzo- wyjściowe. Dlatego też składnia polecenia wartość wszystkich produktów na magazy-
nym tuż przed otwarciem kursora. Na Li- EXECUTE dla wywoływanych procedur za- nie, tak jak pokazałem poniżej:
stingu 28 przedstawiłem procedurę, któ- wiera klauzule INTO oraz USING . W klau-
ra zwraca zestaw danych oparty na kur- zuli INTO podajemy zmienne, do których Wartości parametrów wyjściowych
sorze, ale liczba kolumn i lista zwróco- zostaną zapisane wartości z parametrów --------------------------
nych rekordów zależą od przekazanych wyjściowych i wejściowo-wyjściowych, Nazwa parametru: P_OUT
do procedury parametrów. W parame- a w klauzuli USING podajemy zmienne za- Wartość parametru: 2215.50
trze p _ columns przekazuję listę nazw wierające parametry wejściowe wywoły- Status powrotu= 0
kolumn do wyświetlenia, a w parametrze wanej procedury. Na Listingu 29 zamie-
p _ condition warunek selekcji rekor- ściłem procedurę, która oblicza całkowi- Podsumowanie
dów. Przykład ten pokazuje, jak za pomo- tą wartość wszystkich produktów, a do W artykule przybliżyłem podstawowe kon-
cą dynamicznego kursora w prosty sposób obliczeń wykorzystuje procedurę calc _ strukcje języka procedur składowanych w
można zrealizować funkcjonalność dy- value z Listingu 4. W wierszu {1} zadekla- DB2, takie jak zmienne, instrukcje bloko-
namicznego raportu. Przyjrzyjmy się za- rowałem zmienną do przechowania uru- we, pętle, instrukcje obsługi błędów, kur-
tem bliżej tej procedurze. W wierszu {1} chamianego zapytania. W wierszu {2} za- sory oraz metody dynamicznego wykony-
zadeklarowałem zmienną do przechowa- deklarowałem treść dynamicznego wy- wania zapytań. Mam nadzieję, że przed-
nia przygotowanego zapytania, a w wier- wołania procedury calc _ value, z ozna- stawione przykłady będą bardzo dobrym
szu {2} zadeklarowałem kursor oparty na czeniem parametrów za pomocą czterech wstępem do programowania w języku SQL
tej zmiennej. Treść dynamicznego zapy- znaków zapytania. Dla przypomnienia, PL w DB2.
tania zapisuję w wierszu {3} do zmiennej deklaracja procedury calc _ value wyglą-
tekstowej, a w wierszu {4} przygotowuję da następująco:
zapytanie, wywołując polecenie PREPARE .
Następnie w wierszu {5} otwieram kur- CREATE PROCEDURE calc_value(
sor, a ponieważ jest on zadeklarowany z IN p_amount INTEGER,
klauzulą WITH RETURN, to zostanie zwróco- IN p_price DECFLOAT,
ny do programu wywołującego. Dzięki te- OUT p_value DECFLOAT, Dariusz Depta
mu rezultat działania procedury list mo- INOUT p_total DECFLOAT Dariusz Depta pracuje jako kierownik działu roz-
żemy zobaczyć bezpośrednio na konsoli ) woju technologicznego w firmie dostarczającej
procesora poleceń. Skompiluj zatem pro- oprogramowanie dla sektora ubezpieczeń bez-
cedurę z Listingu 28, zapisując jej treść w W wierszu {3} wywołuję polecenie pośrednich. Jego pasją jest tworzenie oprogra-
pliku p27.sql: PREPARE ,które przygotowuje zapytanie mowania w różnych językach (Java, C/C++, Ob-
SQL-owe z wiersza {2}. Następnie, za po- ject Pascal, Erlang, Prolog, Ruby), a wolny czas
db2 -td@ -vf p27.sql mocą pętli FOR , iteruję po wszystkich re- spędza z rodziną na wyprawach pieszych i ro-
kordach i sumuję wartości produktów, werowych.
Ustaw dane początkowe, wywołując: wywołując EXECUTE w wierszu {4}. Zwróć Kontakt z autorem: depta@wsoft.pl

www.sdjournal.org 33
Tworzenie aplikacji

DB2 COBRA
– Converting Oracle
Becomes Really Affordable
Marcin Molak
Migracja aplikacji z bazy Oracle do DB2 wymusza na programistach
rozpoznanie specyfiki nowego środowiska baz danych. Programiści
muszą zapoznać się z różnicami w dialektach SQL, typach danych oraz
dostępnych funkcjach. Muszą także pokonać swoje przyzwyczajenia, by
skorzystać z nowych narzędzi. IBM wyszedł naprzeciw oczekiwaniom
firm tworzących oprogramowanie współpracujące z bazami Oracle i
wprowadził szereg mechanizmów kompatybilności w wersji DB2 9.5.
Zakres usprawnień został znacznie rozszerzony w wersji 9.7.
Terminologia w DB2 Wprowadzając na rynek wersję DB2 9.5, Sterowanie całym mechanizmem ograni-
Pierwszą barierą podczas poznawania nowe- firma IBM udostępniła programistom apli- cza się do ustawienia wartości zmiennej sys-
go systemu zarządzania baz danych jest ko- kacji na bazie Oracle DB szereg poziomów temowej DB2_COMPATIBILITY_VECTOR. Po-
nieczność zrozumienia pojęć, jakimi operu- kompatybilności. Co więcej, ich zakres zo- szczególne funkcjonalności dostępne w ba-
ją jego użytkownicy. Patrząc na serwer IBM stał znacząco rozszerzony w wersji 9.7 po- zie Oracle przypisane są odpowiednim war-
DB2 z punktu widzenia programisty lub ad- przez dodanie obsługi składni języka PL/ tościom w systemie heksadecymalnym. Ich
ministratora Oracle DB, zauważymy, iż wie- SQL. Umożliwiono w ten sposób progra- suma pozwala na uruchomienie zbioru od-
le pojęć jest ze sobą tożsamych. Inne wymaga- mistom efektywniejsze przygotowanie ko- powiednich mechanizmów w bazie DB2
ją jedynie poznania nowej nazwy. Istnieją jed- du dla bazy DB2 bez rezygnowania z istnie- (patrz Tabela 2). Warto zauważyć, iż część
nak i takie, które w poznawanym przez nas jących przyzwyczajeń. funkcjonalności będzie uruchomiona je-
systemie mają zupełnie inne znaczenie niż
to, do którego jesteśmy przyzwyczajeni. Przy-
kładem takiego pojęcia są pakiety. W Orac-
le pakiet jest obiektem, który grupuje pro-
gramy PL/SQL oraz inne elementy, takie jak
typy, zmienne, wyjątki czy kursory. Pakiet w
DB2 jest obiektem zawierającym skompilo-
waną wersję zapytań SQL oraz przygotowa-
ne przez optymalizator plany zapytań. Bez-
pośrednim odpowiednikiem pakietów Orac-
le są w DB2 moduły.
W Tabeli 1 przedstawione zostało po-
równanie pojęć w terminologii serwerów
IBM DB2 i Oracle DB, uzupełnione ko-
mentarzem. Zestawienie uzupełniono
również o polskie nazewnictwo dla serwe-
ra IBM DB2.

DB2 jak Oracle DB


Po określeniu różnic w terminologii nowe-
go systemu zarządzania bazami danych pro-
gramista stawał przed kolejnym wyzwa-
niem – poznaniem składni nowego dialek-
tu SQL oraz języka procedur składowanych. Rysunek 1. Silnik kodu proceduralnego DB2 9.7

34 SDJ Extra 35
DB2 COBRA – Converting Oracle Becomes Really Affordable

Tabela 1. Pojęcia w systemach Oracle DB i IBM DB2


Oracle DB IBM DB2 Komentarz
Active log Active log (dziennik aktywny) Plik dziennika transakcji, który zawiera aktywne transakcje. Ten sam plik wykorzystywany jest do
operacji wycofywania transakcji (rollback), jak i do naprawy bazy danych po awarii (crash recovery).
Alert log Administration notification log Jest to podstawowe źródło informacji o zdarzeniach związanych z systemem DB2. Serwer za-
(dziennik powiadomień admini- pisuje w nim informacje takie jak status wykonania narzędzi (reorganizacja, kopia zapasowa),
stracyjnych) błędy aplikacji klienckich, błędy składowania danych czy zmiany w licencjonowaniu produk-
tu. W systemach typu UNIX lub Linux dziennik ten jest dostępny w postaci pliku nazwa_instan-
cji.nfy, a w systemach Windows – w dzienniku zdarzeń systemowych.
Archive log Archive log (Dzienniki archi-
walne)
bdump directory Diagnostic log – db2diag.log Dziennik diagnostyczny jest przeznaczony głównie dla pomocy technicznej DB2. Zawiera
(dziennik diagnostyczny) wszystkie informacje diagnostyczne opisujące błędy (w tym zawarte w dzienniku powiado-
mień administracyjnych).
Data block Data page (strona) Podstawowa jednostka operacji we/wy. W DB2 wspierane są następujące rozmiary stron: 4 KB,
8 KB, 16 KB, 32 KB.
Data buffer cache Buffer pool (pula buforów) DB2 pozwala na utworzenie dowolnej liczby puli buforów.
Data dictionary System catalog (słownik syste- Słownik systemowy jest zbiorem meta danych przechowywanych w formie tabel i widoków.
mowy) Dla każdej bazy serwer przygotowuje dwa zestawy widoków:
SYSCAT – widoki tylko do odczytu
SYSSTAT – widoki dla statystyk, z możliwością modyfikowania
Data file Container (kontener) Dane w DB2 są składowane w kontenerach. Kontenerem może być plik, katalog bądź urządze-
nie surowe (raw device).
Database link Nickname (pseudonim) Pseudonim jest wskaźnikiem dla obiektu sfederowanej bazy danych.
Dual table Dual table / SYSDUMMY1 table Podstawową tabelą dla ewaluacji wyrażeń w DB2 jest SYSIBM.SYSDUMMY1.
(tabele Dual i SYSDUMMY1)
Dynamic performan- Snapshot monitor SQL admini- Widoki administracyjne monitora obrazów stanu dostępne w schemacie SYSIBMADM, prze-
ce views strative views (widoki admini- chowują informacje o komponentach bazy danych.
stracyjne dla monitora obrazów
stanu)
Extent Extent (ekstent) Ekstent jest zbiorem kolejnych stron na dysku przydzielonych dla określonego obiektu.
init.ora i Server Para- Database manager configuration Pojedyncza instancja DB2 może obsługiwać wiele baz danych. Dostęp do plików konfiguracyj-
meter File (SPFILE) file (plik konfiguracyjny instancji) nych jest zapewniony poprzez komendy administracyjne GET i UPDATE DBM CONFIG oraz GET i
i database configuration file (plik UPDATE DB CONFIG.
konfiguracyjny bazy danych)
Instance Instance (instancja) / database Instancja jest niezależnym środowiskiem do pracy z bazami DB2. W DB2 instancja jest również
manager (menadżer baz danych) określana mianem menadżera bazy danych. Z instancją typu serwer związany jest zbiór proce-
sów obsługujących bazy danych oraz wspólny obszar pamięci.
Large pool Utility heap (sterta narzędzi) Fragment pamięci używany przez narzędzia backup, restore i load.
Library cache Package cache (pamięć podręcz- Pamięć przechowująca skompilowane plany realizacji zapytań SQL i XQuery.
na pakietów)
Materialized view Materialized query table – MQT MQT to tabela, której definicję oparto o wynik zapytania. Decyzja o użyciu MQT bądź tabeli ba-
(Zmaterializowany widok) zowej jest podejmowana przez optymalizator DB2.
ORACLE_SID DB2INSTANCE
Package Module (moduł) Obiekty wprowadzone w wersji DB2 9.7. Równolegle wyodrębniono struktury pakietów PL/
SQL.
Procedural SQL Procedural Language (SQL SQL PL (podzbiór SQL/PSM) jest językiem pozwalającym na definiowanie logiki biznesowej w
Language/Structured PL) bazie danych. Od wersji DB2 9.7 możliwe jest również wykorzystywanie składni PL/SQL.
Query Language (PL/
SQL)
Program global area Application shared memory (pa- Pamięć współużytkowana aplikacji to obszar pamięci pozwalający na współdzielenie danych
(PGA) mięć współużytkowana aplikacji) wynikowych między bazą danych a aplikacją.
i agent private memory (prywat- Prywatna pamięć agenta jest używana do obsługi danej aplikacji (sortowanie, utrzymanie kon-
na pamięć agenta) tekstu danej sesji, informacje o kursorach).
Redo log Transaction log (dziennik transakcji) Przechowuje informacje o transakcjach. Używany również w procesie odtwarzania bazy danych.
Role Role (rola) Obiekt dostępny od wersji DB2 9.5.
Segment Storage object (obiekt przecho-
wywania)
Synonym Alias Alias stanowi jedynie alternatywną nazwę dla tabeli, widoku, pseudonimu lub innego aliasu.
Nie jest mechanizmem kontroli wersji procedury składowanej bądź funkcji użytkownika (do te-
go celu służy instrukcja SET PATH).
System global area Instance shared memory (współ- Współużytkowane pamięci na poziomie instancji i bazy danych mogą być mapowane na SGA.
(SGA) użytkowana pamięć instan- Pierwsza z nich przechowuje informacje niezbędne do działania instancji, takie jak informacje
cji) i database shared memory o połączeniach czy uprawnieniach użytkowników. Druga obejmuje struktury pamięciowe ba-
(współużytkowana pamięć ba- zy danych, takie jak pule buforów, bufor dziennika transakcji czy pamięć podręczna pakietów.
zy danych)
User global area Application global memory (cał- Całkowita pamięć dla obsługi aplikacji.
(UGA) kowita pamięć aplikacji)

www.sdjournal.org 35
Tworzenie aplikacji

Listing 1. Mapowanie typów przy włączonym poziomie kompatybilności ORA


dynie dla nowoutworzonych baz danych, a
wszystkie zmiany ustawienia wymagają re-
startu motoru.
CREATE TABLE cobra.zadania ( Ustawienia wartości zmiennej dokonuje-
id NUMBER(5) NOT NULL PRIMARY KEY, my poleceniem db2set, np.:
zadanie VARCHAR2(300),
data DATE db2stop
); db2set DB2_COMPATIBILITY_VECTOR = ORA
DB20000I Wykonanie komendy SQL zakończyło się pomyślnie. db2start
DESCRIBE TABLE cobra.zadania;
Schemat Długość Powyższa zmienna uruchamia maksymalny
Nazwa kolumny typu danych Nazwa typu danych kolumny Zera skali poziom kompatybilności z bazą Oracle DB.
Wartość ORA została wprowadzona w wer-
------------ --------- ----------------- -------- ----- ------ sji DB2 9.7 i jest zalecana dla aplikacji prze-
noszonych z baz Oracle DB.
ID SYSIBM DECIMAL 5 0 Nie
Typy danych i kolekcje
ZADANIE SYSIBM VARCHAR 300 0 Tak Migrując istniejące aplikacje na serwer
IBM DB2, programiści często spotyka-
DATA SYSIBM TIMESTAMP 7 0 Tak li się z koniecznością mapowania typów
z baz danych Oracle DB. Proces ten mógł
Wybrano 3 rekordy. być zautomatyzowany np. poprzez zasto-
sowanie aplikacji IBM Migration Toolkit,
jednak nadal zdarzały się sytuacje, w któ-
Tabela 2. Poziomy kompatybilności w DB2 rych decyzję musiał podjąć człowiek, np. z
Wartość Nazwa funkcjonalności DB2 9.5 DB2 9.7 Wymagane przed utwo- powodu braku odpowiadającego typu bądź
rzeniem bazy różnic w implementacji (np. dla typu Da-
1(0x01) ROWNUM Tak Tak Nie te). W ramach wersji 9.5 wprowadzono
dwa nowe typy – typ zmiennoprzecin-
2(0x02) DUAL Tak Nie dotyczy Tak
kowy DECFLOAT, wspomagany sprzętowo
3(0x04) Operator (+) dla OUTER JOIN Tak Tak Nie
przez procesory rodziny IBM Power 6, oraz
4(0x08) Wyrażenia hierarchiczne Tak Tak Nie typ tablicowy (ARRAY). W wersji 9.7 wpro-
5(0x10) NUMBER Nie Tak Tak wadzono wiele typów znanych z serwera
6(0x20) Oracle DATE Nie Tak Tak danych Oracle DB.
W ramach poziomów kompatybilno-
7(0x40) VARCHAR2 Nie Tak Tak
ści zostały wprowadzone typy: zmienno-
8(0x80) TRUNCATE TABLE Nie Tak Nie
przecinkowy NUMBER, łańcuch znaków
9(0x100) Obsługa łańcuchów znaków Nie Tak Nie VARCHAR2 oraz implementacja formatu cza-
10(0x200) Obsługa kolekcji danych Nie Tak Nie sowego DATE, zgodnego ze strukturą Orac-
11(0x400) Data dictionary – zestaw wido- Nie Tak Tak le. Wykorzystanie typu NUMBER opiera się
ków administracyjnych na jego bezpośrednim mapowaniu na typ
12(0x800) Kompilacja PL/SQL Nie Tak Nie DECFLOAT(16) bądź na typ DECIMAL przy
określonej precyzji. Typ DATE został opar-
Tabela 3. Moduły procedur zaimplementowane w DB2 9.7 ty na typie TIMESTAMP (o precyzji rów-
nej 0), a typ VARCHAR2 na typie VARCHAR z
Nazwa Opis
zachowaniem logiki działania charaktery-
DBMS_ALERT Zawiera procedury do rejestrowania, wysyłania i odbierania alertów. stycznej dla typu Oracle DB, to jest ma-
DBMS_JOB Obejmuje procedury do zarządzania zadaniami. powaniu pustego ciągu znaków na wartość
DBMS_LOB Dostarcza procedur operujących na obiektach LOB. NULL. Zobrazowanie mechanizmu mapo-
wania pokazano na Listingu 1. Na bazie za-
DBMS_OUTPUT Stanowi zbiór procedur wkładających i wyjmujących komunikaty z bufora wia-
domości. Jest podstawą do debugowania aplikacji. pytania SQL tworzona jest tabela ZADANIA
zawierająca typy NUMBER, VARCHAR2 i DATE.
DBMS_PIPE Zapewnia komunikację między sesjami poprzez procedury obsługi strumieni.
Następnie struktura tabeli wewnętrznie
DBMS_SQL Dostarcza procedury składowane do wywoływania dynamicznego kodu SQL,
w tym operacji DML i DDL.
zarządzana przez DB2 jest wyświetlana
poleceniem DESCRIBE TABLE.
DBMS_UTILITY Obejmuje zbiór procedur narzędziowych.
W kodzie proceduralnym możliwe jest
UTL_DIR Zawiera procedury do zarządzania aliasami dla katalogów systemu plików (na również wykorzystanie typu logicznego
rzecz procedur modułu UTL_FILE).
BOOLEAN, rekordu ROW (RECORD), typów za-
UTL_FILE Stanowi zbiór procedur pozwalający na odczyt i zapis plików z systemu plików kotwiczonych ANCHOR(%TYPE) i ANCHOR
serwera bazodanowego.
ROW(%ROWTYPE), kursorów (REF CURSOR) oraz
UTL_MAIL Moduł pozwalający na zarządzanie pocztą elektroniczną (wysyłanie wiadomo- tablic asocjacyjnych (INDEX BY).
ści).
W tym miejscu warto również zaznaczyć,
UTL_SMTP Dostarcza procedur do wysyłania wiadomości elektronicznych poprzez proto- iż nie jest już wymagane jawne rzutowanie
kół SMTP.
pomiędzy typami numerycznymi i łańcu-

36 SDJ Extra 35
DB2 COBRA – Converting Oracle Becomes Really Affordable

chami znaków oraz łańcuchami znaków a teczna i wydajna, to jednak CONNECT BY sta- stępnych funkcji. Wśród nich znalazły
typami date/time/timestamp. ła się w oczach programistów bardziej przy- się funkcje operujące na bitach (BITAND,
jazna. Dlatego też od wersji DB2 9.5 moż- BITANDNOT, BITOR, BITXOR oraz BITNOT), wy-
Funkcje i składnia SQL liwe jest jej uruchomienie w ramach pozio- szukujące najmniejszą i największą wartość
Po przygotowaniu struktur danych nadcho- mów kompatybilności (wartość 0x08 dla w zbiorze argumentów (LEAST i GREATEST).
dzi czas na uruchomienie własnych skryp- wektora). Jej użycie przedstawiono na Li- Wśród nowych funkcji znalazły się również
tów. Jeśli użyliśmy składni oraz funkcji wy- stingu 2. bardzo popularne w Oracle DB funkcje NVL
kraczających poza zakres ANSI SQL, poja- Podobnie jak CONNECT BY, w DB2 9.5 i DECODE. Pierwsza z nich pozwala na wy-
wia się wówczas pytanie, czy przygotowa- wprowadzono również możliwość stoso- szukanie pierwszej wartości oznaczonej w
ny kod zadziała? W wersji DB2 9.5 również wania operatora (+) dla złączeń zewnętrz- zbiorze argumentów, dzięki temu doskona-
ten aspekt motoru bazy danych uległ mody- nych (ang. outer join), klauzuli UNIQUE jako le nadaje się do jawnego określenia wartości
fikacjom. synonimu DISTINCT czy klauzuli MINUS ja- dla pól z wartością NULL w wyniku zapyta-
Na początek przyjrzyjmy się składni dla ko alternatywy dla EXCEPT. Na tym tle war- nia. Druga stanowi natomiast implementa-
wyrażeń hierarchicznych. W DB2 w ślad to również wspomnieć o możliwości wyko- cję funkcji warunkowej, pozwalając na łatwe
za standardem ANSI używana była skład- rzystania tabeli DUAL do ewaluacji wyrażeń rzutowanie wartości jednego zbioru w dru-
nia WITH … UNION ALL. Tymczasem w Orac- oraz pseudokolumny ROWNUM użytecznej w gi. Na Listingu 3 przedstawiono przykłado-
le DB wprowadzono do dialektu SQL alter- stronicowaniu danych (realizowanym w sys- we wykorzystanie funkcji DECODE.
natywę w postaci klauzuli CONNECT BY. Mi- temach Open Source przez klauzule LIMIT
mo iż pod kątem możliwości generowania i OFFSET). Kod PL/SQL
złożonych zbiorów wynikowych standardo- Niezależnie od rozszerzenia składni SQL, Ostatnim i zarazem bardzo istotnym ele-
wa rekursja jest co najmniej tak samo sku- w wersji DB2 9.5 poszerzono wachlarz do- mentem pracy programisty baz danych w

Listing 2. Użycie klauzuli CONNECT BY w DB2

Plik: struktura.sql
-- Tworzenie tabeli
CREATE TABLE cobra.struktura(
id BIGINT NOT NULL PRIMARY KEY,
stanowisko VARCHAR(30),
przel_id BIGINT REFERENCES cobra.struktura(id)
);
-- Uzupełnienie danych
INSERT INTO cobra.struktura VALUES
(1, 'specjalista', 3),
(2, 'konsultant', 3),
(3, 'kierownik', 4),
(4, 'menadżer', 5),
(5, 'dyrektor', NULL);

Plik: drzewo.sql
SELECT LEVEL as poziom,
stanowisko,
CONNECT_BY_ROOT stanowisko AS najwyzsze,
SYS_CONNECT_BY_PATH(stanowisko, ':') AS struktura
FROM cobra.struktura
START WITH stanowisko = 'menadżer'
CONNECT BY PRIOR id = przel_id
ORDER SIBLINGS BY stanowisko;

POZIOM STANOWISKO NAJWYZSZE STRUKTURA

----------- ------------------------------ ------------------------------ -------------------------------

1 menadżer menadżer :menadżer

2 kierownik menadżer :menadżer:kierownik

3 konsultant menadżer :menadżer:kierownik:konsultant

3 specjalista menadżer :menadżer:kierownik:specjalista

Wybrano 4 rekordy.

www.sdjournal.org 37
Tworzenie aplikacji

procesie migrowania aplikacji jest przenie-


Listing 3. Przykładowe wykorzystanie funkcji DECODE sienie istniejącej logiki biznesowej do no-
wego systemu. W tej materii serwery baz
SELECT danych DB2 do wersji 9.5 włącznie wy-
imie, nazwisko, muszały przeniesienie istniejącego kodu
DECODE(plec,'M','Mężczyzna','K','Kobieta') as plec do języka SQL PL. Wraz z wersją 9.7 pro-
FROM cobra.osoby gramista otrzymuje do dyspozycji wbudo-
wany kompilator kodu PL/SQL (patrz Ry-
Listing 4. Przykładowy blok PL/SQL sunek 1).
Aby uruchomić kod PL/SQL z pozio-
SET SQLCOMPAT PLSQL; mu Procesora wiersza poleceń (CLP), musi-
my ustawić środowisko komendą SET SQL-
SET SERVEROUTPUT ON; COMPAT PLSQL. Od tego momentu zna-
kiem terminującym dla wywoływanych
DECLARE skryptów będzie znak slash (/). Pozwoli to
vText VARCHAR2(15); nam na przygotowanie elementów logiki biz-
BEGIN nesowej zgodnie z nową składnią.
vText := 'Witaj świecie!'; Pierwszą i zarazem najprostszą obsługiwa-
DBMS_OUTPUT.PUT_LINE(vText); ną strukturą są bloki. Przykładowy blok zo-
END; stał przedstawiony na Listingu 4. Blok ten
/ składa się z sekcji deklaracji oraz z sekcji wy-
konawczej. W pierwszej z nich deklarujemy
SET SQLCOMPAT DB2; zmienną typu VARCHAR2, w drugiej do-
konujemy przypisania wartości oraz wyświe-
tlenia tekstu.
Przykład ten obrazuje jednak nie tylko
możliwość użycia elementów składni PL/
Ramka 1. Lista dostępnych widoków administracyjnych SQL, takich jak bloki czy operator przypisa-
Ogólne Bezpieczeństwo Tabele i widoki nia ‘:=’. Wyświetlenie tekstu na terminalu
wiąże się bowiem z użyciem procedury nale-
żącej do pakietu (modułu w SQL PL) DBMS_
DICTIONARY USER_ROLE_PRIVS *_CONSTRAINTS OUTPUT. Wraz z kompilatorem PL/SQL zosta-
DICT_COLUMNS DBA_ROLE_PRIVS *_CONS_COLUMNS
*_CATALOG ROLE_ROLE_PRIVS *_INDEXES
ły bowiem dostarczone zbiory procedur wy-
*_DEPENDENCIES SESSION_ROLES *_IND_COLUMNS korzystywanych przez programistów Oracle
*_OBJECTS USER_SYS_PRIVS *_TAB_PARTITIONS DB (patrz Tabela 3).
*_SEQUENCES DBA_SYS_PRIVS *_PART_TABLES W ramach DB2 9.7 możliwe jest rów-
USER_TABLESPACES ROLE_SYS_PRIVS *_PART_KEY_COLUMNS
DBA_TABLESPACES SESSION_PRIVS *_SYNONYMS
nież tworzenie własnych pakietów proce-
*_TAB_PRIVS *_TABLES dur i funkcji PL/SQL. Celem stworzenia
Programowanie i PL/SQL ROLE_TAB_PRIVS *_TAB_COMMENTS pakietu PL/SQL należy przygotować spe-
*_PROCEDURES USER_TAB_PRIVS_MADE *_TAB_COLUMNS cyfikację pakietu, zawierającą deklaracje je-
*_SOURCE ALL_TAB_PRIVS_MADE *_COL_COMMENTS
*_TRIGGERS USER_TAB_PRIVS_RECD *_TAB_COL_STATISTICS go elementów. Drugim elementem pakie-
*_ERRORS ALL_TAB_PRIVS_RECD *_VIEWS tu jest jego ciało, zawierające implementa-
*_ARGUMENTS DBA_ROLES *_VIEW_COLUMNS cje zadeklarowanych wcześniej elementów.
DBA_USERS Listing 5 prezentuje specyfikacje i ciało pa-
kietu str_admin, powiązanego ze strukturą
* = USER_DBA_ALL stanowisk (patrz Listing 2).
Na bazie tego przykładu warto podkreślić
dodanie obsługi klauzuli OR REPLACE dla
obiektów, takich jak aliasy, funkcje, moduły
(i pakiety PL/SQL), pseudonimy, procedury,
sekwencje, wyzwalacze (ang triggers), widoki
oraz zmienne.

CLPPLUS i słownik bazy danych


Analizując ścieżkę migracji aplikacji, posłu-
giwaliśmy się skryptami, które były urucha-
miane ze środowiska Procesora wiersza ko-
mend (CLP). Przyglądając się pracy progra-
mistów i administratorów Oracle DB, moż-
na zauważyć, iż ich praca bardzo często
opiera się na wywołaniu przygotowanych
wcześniej skryptów w terminalu SQL*Plus.
Co więcej, narzędzie to umożliwia bardzo
Rysunek 2. Narzędzie CLPPLUS wygodne formatowanie zbiorów wyniko-

38 SDJ Extra 35
DB2 COBRA – Converting Oracle Becomes Really Affordable

wych, pozwalając na przygotowanie pro-


Listing 5. Specyfikacja i ciało pakietu str_admin
stych raportów. Dlatego też w DB2 9.7
wprowadzono nowe narzędzie tekstowe
SET SQLCOMPAT PLSQL; CLPPLUS. Zachowuje ono cechy swojego
pierwowzoru, przyspieszając poznanie ser-
wera firmy IBM.
CREATE OR REPLACE PACKAGE cobra.str_admin Aby połączyć się do wybranej bazy danych,
IS wykonujemy komendę:
FUNCTION wyswietl_przel (
p_id BIGINT connect nazwa_użytkownika@serwer:port/
) baza_danych
RETURN BIGINT;
PROCEDURE dodaj_stanowisko ( np.
p_stanowisko VARCHAR(30),
p_przel_id BIGINT connect db2admin@localhost:50000/sample
);
END cobra.str_admin; Składnia ta może zostać łatwo rozszerzona o
/ hasło użytkownika do postaci:

connect nazwa_użytkownika/hasło@serwer:
CREATE OR REPLACE PACKAGE BODY cobra.str_admin port/baza_danych
IS
FUNCTION wyswietl_przel ( np.
p_id BIGINT
) connect db2admin/tajne@localhost:50000/
RETURN BIGINT sample
IS
v_szef_id BIGINT; Równie łatwo można poznać wszystkie ko-
BEGIN mendy procesora CLPPLUS. Wystarczy wpi-
SELECT przel_id INTO v_szef_id FROM cobra.struktura WHERE id=p_id; sać polecenie:
RETURN v_szef_id;
EXCEPTION HELP INDEX
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Brak stanowiska o numerze ' || p_id); Ukłonem w stronę administratorów jest
RETURN -1; również wprowadzenie struktur słowni-
END; ka bazy danych znanych im z Oracle DB
PROCEDURE dodaj_stanowisko ( (patrz Ramka). Dzięki temu dotychczas
p_stanowisko VARCHAR(30), wykonywane czynności mogą być w łatwy
p_przel_id BIGINT sposób przeniesione na nowy serwer baz
) danych.
IS
v_id BIGINT:=0; Podsumowanie
BEGIN Ideą niniejszego artykułu było pokazanie no-
SELECT MAX(id) INTO v_id FROM cobra.struktura; wych funkcjonalności dostępnych w serwe-
v_id := v_id + 1; rach danych DB2 w wersjach 9.5 i 9.7, uła-
INSERT INTO cobra.struktura VALUES (v_id, p_stanowisko, p_przel_id); twiających proces migrowania i wdrażania
RETURN 0; aplikacji na nowym serwerze danych. Stano-
EXCEPTION wi on jednak dopiero wstęp do poznania peł-
WHEN OTHERS THEN ni możliwości baz danych DB2 – do czego
DBMS_OUTPUT.PUT_LINE('The following is SQLERRM:'); serdecznie zachęcam.
DBMS_OUTPUT.PUT_LINE(SQLERRM);
DBMS_OUTPUT.PUT_LINE('The following is SQLCODE:');
DBMS_OUTPUT.PUT_LINE(SQLCODE);
RETURN -1;
END; Marcin Molak
END; Specjalista w zakresie zarządzania danymi w
/ dziale oprogramowania IBM Polska i ambasa-
dor programu inicjatywy akademickiej IBM. Od-
powiada za wsparcie serwerów danych DB2 i so-
SET SQLCOMPAT DB2; lidDB oraz narzędzi z rodzin Optim i Data Stu-
dio. Absolwent Wydziału Fizyki Politechniki War-
szawskiej. Prywatnie pasjonat nowych technolo-
gii oraz miłośnik fantastyki.
Kontakt z autorem: marcin.molak@pl.ibm.com

www.sdjournal.org 39
Tworzenie aplikacji

<XML> w praktyce
Marcin Molak
Realizacja kolejnych wymagań biznesowych współczesnego rynku
stawia przed działami IT szereg nowych wyzwań. Podstawowym
wymogiem dla tworzonych przez nie rozwiązań staje się zapewnienie
integracji z używanymi dotychczas aplikacjami. Proces ten, ze względu
na zróżnicowanie obsługiwanych struktur, musi zapewniać możliwość
zarówno transformacji, jak i pełnej walidacji przekazywanych danych.
Jednocześnie stawiane są wysokie wymogi bezpieczeństwa. Przez to
implementacja nowych rozwiązań mogłaby być zarazem procesem
skomplikowanym i czasochłonnym. W praktyce jednak z pomocą
przychodzą standardy oparte na języku XML. Języku, którego
niesłabnąca popularność na rynku trwa już 12 lat od opublikowania
pierwszej specyfikacji. Tym bardziej ciężko jest uwierzyć, iż początki
jego historii sięgają lat sześćdziesiątych dwudziestego wieku.

W
ówczas w laboratoriach firmy Zastosowanie XML prezentacje czy publikacje tekstowe. Obok
IBM trzej inżynierowie – Char- Otwierając dokument XML w edytorze tek- nich powstały także branżowe formaty,
les Goldfarb, Edward Mosher i stowym, poznajemy jego podstawową zaletę wśród których można wymienić standardy
Raymond Lorie opracowali uogólniony język – czytelność struktury danych. Struktury re- organizacji turystycznych (OTA), ubezpie-
znaczników (GML). Znaczniki te pozwalały prezentowanej w postaci drzewa elementów czeniowych (ACORD), finansowych rynku
twórcom dokumentu na wydzielenie w pro- oraz określających je atrybutów. Dzięki temu instrumentów pochodnych (FpML) czy bi-
sty sposób jego logicznych części. Stanowiło aplikacje mogły odwzorować swoje obiekty bliotek (MARC XML) i archiwów (EAD).
to znaczące usprawnienie wobec wcześniej- do samoopisującego się formatu tekstowego, W ten sposób, na tle wymienionych przy-
szego obowiązku fizycznego formatowania zrozumiałego dla innych systemów. Warto kładów stanowiących ułamek zastosowań
elementów, charakterystycznego dla ówcze- jednak zwrócić uwagę na fakt, iż zastosowa- XML, pojawia się potrzeba tworzenia repo-
snych typów drukarek. nie XML nie ogranicza się do samej wymia- zytoriów dokumentów XML dających możli-
W 1986 roku, bazując na doświadcze- ny informacji. O jego uniwersalności świad- wość wydajnego zarządzania informacją.
niach języka GML, opracowano korporacyj- czy cała gama standardów i typów dokumen-
ny standard opisu dokumentów – SGML tów, z którymi mamy częsty kontakt w prze- XML a bazy danych
(ang. Standard Generalized Markup Langu- tworzonej postaci. Podczas planowania repozytorium informa-
age). Jego specyfikacja zakładała jednak nie Najpopularniejszymi czytnikami doku- cji często nasz wybór pada na systemy za-
tylko uproszczenie definiowania struktu- mentów XML są przeglądarki internetowe. rządzania bazami danych. Oferują one wyso-
ry w ramach znaczników, ale również wpro- To za ich pośrednictwem oglądamy codzien- ką wydajność dla przygotowywanych rozwią-
wadzała możliwość określania zasad składni nie strony internetowe, napisane w języku zań, gwarantując jednocześnie ich pełną nie-
unifikujących sposoby konstrukcji oraz wy- XHTML. Coraz częściej wypełniamy także zawodność i rozbudowaną funkcjonalność.
miany dokumentów. W praktyce wymaga- dane w formularzach, dokonujących auto- Należy jednak zwrócić uwagę na fakt, iż
ło to jednak zdefiniowania obok dokumen- matycznej walidacji i przygotowanych w jed- powyższe deklaracje często ograniczają się do
tu również reguł jego zapisu oraz definicji je- nej z implementacji XForms (np. IBM Lotus danych relacyjnych. Dla struktur hierarchicz-
go typu (DTD). Forms). Kanały informacyjne RSS i ATOM nych, jakimi są dokumenty XML, obsługa re-
I właśnie trudności w implementacji języ- pozwalają nam natomiast aktualizować na alizowana jest jedynie na zasadzie rozszerze-
ka SGML zaowocowały przygotowaniem no- bieżąco naszą wiedzę. nia funkcjonalnego. Najczęściej użytkownik
wej specyfikacji, w której jawnie zdefiniowa- Popularnym zastosowaniem XML sta- jest postawiony przed koniecznością wybra-
no reguły zapisu dokumentów, pozostawiając ły się również standardy Open Document nia jednej z dwóch metod zarządzania do-
twórcom definicję ich nowego typu w posta- oraz Office Open XML zaimplementowane kumentami.
ci określonych znaczników. W ten sposób w w pakietach biurowych celem zapisywania Podstawową metodą składowania doku-
1997 roku powstaje język XML. plików zawierających arkusze kalkulacyjne, mentów XML w bazie danych jest ich zapisy-

40 SDJ Extra 35
<XML> w praktyce

wanie w pełnej, niezmienionej, tekstowej po- blemem było również wprowadzenie jedno- Powyższe zagadnienia, a także wiele innych
staci w ramach jednej kolumny tabel, której czesnej obsługi języków zapytań, charaktery- związanych ze światami – relacyjnym i XML,
typ dziedziczy po typie tekstowym (na ogół stycznych dla danych relacyjnych (SQL) i do- stanowiły doskonały punkt wyjścia dla nowej
CLOB). Dzięki temu zachowana jest pełna kumentów XML (XQuery i XPath). technologii – pureXML. Jako że możliwości
elastyczność w definiowaniu, modyfikowa-
niu i transformowaniu struktury danych. Z Listing 1. Przygotowanie tabel dla aplikacji
drugiej jednak strony każde odwołanie do
elementów dokumentu wymaga od systemu CREATE TABLE xmlapp.pracownicy(
powtórzenia procesu analizy składniowej, co id bigint generated always as identity,
jest procesem nieefektywnym. Dlatego, w ce- imie varchar(20) not null,
lu poprawienia wydajności, stosuje się struk- nazwisko varchar(25) not null,
tury pomocnicze, których zadaniem jest email varchar(35)
zwiększenie efektywności dostępu do naj- ) IN relData;
częściej wykorzystywanych elementów drze-
wa dokumentów. W dłuższym odcinku czasu ALTER TABLE xmlapp.pracownicy ADD CONSTRAINT prac_pk PRIMARY KEY (id);
mogą one jednak powodować dodatkowy na-
rzut, związany z kosztami ich utrzymywania. CREATE TABLE xmlapp.zadania(
Druga metoda opiera się o dekompozy- id bigint generated always as identity,
cję dokumentów XML do struktury tabel prac_id bigint,
połączonych ze sobą relacjami. Niewątpli- zadanie xml INLINE LENGTH 500 not null
wą jej zaletą jest zapewnienie wysokiej wy- ) COMPRESS YES IN relData LONG IN xmlData;
dajności dostępu do elementów dokumentu
XML. Jednak struktura obiektów powstaje ALTER TABLE xmlapp.zadania ADD CONSTRAINT zad_pk PRIMARY KEY (id);
na bazie przygotowanego wcześniej schema- ALTER TABLE xmlapp.zadania ADD CONSTRAINT zad_fk FOREIGN KEY (prac_id) REFERENCES
tu walidacji dokumentu, co powoduje nie xmlapp.pracownicy;
tylko jej nadmiarowość wobec zapisywanych
danych (np. braku elementów opcjonalnych CREATE TABLE xmlapp.xslt(
w dokumencie XML), ale przede wszystkim id bigint generated always as identity,
brak elastyczności. Każdorazowa zmiana nazwa char(5) not null,
schematu pociąga bowiem za sobą kosztow- dokument xml not null
ną operację modyfikacji i reorganizacji zało- ) IN relData LONG IN xmlData;
żonych tabel.
Wymienione powyżej problemy powo- ALTER TABLE xmlapp.XSLT ADD CONSTRAINT xslt_uq UNIQUE (nazwa);
dują, iż często obszar zainteresowań doty-
czących infrastruktury dla repozytorium
XML rozszerza się na bazy dedykowane.
Wadą tych ostatnich jest jednak brak narzę-
dzi umożliwiających łatwą integrację po-
między nowym medium danych a danymi
relacyjnymi. Tym samym wzrastają koszty
utrzymania spójności i bezpieczeństwa in-
formacji. Indeksy
Dane relacyjne
Rozwiązaniem wysoce pożądanym stała
się zatem integracja dwóch silników – re- ID ... DOC (XML) Indeksy
lacyjnego i hierarchicznego w ramach jed- PR27 ... fragmentów
PR28 ...
nego systemu zarządzania bazami danych. ACC ...
I właśnie taka integracja została zapropono-
wana w 2006 roku przez IBM wraz z wpro-
wadzeniem na rynek serwera danych DB2 w
wersji 9.1. Repozytorium hierarchiczne

Obsługa XML w DB2


Wprowadzenie natywnego wsparcia dla do-
kumentów XML wymagało od zespołu pro-
gramistów DB2 szeregu modyfikacji silnika
baz danych. Podstawowym warunkiem by-
ło dodanie nowego typu danych – XML. Z
punktu widzenia relacyjnych baz, kolumny
tego typu powinny występować w tabelach
zarówno samodzielnie, jak i obok innych ko-
lumn typów standardowych. Z drugiej stro-
ny hierarchiczne struktury dokumentów wy- Rysunek 1. Fizyczna postać drzewa dokumentu dla kolumny typu XML w wersji 9.5 i nowszych.
magały innych zasad zapisu danych, związa- Dla ID równego PR28 dokument jest umieszczony w repozytorium hierarchicznym (not-inline), dla
nych ze specyfikacją XML::DB. Ważnym pro- pozostałych na poziomie rekordów relacyjnych (inline)

www.sdjournal.org 41
Tworzenie aplikacji

najlepiej poznać poprzez praktykę, przygotu- wiście zapisane w postaci danych relacyj- Jak łatwo zauważyć, przygotowanie ba-
jemy elementy prostego szkieletu aplikacji o nych oraz dokumentów XML. Zaczniemy zy danych obsługującej XML nie wyma-
umownej nazwie terminarz. od stworzenia bazy danych o umownej na- ga definiowania żadnych dodatkowych pa-
zwie termdb. W tym celu wykonujemy po- rametrów związanych z dodatkowym ty-
Przygotowanie struktur danych lecenie: pem danych. W tym miejscu należy zwró-
Naszym pierwszym krokiem będzie przy- cić jedynie uwagę na fakt istniejącego ogra-
gotowanie struktur danych, w których bę- create database termdb using codeset UTF-8 niczenia w wersji 9.1 – bazy dla dokumen-
dziemy umieszczać dane aplikacji, oczy- territory pl tów XML musiały używać kodowania ty-

Listing 2. Dokumenty XML – zadania związane z przygotowaniem artykułu

Plik: zadanie-artykul.xml
<?xml version="1.0" encoding="UTF-8"?>
<p:zadanie data="2009-03-05" typ="artykul"
xmlns:p="http://mmolak.pl/Zadanie"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mmolak.pl/Zadanie Zadanie.xsd">
<nazwa>XML w praktyce</nazwa>
<opis>Artykuł przedstawiający możliwości technologii pureXML w
bazie danych DB2 9.7. Autor przedstawi w nim prostą aplikację,
umożliwiającą zarządzanie zadaniami pracowników opisanymi w
dokumentach XML</opis>
<magazyn>SDJ Extra!</magazyn>
</p:zadanie>
Plik: zadanie-spotkanie1.xml
<?xml version="1.0" encoding="UTF-8"?>
<p:zadanie data="2009-03-01" typ="spotkanie"
xmlns:p="http://mmolak.pl/Zadanie"
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation="http://mmolak.pl/Zadanie Zadanie.xsd ">
<nazwa>Spotkanie z osobami technicznymi w kwestii SDJ Extra!</nazwa>
<opis>Opracowanie tematyki artykułów SDJ Extra!</opis>
<godzinaStart>12:00:00</godzinaStart>
<godzinaStop>13:00:00</godzinaStop>
<osoby>Marcin Molak, Artur Wroński</osoby>
</p:zadanie>

Plik: zadanie-spotkanie2.xml
<?xml version="1.0" encoding="UTF-8"?>
<p:zadanie data="2009-03-01" typ="spotkanie"
xmlns:p=http://mmolak.pl/Zadanie
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mmolak.pl/Zadanie Zadanie.xsd ">
<nazwa>Spotkanie z marketingiem w kwestii SDJ Extra!</nazwa>
<opis>Omówienie koncepcji SDJ Extra!</opis>
<godzinaStart>13:00:00</godzinaStart>
<godzinaStop>14:00:00</godzinaStop>
</p:zadanie>

Listing 3. Procedura składowana do publikowania zadań

CREATE PROCEDURE XMLAPP.DODAJZADANIE ( IN PRACOWNIK BIGINT, IN ZADANIE XML, OUT ID_ZADANIA INTEGER )
P1: BEGIN
DECLARE ID_ZADANIA_TMP INTEGER DEFAULT 0;
DECLARE cursor1 CURSOR FOR
SELECT ID FROM NEW TABLE( INSERT INTO XMLAPP.ZADANIA(PRAC_ID,ZADANIE)
VALUES( DODAJZADANIE.PRACOWNIK, DODAJZADANIE.ZADANIE ));
OPEN cursor1;
FETCH cursor1 INTO ID_ZADANIA_TMP ;
SET ID_ZADANIA = ID_ZADANIA_TMP;
CLOSE cursor1;
END P1
@

42 SDJ Extra 35
<XML> w praktyce

pu Unicode. W wersji 9.5 ograniczenie to szar pamięci, w którym umieszczane są ko- dniowo i na jego podstawie zostaje przygo-
zostało jednak zniesione. Z drugiej stro- lejne rekordy tabeli. Ponieważ w ramach jed- towana hierarchiczna struktura. Następnie
ny strona kodowa UTF-8 stała się warto- nej strony musi być zapisany minimum jeden wszystkie nazwy węzłów są słownikowane
ścią domyślną. rekord, jej wielkość determinuje maksymalny i zastępowane wartościami numerycznymi.
Po przygotowaniu bazy danych mogliby- rozmiar rekordu. Zasada ta nie dotyczy jedy- Ostatnim krokiem jest podział drzewa XML
śmy od razu przystąpić do utworzenia tabel z nie kolumn dla dużych obiektów tekstowych na fragmenty. Zostają one zapisane w ramach
kolumnami typu XML. Nim jednak to uczy- (CLOB) i binarnych (BLOB), które są dzielo- kolejnych, specjalnie zindeksowanych stron.
nimy, zapoznajmy się z mechanizmami zapi- ne na kolejne strony. Jak widać, w tym przypadku wielkość stro-
su danych. Dla DB2 najmniejszą porcją aloka- W przypadku repozytorium XML proces ny będzie determinować liczbę generowa-
cji jest tak zwana strona (ang. page). W przy- jest bardziej złożony. Dokument, dostarczo- nych fragmentów drzewa dla danego doku-
padku danych relacyjnych stanowi ona ob- ny w postaci tekstowej, jest analizowany skła- mentu XML.

Listing 4. Schemat XML definiujący nasze zadania

Plik: Zadanie.xsd

<?xml version="1.0" encoding="UTF-8"?>


<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://mmolak.pl/Zadanie">
<xsd:element name="zadanie">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="nazwa" type="xsd:string" minOccurs="1" maxOccurs="1"/>
<xsd:element name="opis" type="xsd:string" minOccurs="1" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="1">
<xsd:sequence>
<xsd:annotation>
<xsd:documentation>Dla spotkań</xsd:documentation>
</xsd:annotation>
<xsd:element name="godzinaStart" type="xsd:time" minOccurs="1"
maxOccurs="1"/>
<xsd:element name="godzinaStop" type="xsd:time" minOccurs="1"
maxOccurs="1"/>
<xsd:element name="osoby" type="xsd:string" minOccurs="0"
maxOccurs="1"/>
</xsd:sequence>
<xsd:sequence>
<xsd:annotation>
<xsd:documentation>Dla artykułów</xsd:documentation>
</xsd:annotation>
<xsd:element name="magazyn" type="xsd:string" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:choice>
</xsd:sequence>
<xsd:attribute name="data" type="xsd:date" use="required"/>
<xsd:attribute name="typ" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>

Listing 5. Wyzwalacz zapewniający automatyczną walidację

CREATE TRIGGER WalidujZadania NO CASCADE


BEFORE INSERT ON xmlapp.zadania
REFERENCING NEW AS nowe
FOR EACH ROW MODE db2sql
WHEN (nowe.zadanie IS NOT VALIDATED ACCORDING TO XMLSCHEMA ID XMLAPP.ZADANIE)
SET nowe.zadanie = XMLVALIDATE(nowe.zadanie ACCORDING TO XMLSCHEMA ID
XMLAPP.ZADANIE);

www.sdjournal.org 43
Tworzenie aplikacji

W wersji 9.5 DB2 rozszerzono możli- stały rozszerzone także na repozytorium ne z nimi pule buforów, posługując się po-
wości silnika baz danych związane z za- hierarchiczne. leceniami:
pisem XML, wprowadzając tryb INLINE Wykorzystajmy zatem powyższą wiedzę
(patrz Rysunek 1). Rozwiązanie to pozwo- w przygotowaniu struktur danych dla na- CREATE BUFFERPOOL bp4k SIZE 10000
liło na zapis małych dokumentów XML na szej aplikacji. Załóżmy, iż w przypadku da- PAGESIZE 4 K;
poziomie rekordu relacyjnego razem z in- nych relacyjnych będziemy ograniczać się CREATE BUFFERPOOL bp16k SIZE 10000
nymi danymi. Z drugiej strony zachowują do przechowywania danych osobowych dla PAGESIZE 16 K;
one w pełni hierarchiczny charakter. Nie- użytkowników aplikacji, tj. imienia, nazwi- CREATE TABLESPACE relData PAGESIZE 4 K
wątpliwymi zaletami trybu INLINE w wer- ska i adresu e-mail oraz automatycznie gene- BUFFERPOOL bp4k NO FILE SYSTEM
sji 9.5 są: zmniejszenie operacji odczytu i rowanych identyfikatorów rekordów. Struk- CACHING;
zapisu oraz wykorzystanie istniejących w tury hierarchiczne będą natomiast przecho- CREATE TABLESPACE xmlData PAGESIZE 16 K
DB2 mechanizmów głębokiej kompresji wywać opis zadań do wykonania, a także re- BUFFERPOOL bp16k NO FILE SYSTEM
dla danych XML. Warto jednak dodać, iż guły transformowania dokumentów. Przy- CACHING;
w przypadku wersji 9.7 mechanizmy zo- gotujmy zatem przestrzenie tabel i związa-
Mając na uwadze wielkości zapisywanych
Listing 6. Nowy schemat XML definiujący nasze zadania informacji dla danych relacyjnych, użyje-
my stron o długości 4KB, a dla dokumen-
Plik: Zadanie1.xsd tów XML – 16KB, które zapewnią nam wy-
dajną obsługę danych. Kolejnymi krokami w
<?xml version="1.0" encoding="UTF-8"?> stronę optymalizacji było wyłączenie bufo-
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" rowania na poziomie systemu plików, a tak-
targetNamespace="http://mmolak.pl/Zadanie"> że określenie większego rozmiaru puli bufo-
<xsd:element name="zadanie"> rów przy ich tworzeniu.
<xsd:complexType> Utwórzmy zatem tabele dla naszej aplikacji.
<xsd:sequence> Posługując się poleceniami z Listingu 1, two-
<xsd:element name="nazwa" type="xsd:string" minOccurs="1" maxOccurs="1"/> rzymy kolejno tabele z informacjami o użyt-
<xsd:element name="opis" type="xsd:string" minOccurs="1" maxOccurs="1"/> kownikach systemu (PRACOWNICY), ich zada-
<xsd:choice minOccurs="0" maxOccurs="1"> niach (ZADANIA) oraz dla reguł transforma-
<xsd:sequence> cji (XSLT). W przypadku dokumentów XML
<xsd:annotation> przechowujących zadania wykorzystujemy
<xsd:documentation>Dla spotkań</xsd:documentation> tryb INLINE, pozwalając, aby dokumenty o
</xsd:annotation> wielkości do 500 bajtów były przechowywa-
<xsd:element name="godzinaStart" type="xsd:time" minOccurs="1" ne na poziomie rekordu. Dodatkowo dla tabeli
maxOccurs="1"/> zadań uruchamiamy mechanizm kompresji.
<xsd:element name="godzinaStop" type="xsd:time" minOccurs="1" Na koniec, korzystając z dobrych prak-
maxOccurs="1"/> tyk IBM, optymalizujemy konfigurację ba-
<xsd:element name="osoby" type="xsd:string" minOccurs="0" zy danych, zmieniając wartości parametrów
maxOccurs="1"/> APPLHEAPSZ i (CATALOGCACHE_SZ), używa-
</xsd:sequence> jąc poleceń:
<xsd:sequence>
<xsd:annotation> UPDATE DB CFG USING APPLHEAPSZ 40000
<xsd:documentation>Dla artykułów</xsd:documentation> AUTOMATIC;
</xsd:annotation> UPDATE DB CFG USING CATALOGCACHE_SZ
<xsd:element name="magazyn" type="xsd:string" minOccurs="1" 100000;
maxOccurs="1"/>
</xsd:sequence> W ten sposób zakończyliśmy pierwszy etap
<xsd:sequence> w przygotowaniu szkieletu aplikacji.
<xsd:annotation>
<xsd:documentation>Dla telefonów</xsd:documentation> Umieszczanie dokumentów
</xsd:annotation> XML w bazie danych
<xsd:element name="godzina" type="xsd:time" minOccurs="1" Nadszedł czas na uzupełnienie naszej bazy
maxOccurs="1"/> danych. Naszą tabelę użytkowników syste-
<xsd:element name="rozmowca" type="xsd:string" minOccurs="0" mu zasilimy w prosty sposób, posługując się
maxOccurs="1"/> poleceniem:
</xsd:sequence>
</xsd:choice> insert into XMLAPP.PRACOWNICY(imie,
</xsd:sequence> nazwisko, email) values
<xsd:attribute name="data" type="xsd:date" use="required"/> ('Marcin', 'Molak',
<xsd:attribute name="typ" type="xsd:string" use="required"/> 'Marcin.Molak@pl.ibm.com'),
</xsd:complexType> ('Artur', 'Wroński',
</xsd:element> 'artur.wronski@pl.ibm.com');
</xsd:schema>
Czas na przygotowanie zadań. W naszym
wypadku będą to informacje dotyczące pra-

44 SDJ Extra 35
<XML> w praktyce

cy nad niniejszym artykułem – czyli zdefi- komunikat z informacją o nieprawidłowym ku DB2, w ślad za standardami, jest to XML
niowanie jego tematyki, oraz spotkania ro- dokumencie. Schema.
bocze. Treść kolejnych dokumentów przed- Drugim poziomem poprawności jest po- Przykładem dokumentu XML Schema
stawia Listing 2. prawność strukturalna wymagająca zdefinio- dla zadań wstawianych przez naszą aplika-
Jak łatwo zauważyć, każde z zadań po- wania dodatkowych reguł walidacji. Reguły cję jest Listing 4. Widzimy, iż precyzuje on
siada pewne stałe elementy, takie jak atry- takie gwarantują nam poprawność informa- kolejność występowania elementów, wyróż-
buty data i typ oraz elementy nazwa i opis. cji w kontekście biznesowym, jednak wyma- nia elementy wspólne (nazwa, opis), a tak-
Jednak każdy z typów zadań posiada ele- gają użycia specjalnego języka. W przypad- że elementy charakterystyczne dla danego
menty unikalne dla siebie. Co więcej, nie-
które z nich są opcjonalne. Możemy zatem Listing 7. Zapytanie SQL/XML z automatycznym rzutowaniem
korzystać w pełni z uniwersalności języ-
ka XML. select z.id, z.prac_id, t.*
Aby każdy z użytkowników mógł wy- from xmlapp.zadania z,
godnie dodać zadanie, przygotujemy pro- xmltable (
cedurę o nazwie DODAJZADANIE, w której XMLNAMESPACES('http://mmolak.pl/Zadanie' AS "p"),
każdy z użytkowników jako parametry wej- '$ZADANIE/p:zadanie'
ściowe poda swoje id oraz dokument XML COLUMNS
z opisem zadania. W wyniku zaś otrzyma dzien_zadania DATE PATH './@data',
id, które otrzymało w bazie wstawiane za- nazwa VARCHAR(3200) PATH './nazwa',
danie. Analiza ciała procedury (patrz Li- opis VARCHAR(3200) PATH './opis'
sting 3) pokazuje, iż cała operacja wsta- ) as t
wiania ogranicza się do przekazania war- WHERE
tości zmiennych wejściowych i użycia kla- xmlexists(
sycznej komendy INSERT. Wywołanie pro- 'declare namespace p="http://mmolak.pl/Zadanie";
cedury sprowadza się zaś do wykonania ko- $ZADANIE/p:zadanie[@typ="spotkanie"]')
mendy: ORDER BY z.prac_id;

CALL XMLAPP.DODAJZADANIE (1, Listing 8. Użycie funkcji XMLGROUP


XMLPARSE(DOCUMENT
'treść naszego dokumentu XML’),?); SELECT XMLGROUP( IMIE AS "Imie",
NAZWISKO AS "Nazwisko",
gdzie 1 jest numerem wybranego pracow- EMAIL AS "E-mail",
nika (w naszym przykładzie Artura Wroń- OPTION ROW "Pracownik" ROOT "Pracownicy")
skiego). AS Lista
W ten sposób przygotowana procedura FROM XMLAPP.PRACOWNICY;
może być wywołana z dowolnego języka pro-
gramowania. Możliwe jest zatem przygoto- LISTA
wanie aplikacji, która zadanie wczyta z pliku ----------
i zapisze je do bazy danych dla danego użyt- <Pracownicy>
kownika. Funkcjonalność taką oferuje rów- <Pracownik>
nież narzędzie Data Studio Developer, wspo- <Imie>Marcin</Imie>
magające proces przygotowania aplikacji ba- <Nazwisko>Molak</Nazwisko>
zodanowych. <E-mail>Marcin.Molak@pl.ibm.com</E-mail>
My w ramach ćwiczenia dodajmy infor- </Pracownik>
macje o spotkaniach do obydwu pracowni- <Pracownik>
ków, a zadanie typu artykuł jedynie do je- <Imie>Artur</Imie>
go autora. <Nazwisko>Wroński</Nazwisko>
<E-mail>artur.wronski@pl.ibm.com</E-mail>
Walidacja danych </Pracownik>
Jednak czy w ten sposób przygotowane roz- </Pracownicy>
wiązanie zapewni nam poprawność wpro-
wadzonych przez użytkownika danych? Aby
Listing 9. Wyrażenie FLWOR zawracające listę spotkań
odpowiedzieć sobie na to pytanie, musimy
uszczegółowić zagadnienie poprawności do-
kumentów XML. xquery
Podstawowym poziomem poprawności declare default element namespace 'http://mmolak.pl/Zadanie';
dokumentów jest poprawność składniowa. <spotkania>{
Nakłada ona na dostawcę dokumentu szereg for $i in db2-fn:sqlquery("SELECT ZADANIE FROM XMLAPP.ZADANIA WHERE prac_id=1")
zasad budowy określonych w ramach spe- let $x := $i/zadanie
cyfikacji. Niespełnienie ich powoduje błę- where $x/@typ="spotkanie"
dy analizatora składniowego i brak możli- order by $x/@data, $x/godzinaStart
wości opracowania hierarchicznej struktury return $x
w bazie. W takich sytuacjach próba dodania }</spotkania>
dokumentu nie powiedzie się, a DB2 zgłosi

www.sdjournal.org 45
Tworzenie aplikacji

typu zadań. Pozwala także na określenie ty- Od tej chwili możliwa jest walidacja doku- Po ponownym wdrożeniu procedury struk-
pu danych oraz ilości elementów o danej na- mentu XML. Zmodyfikujmy więc nieco tura każdego nowego dokumentu będzie
zwie w ramach dokumentu XML. Podob- kod naszej procedury, wykorzystując funk- sprawdzana na podstawie schematu, które-
ne zasady dotyczą również atrybutów dane- cję walidacji dokumentów – XMLVALIDATE. go nazwę w bazie danych określiliśmy w mo-
go elementu. Dotychczasowe polecenie INSERT zastępuje- mencie rejestracji.
Aby zarejestrować schemat XML, wykonu- my następującym: Jednak w takim wypadku gwarancja popraw-
jemy polecenie: ności dokumentu jest zapewniona lokalnie dla
INSERT INTO XMLAPP.ZADANIA( naszej procedury składowanej. W DB2 istnieją
REGISTER XMLSCHEMA PRAC_ID, ZADANIE ) jednak mechanizmy, które pozwalają nam na za-
'http://mmolak.pl/Zadanie' VALUES(DODAJZADANIE.PRACOWNIK, pewnienie strukturalnej poprawności na pozio-
FROM XMLVALIDATE(DODAJZADANIE.ZADANIE mie globalnym. Pierwszy z nich stanowi waru-
'file:////sciezka_do_pliku\Zadanie.xsd' ACCORDING TO XMLSCHEMA nek spójności (ang. constraint), w którym doko-
AS XMLAPP.ZADANIE COMPLETE; ID XMLAPP.ZADANIE) ) nujemy sprawdzenia, czy walidacja danego do-
kumentu została wykonana w oparciu o sche-
Listing 10. Procedura dodająca nowe osoby do spotkania mat XML. Aby założyć taki warunek dla naszej
tabeli zadań, posługujemy się poleceniem:
CREATE PROCEDURE XMLAPP.DODAJOSOBY ( IN ZAD_ID BIGINT, IN OSOBY VARCHAR(255) )
P1: BEGIN ALTER TABLE xmlapp.zadania
DECLARE istnieja INT; ADD CONSTRAINT wZadan
DECLARE cursor1 CURSOR FOR CHECK(zadanie IS VALIDATED ACCORDING TO
SELECT COUNT(id) FROM xmlapp.zadania z XMLSCHEMA ID XMLAPP.ZADANIE);
WHERE z.id=dodajosoby.zad_id
AND XMLEXISTS( Należy jedynie zauważyć, iż mechanizm ten nie
'declare namespace p="http://mmolak.pl/Zadanie"; powoduje automatycznej walidacji dokumen-
$ZADANIE/p:zadanie/osoby' tu. Aby zapewnić taką funkcjonalność, od wer-
); sji 9.5 możemy posłużyć się wyzwalaczem (ang.
OPEN cursor1; trigger), który przed zapisaniem dokumentu do
FETCH cursor1 INTO istnieja; bazy dokona sprawdzenia poprawności struk-
CLOSE cursor1; turalnej. Kod takiego wyzwalacza dla naszej
aplikacji przedstawiono na Listingu 5.
IF istnieja = 0 THEN Nasze aplikacje podlegają jednak ciągłym
UPDATE xmlapp.zadania modyfikacjom wynikającym z nowych wy-
SET zadanie = XMLQUERY( magań biznesowych. Nie trudno wyobrazić
'declare namespace p="http://mmolak.pl/Zadanie"; sobie sytuację, w której ktoś chciałby dodać
copy $new := $ZADANIE do listy swoich zadań wykonywanie telefo-
modify do insert <osoby>{$osoby}</osoby> nów. W takiej sytuacji istniejący schemat
after $new/p:zadanie/godzinaStop mógłby ograniczyć możliwość wprowadza-
return $new' nia informacji tego typu. Odpowiedzią na
PASSING dodajosoby.osoby AS "osoby" te zagadnienie jest wprowadzona w wersji
) WHERE id=dodajosoby.zad_id 9.5 ewolucja schematów XML.
AND XMLEXISTS( Aby skorzystać z tego mechanizmu, przy-
'declare namespace p="http://mmolak.pl/Zadanie"; gotowujemy nowy schemat (Listing 6) i reje-
$ZADANIE/p:zadanie[@typ="spotkanie"]' strujemy go w bazie danych poleceniem:
);
REGISTER XMLSCHEMA
ELSE 'http://mmolak.pl/Zadanie1'
UPDATE xmlapp.zadania FROM
SET zadanie = XMLQUERY( 'file:////sciezka_do_pliku\Zadanie1.xsd'
'declare namespace p="http://mmolak.pl/Zadanie"; AS XMLAPP.ZADANIE1 COMPLETE;
copy $new := $ZADANIE
modify do replace value of $new/p:zadanie/osoby Ostatnim krokiem jest aktualizacja schema-
with $ZADANIE/p:zadanie/osoby+ " "+$osoby tu poprzez wywołanie procedury składowa-
return $new' nej XSR _ UPDATE:
PASSING dodajosoby.osoby AS "osoby"
) WHERE id=dodajosoby.zad_id CALL SYSPROC.XSR_UPDATE('XMLAPP','ZADANIE'
AND XMLEXISTS( ,'XMLAPP','ZADANIE1',0);
'declare namespace p="http://mmolak.pl/Zadanie";
$ZADANIE/p:zadanie[@typ="spotkanie"]' Od tego momentu nasze dokumenty będą
); walidowane nowym schematem. Należy jed-
END IF; nak zwrócić uwagę na pewne ograniczenia
END P1 takiego podejścia. Nowy schemat nie może
@ bowiem wprowadzić zmian, które zawiera-
łyby reguły niespełniane przez istniejące już
w bazie dokumenty XML. Niemożliwe są

46 SDJ Extra 35
<XML> w praktyce

zatem zmiany typu danych dla elementów ło jawne rzutowanie parametrów między dia- użycie funkcji XMLGROUP z uzyskanym
czy dodawanie nowych, obowiązkowych lektami za pomocą klauzuli PASSING defi- wynikiem.
elementów czy atrybutów. niującej zmienną SQL i odpowiadający jej alias Dla języka XQuery integracja z SQL została
XML. W wersji 9.5 wprowadzono automa- oparta na dwóch funkcjach: db2-fn:xmlcolumn
Nowy widok na dane tyczne rzutowanie, minimalizując użycie klau- oraz db2-fb:sqlquery. Pozwoliły one na mapo-
Wprowadzenie obsługi dokumentów XML zuli do specyficznych przypadków. Przykład wanie kolumny typu XML stanowiącej ele-
wymagało również implementacji nowego automatycznego rzutowania ilustruje Listing ment tabeli bądź wynik zapytania SQL na ko-
interfejsu dostępu do danych uwzględniają- 7, w którym nazwa kolumny XML jest użyta lekcje XML. Umożliwiło to przetwarzanie do-
cego ich hierarchiczną strukturę i pozwalają- w wyrażeniach XQuery jako nazwa zmiennej. kumentów w ich oryginalnej postaci do za-
cego na jej łatwe przeszukiwanie. W tej mate- Kod ten obrazuje jednocześnie prostą de- danego zbioru wynikowego za pomocą wyra-
rii naturalnym wyborem stał się język XQu- kompozycję dokumentów XML do struk- żeń. Najczęściej stosowanym jest wyrażenie
ery. Z drugiej strony należało zachować pełną tur relacyjnych na bazie określonych węzłów FLWOR. Jego definicję stanowią człony: for
możliwość dostępu do danych z poziomu ję- drzewa. Przy okazji warto zwrócić uwagę na – umożliwiający iteracje po elementach zbioru,
zyka SQL. Mając jednak na uwadze jego ogra- funkcję XMLEXISTS, która stanowi właściwy let – definiujący zmienne, where – określający
niczenia związane z przetwarzaniem doku- sposób definiowania warunków wyboru do- warunki brzegowe, order – sortujący zbiór, oraz
mentów XML, IBM zdecydował się na imple- kumentów XML z kolekcji. return – zwracający zbiór wynikowy. Przykłado-
mentację specyfikacji SQL/XML wzbogacają- Język SQL/XML pozwala również na bu- we użycie ilustruje Listing 9. Na podstawie ze-
cej składnie o nowe funkcje pozwalające na dowanie dokumentów XML na bazie da- stawu zadań pracownika z id równym 1 genero-
mapowanie danych. nych relacyjnych. W wersji 9.1 zrealizowa- wany jest dokument XML zawierający informa-
Bardzo ważnym elementem dla modelu hy- nie tego celu wymuszało na programistach cje o kolejnych spotkaniach.
brydowego stała się jednak nie tylko imple- zastosowanie szeregu funkcji, takich jak:
mentacja obu języków, ale także możliwości XMLDOCUMENT, XMLELEMENT czy XMLAGG. W Modyfikacja dokumentów XML
ich wzajemnej integracji. Dzięki temu możli- wersji 9.5 do SQL/XML dołączono XML- Z punktu widzenia aplikacji ważnym ele-
we stało się definiowanie zapytań SQL z ele- ROW zapisującą rekord w postaci dokumen- mentem w obsłudze danych jest jednak nie
mentami XQuery, a także zapytań XQuery z tu XML, oraz XMLGROUP budującą doku- tylko możliwość ich przeszukiwania, ale rów-
osadzonymi poleceniami SQL. W wersji 9.1 ment XML na podstawie zbioru rekordów. nież modyfikacji. W przypadku wersji 9.1
dla wielu funkcji SQL/XML wymagane by- Na Listingu 8 przedstawiono przykładowe funkcjonalność taka nie stanowiła elementu

Listing 11. Reguły transformujące dokument XML do formatu HTML


<td><xsl:value-of select="./opis" /></td>
<?xml version="1.0" encoding="UTF-8"?> </tr>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/ </xsl:template>
Transform" </xsl:stylesheet>
xmlns:p="http://mmolak.pl/Zadanie"
xmlns:xsi="http://www.w3.org/2001/ Listing 12. Procedura zwracająca raport z zadaniami pracownika
XMLSchema-instance"
version="1.0" CREATE PROCEDURE XMLAPP.POKAZRAPORT ( IN ID_PRAC BIGINT, IN TYP
xmlns:xalan="http://xml.apache.org/xslt"> CHAR(5) DEFAULT 'html ')
<xsl:template match="zadania"> DYNAMIC RESULT SETS 1
<html> P1: BEGIN
<head> DECLARE xsltDoc XML;
<title>Zadania dla pracownika</title> DECLARE cursor CURSOR FOR
</head> SELECT DOKUMENT FROM XMLAPP.XSLT WHERE
<body> NAZWA=POKAZRAPORT.TYP;
<table> DECLARE cursor1 CURSOR WITH RETURN FOR
<th> WITH wynik(dokument) AS (
<td>Data</td> SELECT XMLELEMENT(
<td>Typ</td> NAME "zadania",
<td>Nazwa zadania</td> XMLAGG(
<td>Opis</td> ZADANIE
</th> )
<xsl:apply-templates /> ) FROM XMLAPP.ZADANIA WHERE PRAC_ID =
</table> POKAZRAPORT.ID_PRAC
</body> )
</html> SELECT xsltransform(dokument USING xsltDoc AS clob(10M) )
</xsl:template> FROM wynik;
<xsl:template match="p:zadanie"
xsi:schemaLocation="http://mmolak.pl/Zadanie OPEN cursor;
Zadanie.xsd"> FETCH cursor INTO xsltDoc;
<tr> CLOSE cursor;
<td><xsl:value-of select="./@data" /></td> OPEN cursor1;
<td><xsl:value-of select="./@typ" /></td> END P1
<td><xsl:value-of select="./nazwa" /></td> @

www.sdjournal.org 47
Tworzenie aplikacji

motoru bazy danych. Można ją było osiągnąć Analizując Listing 10, widzimy, iż proces prze- Wyobraźmy sobie, iż z naszej bazy za-
jedynie poprzez dodanie upublicznionych biega dwuetapowo. Na wstępie sprawdzane jest dań chcemy wydrukować raport w formacie
procedur składowanych bądź własne imple- występowanie elementu osoby w drzewie doku- HTML. Raport ten ma zawierać tabelkę z pre-
mentacje na poziomie warstwy aplikacji. mentu XML. Jest to zabezpieczenie przed pró- zentacją daty, typu, nazwy i opisu kolejnych
Wraz z wprowadzeniem na rynek wersji 9.5 bą modyfikacji nieistniejącego elementu, która zadań dla danej osoby. Ponieważ reguły trans-
w motorze bazy danych rozszerzono obsługę zakończyłaby się błędem. W przypadku braku formujące są zapisane w dokumentach XML,
składni języka XQuery o klauzulę transform co- węzła jest on dodawany w pierwszej instrukcji możemy je zapisać w tabeli DB2. W tym ce-
py, pozwalającą na modyfikowanie dokumen- UPDATE. Mając na uwadze poprawność struk- lu skorzystamy z przygotowanej na początku
tu XML. Użytkownikom umożliwiono: turalną (opisaną w schemacie XML), element artykułu tabeli XSLT. Arkusz transformujący
osoby zostaje umieszczony po elemencie godzi- nasze dokumenty do strony HTML (patrz Li-
• zmianę wartości węzła; naStop. Jeśli węzeł istnieje, jego wartość jest za- sting 11) dodajemy poleceniem:
• zastąpienie węzła nowym; stępowana nową, stanowiącą konkatenację ist-
• dodanie nowego węzła z uwzględnie- niejącego i wprowadzonego przez użytkowni- INSERT INTO XMLAPP.XSLT(NAZWA,DOKUMENT)
niem jego położenia w dokumencie; ka łańcucha znaków. Drugim zabezpieczeniem VALUES (‘html’,
• skasowanie węzła; przed nieprawidłowym działaniem użytkow- XMLPARSE(DOCUMENT 'treść dokumentu
• zmianę nazwy węzła; nika jest również wykorzystanie warunku defi- XSLT’));
• jednoczesną modyfikację wielu węzłów niującego typ zadania.
w ramach jednej instrukcji UPDATE; Kolejny krok stanowi przygotowanie procedu-
• jednoczesną modyfikację wielu doku- Transformacja dokumentów XML ry POKAZRAPORT (Listing 12), która dla danego
mentów w ramach jednej instrukcji Kolejną funkcjonalnością, wprowadzoną w id pracownika oraz typu transformaty zwró-
UPDATE. wersji 9.5, jest możliwość transformacji doku- ci nam w wyniku raport. Przeanalizujmy jej
mentów XML do innych formatów,takich jak działanie. W pierwszym kroku do zmien-
Aby zademonstrować możliwość aktualiza- XHTML, Open Document czy Open XML. Za nej typu XML wczytywany jest wybrany ar-
cji dokumentów XML, stworzymy procedu- jej realizację odpowiada funkcja XSLTRANSFORM kusz transformat. Następnie na bazie wszyst-
rę DODAJOSOBY, która pozwoli użytkowni- wykorzystująca dokumenty z regułami zapisa- kich dokumentów zawierających zadania jest
kowi dla danego spotkania dodać nowe osoby. nymi w języku XSLT. bazującym na XML. utworzony przy pomocy funkcji XMLELEMENT
i XMLAGG jeden dokument XML z głównym
węzłem zadania. Ten zaś jest transformowa-
Rozbudowana funkcjonalność XML przy zachowaniu wysokiej
ny przez funkcje XSLTRANSFORM.
wydajności bazy danych W przykładzie tym warto również zwrócić
Stale rosnący wolumen danych powoduje, iż firmy szukają nie tylko rozwiązań oferujących
rozbudowaną funkcjonalność, ale przede wszystkim gwarantujących zachowanie stałego
uwagę na definicję drugiego parametru wej-
poziomu wydajności. ściowego, w której określono jego wartość do-
Wykorzystując test TPoX (Transaction Processing over XML), firmy IBM i Intel sprawdziły wydaj- myślną. Jest to jedna z nowych funkcjonalności
ność bazy DB2 dla 350 milionów dokumentów XML o łącznej wielkości 1TB. Symulowano rze- wprowadzonych w DB2 9.7. Zatem wywołanie
czywiste obciążenie opierające się w 70% na przeszukiwaniu dokumentów i 30% na opera- dla transformaty HTML będzie miało postać:
cjach dodawania, kasowania oraz modyfikowania.
Środowisko testowe wykorzystywało 64 bitową platformę Linux z zainstalowanym serwerem
CALL XMLAPP.POKAZRAPORT(1);
danych DB2 9.5 z 2 pakietem poprawek. Serwer był wyposażony w 4 sześciordzeniowe pro-
cesory z rodziny Intel Xeon 7400 2.67GHz, 64GB pamięci RAM i 137 dysków. Analizowana ba-
za wykorzystywała strony o wielkości 16KB, a także mechanizmy automatycznego strojenia, Podsumowanie
zarządzania pamięcią i rozszerzania obszaru dyskowego. Tabele dokumentów XML wykorzy- Wraz z wejściem na rynek wersji 9.1 przed pro-
stywały tryb INLINE i kompresję danych. gramistami DB2 otworzyło się wiele nowych
Wynik wyprzedził wszystkie oczekiwania. Po załadowaniu dane zajmowały powierzchnię
440,2 GB, wskazując maksymalny poziom kompresji na poziomie 64%. Natomiast w teście
możliwości. Możliwości związanych ze składo-
obciążenia baza osiągnęła liczbę 6763 transakcji na sekundę. waniem, przetwarzaniem i transformowaniem
Więcej o teście pod adresem: tpox.sourceforge.net/tpoxdata_files/Taming_1TB_of_XML_Da- dokumentów XML stanowiących standard w
ta_with_DB2+Intel.pdf. wielu współczesnych implementacjach.
Niniejszy artykuł stanowi początek drogi do
poznania technologii pureXML. Przed czytel-
TPoX Transactions per Seckond (TTPS)
8,000 nikiem pozostaje jeszcze wiele ciekawych za-
6,763 TTPS at 95% CPU gadnień, takich jak wykorzystanie XML w śro-
7,000 dowiskach partycjonowanych, wielowymiaro-
6,000 wych klastrach MDC oraz strukturach anali-
tycznych (OLAP) czy dekompozycja XML na
5,000
potrzeby przepływów danych ETL.
TTPS

4,000

3,000
MARCIN MOLAK
Specjalista w zakresie zarządzania danymi w
2,000 TTPS dziale oprogramowania IBM Polska i ambasa-
dor programu inicjatywy akademickiej IBM. Od-
1,000
powiada za wsparcie serwerów danych DB2 i so-
0 lidDB oraz narzędzi z rodzin Optim i Data Stu-
0 50 100 150 200 250 dio. Absolwent Wydziału Fizyki Politechniki War-
Number of concurrent users szawskiej. Prywatnie pasjonat nowych technolo-
gii oraz miłośnik fantastyki.

48 SDJ Extra 35
Opis CD

DB2 9.7 Discovery Kit


I BM DB2 9.7 Discovery Kit stanowi bogaty zestaw materiałów technicznych, pozwalających na poszerzenie wiedzy w zakresie ser-
wera baz danych DB2.
Na płycie znajdują się książki, artykuły, prezentacje oraz filmy instruktażowe dedykowane administratorom baz danych, dewelope-
rom aplikacji oraz architektom IT. Nowe funkcjonalności serwera danych możesz przetestować dzięki załączonym: wersji testowej DB2
Enterprise Edition oraz przygotowanemu środowisku wirtualnemu – DB2 Enterprise Virtual Appliance.
Materiały obejmują również informacje o ekosystemie DB2 – hurtowni InfoSphere Warehouse, rodzinie narzędzi Optim oraz bazie
danych, rezydującej w pamięci – solidDB. Znajdziesz tam również materiały na temat ścieżek certyfikacyjnych oraz programów part-
nerskich i akademickich.

www.sdjournal.org 49
Tworzenie aplikacji

Poziomy izolacji w DB2


Artur Wroński, Krzysztof Mikołajewski
Deweloperom oprogramowania, którzy dopiero rozpoczynają
korzystanie z DB2, stosunkowo dużą trudność sprawia zrozumienie
i poprawne wykorzystanie poziomów izolacji, tak by zapewnić
maksymalną współbieżność aplikacji. W tym artykule omówimy te
mechanizmy, co, mamy nadzieję, pozwoli tworzyć bardziej wydajne
aplikacje.

P
rzybliżymy także optymistyczne oznacza, że na blokady dla wszystkich apli- Poziomy izolacji
blokowanie rekordów (ang. optimi- kacji łączących się do tej bazy danych jest Liczba blokad, którą serwer zaalokuje dla da-
stics locking) wprowadzone w wer- przeznaczone 100 x 4 KB = 400 KB pa- nej aplikacji, zależy nie tylko od wykonywa-
sji 9.5 oraz nowy tryb izolacji wykorzystu- mięci, z czego pojedyncza aplikacja łączą- nych modyfikacji danych. Zapytania także
jący wersjonowanie rekordu wprowadzony ca się do bazy danych może maksymalnie mogą zakładać blokady na rekordach, a licz-
w wersji 9.7. wykorzystać 22%, czyli 88 KB. Do opisu ba blokad zależy od wybranego poziomu izo-
jednej blokady w instancji 32 bitowej DB2 lacji.
Obsługa blokad potrzebne są 32 bajty, natomiast w instan- DB2 obsługuje następujące poziomy izo-
DB2 przechowuje informacje o blokadach cji 64 bitowej jedna blokada zajmuje 72 baj- lacji:
w pamięci operacyjnej w tzw. stercie blo- ty. Można łatwo obliczyć, jaka jest maksy-
kad (ang. lock heap). Każda baza danych malna liczba blokad dostępna dla pojedyn- • UNCOMMITTED READ (UR) – od-
posiada własną stertę blokad, a jej rozmiar czej aplikacji przy takiej konfiguracji ba- czyt niezatwierdzonych danych;
określony jest przez parametr bazy LOC- zy danych: • CURSOR STABILITY (CS) – stabilność
KLIST. Jeśli aplikacja potrzebuje zabloko- kursora;
wać dany rekord, wtedy informacja o bloka- • 11378 blokad w 32 bitowej instancji; • READ STABILITY (RS) – stabilność
dzie odkładana jest na liście blokad. Bloka- • 5689 blokad w 64 bitowej instancji. odczytu;
dy są zakładane nie tylko dla każdego zmo- • REPEATABLE READ (RR) – odczyt
dyfikowanego rekordu, ale także dla odczy- Domyślnie DB2 przydziela blokady na po- powtarzalny.
tanych wierszy, zależnie od poziomu izola- ziomie pojedynczego rekordu. Jeśli aplika-
cji zapytania. cja wykorzysta wszystkie przysługujące jej Poziomy izolacji mają za zadanie odizolo-
W konfiguracji baz danych DB2 są dwa blokady, wtedy dalsza kontynuacja pracy wać wpływ innych aplikacji na przepro-
parametry regulujące liczbę blokad, które aplikacji możliwa jest dopiero po wykona- wadzane operacje na bazie danych, tak by
może otrzymać pojedyncza aplikacja. Są niu tzw. eskalacji blokad. Mechanizm ten zapewnić spójność wykonywanych opera-
to LOCKLIST i MAXLOCKS. Pierwszy z nich wyzwalany jest automatycznie i powodu- cji. Każdy z czterech dostępnych pozio-
został już przedstawiony i definiuje ob- je, że serwer DB2 na czas trwania transak- mów izolacji oferuje różny poziom odse-
szar pamięci przeznaczony do przechowy- cji zamienia wiele blokad na poziomie re- parowania wpływu działania innych apli-
wania informacji o blokadach dla wszyst- kordu jedną blokadą na poziomie tabeli. Ta- kacji. Działanie poziomów izolacji zapre-
kich aplikacji łączących się do bazy da- kie zachowanie pozwala zmniejszyć liczbę zentujemy na prostej tabeli rezerwacje,
nych. Drugi z nich mówi, jaka część te- blokad używanych przez aplikację, ale jed- którą utworzyliśmy następującą instruk-
go obszaru może być maksymalnie przy- nocześnie ogranicza współbieżność dostę- cją SQL:
dzielona dla pojedynczej aplikacji. Para- pu do tabeli dla innych aplikacji. Inne apli-
metr LOCKLIST wyrażony jest w 4 kilobaj- kacje będą musiały czekać aż sesja będąca create table rezerwacje (
towych stronach, natomiast MAXLOCKS w przyczyną eskalacji blokad zatwierdzi bądź data date,
procentach. wycofa bieżącą transakcję. Zadaniem admi- dzien char(13),
We wcześniejszych wersjach DB2 (do nistratora baz danych DB2 w wersji 8 było id_osoby int
wersji 8 włącznie) do obowiązków admini- dobranie tych parametrów w zależności od )
stratora należało ustawienie wartości tych liczby wierszy w tabelach, dostępnej pamię-
parametrów, tak by zarezerwować pamięć ci operacyjnej oraz rozmiaru transakcji, tak Tabelę REZERWACJE wypełnimy datami z za-
dla odpowiedniej liczby blokad. Ustawie- aby eskalacja blokad nie występowała. Od kresu od stycznia 2009 do grudnia 2010
nie tych parametrów na następujące war- wersji DB2 9 dla nowo tworzonych baz da- przy pomocy złożonej instrukcji SQL poka-
tości: nych te dwa parametry domyślnie ustawio- zanej na Listingu 1 (wywołanie: db2 –td@ -
ne są na wartość AUTOMATIC i serwer f plik _ z _ instrukcją ). Poniżej przedsta-
• LOCKLIST = 100; DB2 dynamicznie ustawia te dwa parame- wiliśmy kilka początkowych rekordów zała-
• MAXLOCKS = 22. try w zależności od potrzeb. dowanych do tej tabeli:

50 SDJ Extra 35
Poziomy izolacji w DB2

DATA DZIEN ID_OSOBY Jak widać, poziom izolacji UR odczytuje nie- sprawdzić domyślny poziom izolacji w bie-
---------- ------------- ----------- zatwierdzone dane i dlatego wymaga uważ- żącej sesji:
2009-01-01 czwartek - nego stosowania. Aplikacja modyfikująca re-
2009-01-02 piątek - kord może wycofać zmiany (ROLLBACK), co db2 values current isolation
2009-01-03 sobota - może oznaczać, że druga sesja odczyta war-
2009-01-04 niedziela - tość, która tak naprawdę nigdy nie została 1
trwale zapisana w bazie danych. --
Pole ID _ OSOBY początkowo zawiera warto- Poziom izolacji można także ustawić in- UR
ści NULL, które będziemy sukcesywnie wy- strukcją SET ISOLATION:
pełniać identyfikatorami osób dokonujących 1 record(s) selected.
rezerwacji. db2 set isolation = UR
CURSOR STABILITY
UNCOMMITTED READ Po wykonaniu powyższej instrukcji Z definicji poziom izolacji CURSOR STABILITY
Poziom izolacji UNCOMMITTED READ (UR) nie wszystkie instrukcje SQL, dla których (CS) czyta wyłącznie zatwierdzone dane. Je-
korzysta z blokad i odczytuje zawsze bieżą- jawnie nie podaliśmy poziomu izolacji, bę- śli w drugiej sesji wykonam to samo zapyta-
cą wartość. Zademonstrujemy działanie te- dą stosowały poziom UR. Sięgając do reje- nie z tym poziomem izolacji, wtedy mam
go poziomu izolacji, uruchamiając dwie se- stru CURRENT ISOLATION, możemy gwarancję, że nie odczytamy już niezatwier-
sje interpretera poleceń DB2 podłączone
do wybranej bazy danych. Sesje interprete- Listing 1. Instrukcja ładująca tabelę rezerwacje
ra uruchomimy z wyłączonym automatycz-
nym zatwierdzaniem. Wszystkie przykłady BEGIN ATOMIC
podane w artykule będą wymagały jawne- DECLARE data DATE;
go zatwierdzenia (COMMIT) bądź wycofania SET data = DATE('2009-01-01');
transakcji (ROLLBACK). W tym celu w oknie WHILE ( data < DATE('2011-01-01') )
interpretera DB2 przed podłączeniem się do DO
bazy danych ustawimy zmienną środowisko- INSERT INTO rezerwacje VALUES (data, dayname(data),NULL);
wą DB2OPTIONS=+c. Następującym po- SET data = data + 1 DAY;
leceniem możemy sprawdzić, czy automa- END WHILE;
tyczne zatwierdzanie jest wyłączone (au- END @
to-commit off):
Listing 2. Usunięcie powtarzających rekordów
db2 list command options
Command options (DB2OPTIONS) = +c insert into rezerwacje values ('2010-11-30', dayname('2010-11-30'), 99) ;
Option Description Current Setting select * from rezerwacje where data = '2010-11-30'
------ --------------- ---------------
-a Display SQLCA OFF DATA DZIEN ID_OSOBY
-c Auto-Commit OFF ---------- ------------- -----------
… 2010-11-30 wtorek 99
2010-11-30 wtorek -
W pierwszej sesji uaktualnimy ID _ OSOBY
dla rekordu o dacie 2009-09-15. Ponieważ
wyłączyliśmy automatyczne zatwierdzanie, select * from old table (
po wykonaniu poniższej instrukcji na uak- delete from (
tualnianym rekordzie zostanie utrzymana select row_number() over (
blokada na wyłączność (X): partition by DATA order by ID_OSOBY asc) as nr
from rezerwacje
db2 update rezerwacje set id_osoby = 120 ) where nr > 1
where data = '2009-09-15' ) ;

Z drugiej sesji spróbujemy odczytać modyfi-


kowany rekord w trybie izolacji UR. Poziom DATA ID_OSOBY
izolacji można określić dla każdego zapy- ---------- -----------
tania poprzez dodanie na końcu zapytania 2010-11-30 -
klauzuli WITH:

db2 select * from rezerwacje where data = select * from rezerwacje where data = '2010-11-30'
'2009-09-15' with ur
DATA DZIEN ID_OSOBY
Zapytanie zwróci aktualną, jeszcze nieza- ---------- ------------- -----------
twierdzoną wartość: 2010-11-30 wtorek 99

DATA DZIEN ID_OSOBY


---------- ------------- -----------
2009-09-15 wtorek 120

www.sdjournal.org 51
Tworzenie aplikacji

dzonych rekordów, tak jak w przypadku po- or timeout. Reason code "68". zatwierdzona wartość rekordu, czyli w na-
ziomu UR. SQLSTATE=40001 szym przypadku zapytanie zwróci:

db2 select * from rezerwacje where data = Domyślnie parametr LOCKTIMEOUT ustawio- DATA DZIEN ID_OSOBY
'2009-09-15' with cs ny jest na wartość -1, co oznacza, że apli- ---------- ------------- -----------
kacja będzie czekała dowolnie długo. Czas 2009-09-15 wtorek -
Zachowanie sesji będzie jednak zależało oczekiwania na zwolnienie blokady można
od użytej wersji DB2. W DB2 9.5 i wcze- określić także instrukcją SET CURRENT LOCK Warto wspomnieć, że tak zachowa się za-
śniejszych wersjach zapytanie to zostanie TIMEOUT. Wykonanie poniższej instrukcji pytanie, którego intencją jest wyłącznie od-
wstrzymane aż do momentu, kiedy aplika- spowoduje, że w bieżącej sesji czas oczeki- czytanie danych (np. do celów raporto-
cja z pierwszej sesji zatwierdzi bądź wycofa wania na zwolnienie zasobu będzie wyno- wych), a nie modyfikacja danych. Wykona-
transakcję. Zapytanie będzie czekać okre- sił 15 sekund: nie zapytania z zamiarem zapisu (klauzula
śloną liczbę sekund zdefiniowaną przez pa- FOR UPDATE) spowoduje, że zapytanie tak-
rametr bazy danych LOCKTIMEOUT. Jeśli po db2 set current lock timeout 15 że zostanie wstrzymane na zablokowanym
tym czasie aplikacja z pierwszej sesji nie rekordzie:
zwolni blokady, wtedy zapytanie zakończy W DB2 9.7 zapytanie z poziomem izolacji
się błędem: CS nie będzie czekało na zwolnienie bloka- db2 select * from rezerwacje where data =
dy i od razu zwróci wynik. Jeśli dany rekord '2009-09-15' for update with cs
SQL0911N The current transaction has been jest przetwarzany na wyłączność przez inną
rolled back because of a deadlock aplikację, wtedy zwracana jest poprzednia Tak naprawdę dla powyższego zapytania do-
danie klauzuli FOR UPDATE nie ma większego
sensu. Dopiero wykorzystanie kursorów po-
zwoli zademonstrować możliwości tej klau-
zuli. Załóżmy, że będziemy chcieli odczy-
tać dwa rekordy o datach 2009-09-15 oraz
2009-09-16, a następnie w aplikacji podjąć
decyzję o aktualizacji tych rekordów. Do te-
Sesja 1
update rezerwacje set id_osoby = 33 where data = '2009-01-01
go celu wykorzystamy kursor, którym bę-
dziemy przemieszczać się po zbiorze wyni-
Sesja 2
kowym (w naszym przykładzie zbiór będzie
update rezerwacje set id_osoby = 22 where data = '2009-01-05'
składał się z dwóch rekordów). Kursor zade-
klarujemy i otworzymy następującymi in-
2009-01-01 czwartek 33 strukcjami SQL:
2009-01-02 piątek NULL
Blokada (x) 2009-01-03 sobota NULL
2009-01-04 niedziela NULL db2 declare k1 cursor for select * from
2009-01-05 poniedziałek 22 rezerwacje where data = '2009-09-
2009-01-06 wtorek NULL
15' or data = '2009-09-16' for
update with cs
db2 open k1

a następnie pobierzemy pierwszy rekord ze


zbioru wynikowego:

db2 +c fetch from k1

Rysunek 1. Brak indeksu na polu data spowoduje wstrzymanie jednej z sesji na blokadzie
Pobranie tego rekordu zostało wstrzyma-
ne (nie użyliśmy klauzuli ORDER BY, więc
DB2_EVALUNCOMMITTED w innych warunkach przetwarzanie może
W DB2 istnieje specjalna zmienna rejestrowa DB2_EVALUNCOMMITTED, której włączenie być wstrzymane na następnym rekordzie),
spowoduje, że obie aktualizacje danych z Rysunku 1 powiodą się nawet w przypadku braku
indeksu. Zmienną aktywuje się poleceniem db2set:
ponieważ w pierwszej sesji zmodyfikowa-
db2set DB2_EVALUNCOMMITTED=YES liśmy rekord dla daty 2009-09-15 i nie za-
Po ustawieniu tej zmiennej trzeba jeszcze powtórnie wystartować instancję. Jeśli podczas twierdziliśmy zmian. Zatwierdzając trans-
sekwencyjnego przemieszczania się po tabeli baza napotka na blokadę, wtedy sprawdza akcję w pierwszej sesji, będziemy mogli po-
aktualną wartość rekordu, by ocenić, czy rekord ten pasuje do kryteriów zapytania. Jeśli re- brać rekord:
kord nie pasuje do zbioru wynikowego, wtedy przeszukiwanie jest kontynuowane od na-
stępnego rekordu. Osobiście jednak nie zalecamy włączania tej zmiennej, ponieważ wymaga
DATA DZIEN ID_OSOBY
ona odpowiedniego sprofilowania aplikacji. Zmienna ta wykorzystywana jest głównie wte-
dy, gdy aplikacja modyfikuje kolumny, które nie są wykorzystywane jako kryterium wyszuki- ---------- ------------- -----------
wania wierszy (tak jak dla przykładu z Rysunku 1: pole data było wykorzystywane do zloka- 2009-09-15 wtorek 120
lizowania rekordów, natomiast uaktualniane było inne pole: id _ osoby). W naszym przeko-
naniu dużo lepsze efekty daje odpowiednie zaprojektowanie indeksów oraz normalizacja ta- Oczekiwanie na wycofanie (bądź zatwier-
bel. Projektowanie zdenormalizowanych tabel, które zawierają bardzo dużą liczbę kolumn,
powoduje, że aktualizacja dowolnego z pól blokuje także dostęp pozostałych pól w rekor-
dzenie) transakcji było związane z tym,
dzie (blokujemy przecież cały rekord). Rozbicie takiej struktury na wiele węższych tabel spo- że pierwsza sesja utrzymywała blokadę na
woduje, że każda z nich będzie mogła być uaktualniana niezależnie. wyłączność (X) dla rekordu o dacie 2009-
09-15. Druga sesja próbowała odczytać re-

52 SDJ Extra 35
Poziomy izolacji w DB2

kord z intencją zapisu, co oznaczało, że ONLY możliwa jest aktualizacja danych stały zmodyfikowane, ponieważ UPDATE zo-
chciała założyć blokadę typu UPDATE (U) z wykorzystaniem klasycznego warun- stanie wykonany wyłącznie dla dat, dla któ-
na tym rekordzie. Blokada (U) nie mo- ku wyszukiwania, na przykład poprzez rych nie zrobiono wcześniej rezerwacji. Za-
gła być założona ze względu na wcześniej- podanie wartości klucza (ang. searched kładając unikatowość pola data, powyż-
szą blokadę (X) z pierwszej sesji. W doku- update). sza instrukcja UPDATE może uaktualnić 0,1
mentacji DB2 Information Center możesz Powyższe instrukcje wykonywaliśmy w lub 2 rekordy. W sytuacji, w której uaktu-
znaleźć tabelę informującą, jakiego rodza- oknie poleceń tekstowych DB2 z opcją +c, alniono tylko część rekordów, aplikacja mu-
ju blokady mogą być zakładane na określo- która wyłącza automatyczny COMMIT. Jeśli si podjąć decyzję o wycofaniu zmian (ROL-
nym rodzaju blokad (szukaj pod hasłem kursor nie jest zdefiniowany z klauzulą WITH LBACK albo ROLLBACK to SAVEPOINT) albo za-
lock compatibility). HOLD, wtedy zatwierdzenie transakcji au- akceptowaniu rezerwacji na niepełną licz-
Po zatwierdzeniu transakcji w pierwszej tomatycznie go zamknie, co spowoduje, że bę dni.
sesji (COMMIT) druga sesja odczytała rekord przemieszczanie się po zbiorze wynikowym Do sprawdzenia uaktualnionych rekordów
o dacie 2009-09-15, ponieważ odczyt wy- (FETCH) nie będzie możliwe. najlepiej wykorzystać instrukcję SELECT opar-
konywany był z intencją zapisu, co ozna- Jak wspomnieliśmy na początku, zada- tą o instrukcję UPDATE:
cza, że rekord ten jest automatycznie za- niem poziomów izolacji jest zagwaranto-
blokowany blokadą typu UPDATE (U). Bloka- wanie spójności wykonywanych operacji. select data from new table(
da (U) charakteryzuje się tym, że inne sesje Na podstawie odczytanych wartości podej- update rezerwacje set id_osoby = 250
mogą czytać rekord (mogą zakładać blokady mujemy decyzję o jego modyfikacji. Gdyby where data in ('2009-09-15','2009-09-
SHARED (S)), natomiast nie mogą aktualizo- ktoś w międzyczasie podmienił zawartość 16') and id_osoby is null)
wać rekordu (pośrednio: zakładać blokad tu- rekordu, wtedy być może podjęlibyśmy in-
pu (X) lub (U)). Innymi słowy, tak długo jak ną decyzję – dzięki mechanizmowi blokad który dla naszego zestawu danych zwrócił
będziemy utrzymywać kursor na danym re- taka sytuacja nie będzie miała miejsca. Po- jeden rekord.
kordzie, nikt inny nie podmieni nam jego za- ziom izolacji CS oferuje bardzo dobry sto-
wartości. pień współbieżności, ponieważ podczas DATA
Jeśli przemieścimy się po zbiorze wyniko- czytania danych w danej chwili utrzymy- ----------
wym do następnego rekordu (2009-09-15): wana jest blokada wyłącznie na bieżącym 2009-09-16
rekordzie. Oczywiście, jeśli zmodyfikuje-
db2 +c fetch from k1 my rekord, wtedy blokada (U) zostaje prze- Wykorzystanie takiej konstrukcji ma wie-
konwertowana do blokady na wyłączność le zalet. Zwracamy tylko te rekordy, któ-
wtedy blokada (U) zostanie zwolniona z (X) i pozostaje aż do momentu zatwierdze- re zostały zmodyfikowane. Zapytanie opar-
pierwszego rekordu (2009-09-15) i zosta- nia bądź wycofania transakcji. Ten poziom te o instrukcję modyfikującą zapewnia tak-
nie założona na kolejnym (2009-09-16). izolacji gwarantuje spójność odczytu i zapi- że spójność odczytu, ponieważ obydwie ope-
W tym momencie można domyślić się, su, jeśli decydujemy się na modyfikację re- racje wykonywane są w jednym kroku i nie
skąd wzięła się nazwa CURSOR STABI- kordu w momencie jego przetwarzania. ma „przerwy” pomiędzy modyfikacją a od-
LITY (stabilność kursora). W tym trybie Jeśli z góry wiemy, które rekordy chcemy czytem.
izolacji baza gwarantuje spójność rekor- uaktualnić, wtedy nie musimy korzystać z Rekordy możemy zaktualizować także
du, na którym pozycjonowany jest kur- kursorów i możemy wykorzystać pojedynczą przy pomocy alternatywnej konstrukcji, w
sor. Podczas przemieszczania się po zbio- instrukcję UPDATE: której UPDATE oparty jest o wynik instruk-
rze wynikowym instrukcją FETCH, bloka- cji SELECT:
dy zakładane są wyłącznie na bieżącym update rezerwacje set id_osoby = 250
rekordzie (tam, gdzie pozycjonowany jest where data in ('2009-09-15','2009-09- select data from new table(
kursor). 16') and id_osoby is null update (
Po sprawdzeniu, czy danego dnia nikt nie select data, id_osoby
dokonywał rezerwacji, rekord możemy uak- Po wykonaniu instrukcji modyfikującej from rezerwacje
tualnić następującą instrukcją SQL: trzeba jeszcze sprawdzić, które rekordy zo- where data in ('2009-09-15','2009-

db2 +c update rezerwacje set id_osoby =


250 where current of k1
Rodzaje blokad
Blokady mogą być zakładane na rekordach, tabelach, obszarach tabel oraz partycjach tabel.
W DB2 dostępne są różne rodzaje blokad. Najbardziej powszechnymi rodzajami blokad za-
Warto zwrócić uwagę na warunek WHE- kładanych na rekordach są:
RE, w którym zamiast klasycznych wa-
runków wyszukiwania podaliśmy aktu- • Shared (S) – blokada zakładana jest podczas czytania rekordów. Inni użytkownicy mogą
czytać rekordy, lecz nie mogą ich modyfikować. Blokady typu (S) mogą być zakładane na
alne położenia kursora k1 (CURRENT OF). blokadach (S) pochodzących od innych użytkowników.
Aktualizacja z wykorzystaniem bieżącej • Update (U) – blokada zakładana jest podczas czytania rekordów z intencją zapisu. In-
pozycji kursora (ang. positioned update) ni użytkownicy mogą czytać dane, ale nie mogą przystąpić do aktualizacji rekordu, czy-
jest możliwa wyłącznie w sytuacji, gdy li założyć blokady typu (U) na istniejącej blokadzie (U). Blokady typu (S) mogą być zakła-
kursor był zadeklarowany z klauzulą FOR dane na blokadzie typu (U).
• Exclusive (X) – blokada jest zakładana podczas modyfikacji danych. Właściciel blokady
UPDATE . W przypadku kursorów tworzo-
może czytać i uaktualniać dane. Inni użytkownicy nie mogą aktualizować danych. Mogą
nych z klauzulą FOR READ ONLY nie jest podejrzeć zawartość rekordu bez sprawdzania blokad: bieżącą wartość w trybie UR bądź
możliwe wykorzystanie warunku WHERE wartość sprzed modyfikacji w trybie CS (w wersji DB2 9.7).
CURRENT OF, ponieważ dla każdego re-
kordu pobranego instrukcją FETCH zakła- Blokady można monitorować poleceniem db2pd –db baza –lock, bądź wykonując zapytania
na systemowym widoku SYSIBMADM.SNAPLOCK, który zwraca aktualną listę blokad.
dane są blokady typu SHARED (S). Oczy-
wiście w przypadku kursorów FOR READ

www.sdjournal.org 53
Tworzenie aplikacji

09-16')
Listing 3. Zjawisko fantomów występujące w poziomie izolacji RS
and id_osoby is null
) set id_osoby = 250
Sesja 1: Wykonanie zapytania z poziomem RS )

select * from ( Wewnętrzne zapytanie wskazuje na listę


select data, dzien, id_osoby from rezerwacje rekordów, które mają być przekazane do
where data >= '2009-09-10' instrukcji aktualizującej. Zewnętrzne za-
order by data asc pytanie zwraca zmodyfikowane rekordy.
fetch first 5 rows only Obsługa tej instrukcji działa podobnie do
) omówionego wcześniej przypadku, któ-
with rs; ry uaktualnia dane na podstawie bieżą-
cej pozycji kursora (WHERE CURRENT OF).
DATA DZIEN ID_OSOBY Wykorzystanie tej konstrukcji daje bar-
---------- ------------- ----------- dzo dużą elastyczność i czasami pozwa-
2009-09-10 czwartek - la uniknąć implementacji kursorów przy
2009-09-11 piątek - bardziej złożonych operacjach. Na Listin-
2009-09-12 sobota - gu 2 zademonstrowaliśmy przykład usu-
2009-09-13 niedziela - nięcia rekordów o powtarzających się da-
2009-09-14 poniedziałek - tach, zachowując te o najmniejszym ID_
OSOBY.
Sesja 2: Wstawienie i zatwierdzenie rekordu pasującego do kryterium zapytania z Wykorzystanie tej konstrukcji jest du-
Sesji 1 żo wydajniejsze i dodatkowo zapewnia du-
insert into rezerwacje values ( '2009-09-11', 'Fantom !', 1); żo większą współbieżność w porównaniu do
commit; implementacji z wykorzystaniem kursorów,
ponieważ zadanie wybierz rekordy, usuń je i
DB20000I The SQL command completed successfully. zwróć usunięte jest realizowane przez bazę da-
nych jak jedna operacja SQL.
Sesja 1: Powtórzenie zapytania z poziomem RS Przy wykonywaniu instrukcji UPDATE ba-
za automatycznie rygluje wyszukane rekor-
select * from ( dy blokadą typu (U) i konwertuje tę bloka-
select data, dzien, id_osoby from rezerwacje dę do typu (X) w momencie uaktualnienia
where data >= '2009-09-10' danych. Oczywiście opisany mechanizm
order by data asc zakładania blokad wykonywany jest auto-
fetch first 5 rows only matycznie i trwa bardzo krótko. By samo-
) dzielnie prześledzić ten proces „w zwolnio-
with rs; nym tempie”, można wykorzystać kursory.
Tworzymy kursor oparty o SELECT z klau-
DATA DZIEN ID_OSOBY zulą FOR UPDATE, przemieszczamy się po
---------- ------------- ----------- zbiorze wynikowym instrukcją FETCH, a na-
2009-09-10 czwartek - stępnie aktualizujemy wybrane rekordy z
2009-09-11 piątek - klauzulą WHERE CURRENT OF. W drugiej sesji
2009-09-11 Fantom ! 1 możemy uruchomić narzędzie db2pd –db
2009-09-12 sobota - sample –lock, by sprawdzić zakładane blo-
2009-09-13 niedziela - kady bądź wykorzystać systemowy widok
SYSIBMADM.SNAPLOCK.

Znaczenie indeksów
Zakleszczenia (ang. deadlocks) dla współbieżności
Zakleszczenie (ang. deadlock) powstaje w sytuacji, w której dana sesja oczekuje na zasób, Znaczenie indeksów omówimy na pro-
który nigdy nie będzie zwolniony. Najczęstszym przypadkiem zakleszczenia jest sytuacja, w stym przykładzie. W pierwszej sesji uaktu-
której dwie bądź więcej sesji zakładają blokady typu (S) na tym samym rekordzie, a następ- alnimy rekord o dacie 2009-01-01, jednak
nie próbują zaktualizować rekord. Aktualizacja rekordu wymaga założenia blokady na wy- bez zatwierdzania zmian, tak by utrzymać
łączność (X). Blokada taka nie może być zrealizowana ze względu na blokady (S) pochodzące blokadę na wyłączność (X). W drugiej se-
od innej sesji. Pierwsza sesja zgłaszająca chęć aktualizacji będzie oczekiwać na decyzję dru-
sji spróbujemy uaktualnić rekord o datach
giej. Jeśli druga wykona ROLLBACK, wtedy pierwsza bezproblemowo dokończy pracę. Nato-
miast jeśli druga z sesji spróbuje także zaktualizować dane, wtedy obie sesje utkwią w mar- 2009-01-05, tak jak przedstawione jest to
twym punkcie: druga będzie czekała na pierwszą, natomiast pierwsza na drugą. DB2 auto- na Rysunku 1.
matycznie wykrywa taki przypadek i odkręca transakcje jednej z sesji (ROLLBACK). Obie sesje uaktualniają zupełnie inne ze-
Do wykrywania zakleszczeń może posłużyć specjalna zmienna rejestrowa: stawy rekordów, więc wydaje się, że nie po-
db2set DB2_CAPTURE_LOCKTIMEOUT=ON
winno być konfliktu współbieżności. UPDATE
Po ustawieniu tej zmiennej i zrestartowaniu instancji DB2 będzie gromadziło szczegółowe
informacje o zakleszczeniach, w szczególności, jaka sesja była przyczyną zakleszczenia oraz w drugiej sesji zostanie jednak wstrzyma-
na jakim zasobie nastąpił konflikt. ny aż do momentu, kiedy pierwsza sesja za-
twierdzi bądź wycofa transakcję. Przyczyną
takiego zachowania jest brak indeksu na po-

54 SDJ Extra 35
Poziomy izolacji w DB2

lu wykorzystywanym do odszukania zmie- Taki sposób rezerwacji byłby poprawny przy cja może zaktualizować dane. Gdyby tak się
nianego rekordu. By zlokalizować rekord o założeniu, że jesteśmy jedyną osobą, która stało, wtedy wykonana przez nas instrukcja
dacie 2009-01-05, baza danych musi do- jest podłączona do bazy danych. Rezerwa- UPDATE doprowadzi do niespójności w bazie,
konać ewaluacji wartości wszystkich rekor- cji dokonujemy w dwóch krokach. W pierw- ponieważ w ten sposób nadpiszemy rezerwa-
dów w tabeli (sekwencyjny skan tabeli). Po- szym czytamy dane z bazy, a w drugim zapi- cję wykonaną przez innego użytkownika.
nieważ jeden z rekordów (2009-01-01) ma sujemy. Pomiędzy wykonaniem tych dwóch Rozwiązaniem problemu może być zablo-
założoną blokadę na wyłączność (X), ewa- operacji jest przerwa, w której inna aplika- kowanie rekordów już w momencie odczy-
luacja wartości tego rekordu będzie możli-
wa dopiero po jej zwolnieniu (pamiętajmy,
że czytamy z intencją zapisu, więc nie mo-
żemy pobrać ostatnio zatwierdzonej war-
tości rekordu). Utworzenie indeksu na po-
lu data spowoduje, że dla drugiej sesji baza
danych uaktualni rekord 2009-01-05 bez
Baza danych
konieczności odwoływania się do pozosta-
łych rekordów. Wszystkie przykłady z dal- ...
szej części artykułu będziemy wykonywać 2009-01-10 czwartek NULL
2009-01-11 piątek NULL
przy założeniu, że został utworzony nastę- 2009-01-12 sobota NULL
pujący indeks: 2009-01-13 niedziela NULL
2009-01-14 poniedziałek NULL
2009-01-15 wtorek NULL
db2 create index rez_data_idx on
...
rezerwacje(data)

I. Odczyt bez blokowania


READ STABILITY III. Zlokalizowanie rekordów i spójny zapis
Czasami logika aplikacji wymaga, by decy-
zję o sposobie uaktualnienia danych podjąć II. Aktualizacja po stronie aplikacji
dopiero po odczytaniu większej części re- 2009-01-12 sobota 150
kordów. Wyobraźmy sobie, że chcemy doko- 2009-01-13 niedziela 150
nać rezerwacji na 5 dni w całości, licząc od
2009-09-10. Aplikacja
Najpierw musimy sprawdzić, czy w tych
dniach nikt inny nie dokonał rezerwacji. Ta-
kie sprawdzenie możemy wykonać następują-
cym zapytaniem SQL:

select count(id_osoby) from (


select id_osoby from rezerwacje Rysunek 2. Modyfikacja rekordów bez wstępnego blokowania przy odczycie
where data >= '2009-09-10'
order by data asc
Listing 4. Lista blokad przy poziomie izolacji RR zależnie od istnienia indeksu na polu data. Listę
fetch first 5 rows only uzyskaliśmy, wykonując zapytanie na widoku systemowym SYSIBMADM.SNAPLOCK
)
Lista blokad dla zapytania z Listingu 3 wykonanego z poziomem RR po usunięciu
Wewnętrzne zapytanie wybiera listę pię- indeksu na polu data
ciu rekordów dla dni, które nas interesują.
Zewnętrzne zapytanie zlicza id _ osoby. LOCK_OBJECT_TYPE TABNAME LOCK_MODE LOCK_ATTRIBUTES
Zewnętrzne zapytanie zwróci wartość ze- ------------------ ---------- ---------- ---------------
ro, jeśli w polu ID _ OSOBY znajdowały się INTERNALP_LOCK – S NONE
wyłącznie wartości NULL, co oznacza, TABLE_LOCK REZERWACJE S RR
że w tych dniach nie dokonano rezerwa-
cji. Jeśli zapytanie zwróci wartość więk-
szą od zera, wtedy musimy poszukać in- Lista blokad dla zapytania z Listingu 3 z poziomem RR przy istniejącym indeksie na
nego terminu albo zmienić liczbę rezerwo- polu data
wanych dni.
Dla naszych danych zapytanie zwróciło LOCK_OBJECT_TYPE TABNAME LOCK_MODE LOCK_ATTRIBUTES
wartość zero, więc możemy przystąpić do ------------------ ---------- ---------- ---------------
rezerwacji, uaktualniając kolumnę id_osoby ROW_LOCK REZERWACJE S RR
dla pięciu rekordów: ROW_LOCK REZERWACJE S RR
ROW_LOCK REZERWACJE S RR
update ( ROW_LOCK REZERWACJE S RR
select id_osoby from rezerwacje ROW_LOCK REZERWACJE S RR
where data >= '2009-09-10' INTERNALP_LOCK – S NONE
order by data asc TABLE_LOCK REZERWACJE IS RR
fetch first 5 rows only
) set id_osoby = 123

www.sdjournal.org 55
Tworzenie aplikacji

tu, tak by inni użytkownicy nie mogli zmo- typu (S) założone z pierwszej sesji. W tym stują blokadę typu (U), inne typu (S)), może
dyfikować w międzyczasie wybranych przez momencie DB2 wykrywa, że wystąpiło za- dojść do zakleszczenia. By zapobiec takiej sy-
nas rekordów. Taką funkcjonalność oferu- kleszczenie (ang. deadlock) i wycofuje jed- tuacji, możemy zastosować blokadę na wy-
je właśnie poziom izolacji READ STABILITY ną z transakcji. Jedna z transakcji kończy się łączność (X):
(RS). W tym trybie izolacji każdy odczyta- z błędem:
ny rekord, który pasuje do zbioru wynikowe- select count(id_osoby) from (
go, jest domyślnie blokowany blokadą typu SQL0911N The current transaction has been select id_osoby from rezerwacje
SHARED (S), co oznacza, że inni użytkowni- rolled back because of a deadlock where data >= '2009-09-10'
cy nie będą mogli założyć blokady typu (X) or timeout. Reason code "68". order by data asc
na tych rekordach. Zapytanie wykorzystują- SQLSTATE=40001 fetch first 5 rows only
ce poziom izolacji RS będzie wyglądało na- )
stępująco: Przedstawione rozwiązanie zabezpiecza with rs use and keep exclusive locks
przed niespójnością danych, jednak jest
select count(id_osoby) from ( mało eleganckie ze względu na stosunkowo Takie rozwiązanie zagwarantuje, że żadna
select id_osoby from rezerwacje wysoki koszt obsługi zakleszczenia. Przy inna sesja nie podejrzy przetwarzanych da-
where data >= '2009-09-10' takim podejściu decyzja o wstrzymaniu nych, jeśli chce przeczytać rekordy z zamia-
order by data asc przetwarzania którejś z sesji zostanie odło- rem ich modyfikacji. Inne sesje chcące doko-
fetch first 5 rows only żona aż do momentu wykonania instruk- nać sprawdzenia zawartości mogą odczytać
) cji UPDATE. dane z wykorzystaniem poziomu CS Cur-
with rs Gdyby wszystkie aplikacje wykorzystywa- rently Committed (DB2 9.7), który pozwoli
ły do sprawdzania zapytanie wykorzystujące na odczytanie zatwierdzonych danych z po-
Po wykonaniu tego zapytania wszystkie blokady typu (U), tak jak poniżej: minięciem blokad.
odczytane rekordy zostaną zablokowane
blokadą (S). Blokada typu (S) dopuszcza select count(id_osoby) from ( REPEATABLE READ
zakładanie przez innych użytkowników select id_osoby from rezerwacje Poziom REPEATABLE READ (RR) działa bar-
na tym samym rekordzie dodatkowych where data >= '2009-09-10' dzo podobnie do poziomu RS. Każdy z
blokad typu (S). Inny użytkownik będzie order by data asc odczytanych rekordów jest blokowany aż
mógł wykonać dokładnie to samo zapyta- fetch first 5 rows only do momentu zatwierdzenia bądź wycofa-
nie sprawdzające i także dostanie taki sam ) nia transakcji.W przypadku wykorzysta-
wynik. with rs use and keep update locks nia kursorów istnieje możliwość wcześniej-
W takiej sytuacji dwie sesje będą prze- szego zwolnienia blokad, zamykając kursor
konane, że nikt wcześniej jeszcze nie doko- , wtedy druga sesja zostanie wstrzymana już instrukcją CLOSE kursor WITH RELEASE. Do-
nał rezerwacji w tych terminach, więc oby- w momencie wykonywania zapytania spraw- myślnie utrzymywane są blokady typu (S),
dwie sesje mogą przystąpić do wykonania in- dzającego aż do czasu skończenia transakcji a przy wykorzystaniu klauzuli USE AND KEEP
strukcji UPDATE. Pierwsza z sesji, która wyko- przez pierwszą sesję. Takie zachowanie wy- możliwe jest także użycie blokad typu (U)
na UPDATE, zostanie wstrzymana, ponieważ nika stąd, że DB2 nie dopuszcza zakładania lub (X). Jedyną różnicą pomiędzy pozio-
nie będzie mogła założyć blokad (X) na re- blokady (U) na rekordzie, który już blokadę mem RR w porównaniu do RS jest to, że
kordach, które posiadają blokady typu (S) (U) posiada. baza danych nie zezwala, by inna sesja wsta-
pochodzące od drugiej sesji. Jeśli druga se- Blokada typu (U) zezwala jednak na zakła- wiła rekord, który będzie pasował do zbio-
sja wykona UPDATE, wtedy także zostanie danie blokad typu (S) przez inne sesje. W sy- ru wynikowego zapytania. Odnosząc się do
wstrzymana z tego samego powodu – na tuacji, w której aplikacje niekonsekwentnie wcześniejszego przykładu wykorzystujące-
zmienianych rekordach występują blokady wykorzystują rodzaje blokad (jedne wykorzy- go poziom RS, przy wielokrotnym wykony-
waniu tego samego zapytania istnieje nieze-
Listing 5. Pobranie adresu rekordu i tokenu modyfikacji rekordu rowe prawdopodobieństwo uzyskania róż-
nych wyników. Tak jak pokazaliśmy na Li-
db2 select id_osoby, rid_bit(rezerwacje), row change token for rezerwacje from stingu 3, rekord wstawiony w Sesji 2 jest
rezerwacje where data = '2009-09-10' widoczny w Sesji 1 po powtórnym wykona-
niu tego samego zapytania. Dodatkowy re-
ID_OSOBY 2 3 kord, który pojawił się w Sesji 2, określany
----------- ----------------------------------- -------------------- jest jako „Fantom”.
x'14008200000000000000000002795824' 3999328423385235456 Poziom izolacji REPEATABLE READ z defini-
cji nie dopuszcza Fantomów. W przypadku
Listing 6. Pobranie znacznika czasu modyfikacji rekordu poziomu izolacji RR baza danych gwarantuje,
że wielokrotne wykonywanie tego samego za-
db2 select data, dzien, id_osoby, row change timestamp for rezerwacje from pytania zawsze zwróci dokładnie ten sam ze-
rezerwacje staw rekordów. Gdyby zapytanie z Listingu 3
wykorzystywało poziom RR, wtedy instruk-
DATA DZIEN ID_OSOBY 4 cja INSERT w Sesji 2 zostałaby wstrzymana
---------- --------- ----------- -------------------------- aż do momentu zatwierdzenia bądź wycofa-
2009-01-01 czwartek – 0001-01-01-00.00.00.000000 nia transakcji.
2009-01-02 piątek – 0001-01-01-00.00.00.000000 REPEATABLE READ jest najbardziej re-
2009-01-03 sobota – 0001-01-01-00.00.00.000000 strykcyjnym poziomem izolacji dostęp-
nym w DB2. Dla tego poziomu bardzo du-
że znaczenie ma zaprojektowanie odpo-

56 SDJ Extra 35
Poziomy izolacji w DB2

wiednich indeksów, tak by blokować tyl- Najpierw blokujemy rekordy, a potem je ak- W Podejściu 3 najpierw blokujemy inte-
ko te instrukcje INSERT, które faktycznie tualizujemy. resujące nas dane, wykorzystując poziom
mogą spowodować Fantomy. Gdyby zapy- W Podejściu 1 od razu wykonujemy in- izolacji RR / RS (najlepiej korzystając z
tanie w Sesji 1 z Listingu 3 było wykona- strukcję UPDATE na interesującym nas zesta- klauzuli USE AND KEEP UPDATE | EXCLUSIVE
ne z poziomem izolacji RR, a indeks na po- wie rekordów bez zatwierdzania transakcji LOCKS, by wyeliminować zakleszczenia),
lu data zostałby wcześniej usunięty, wte- i w tym samym kroku odczytujemy zaktu- a następnie zatwierdzamy zmiany. Gdy-
dy zapytanie wymusiłoby założenie jed- alizowane rekordy sprzed aktualizacji. Do by okazało się, że nie jesteśmy w stanie za-
nej blokady (S) na całej tabeli. Taka bloka- tego celu możemy wykorzystać konstruk- blokować interesującego zestawu rekordów
da gwarantuje, że nikt nie wstawi rekordu cję SELECT FROM NEW / OLD TABLE opartą o (ktoś dokonał w międzyczasie modyfika-
pasującego do zbioru wynikowego zapyta- instrukcję modyfikującą UPDATE, INSERT, cji), wtedy po prostu zwalniamy blokady.
nia, jednak jednocześnie ogranicza współ- DELETE. Gdyby w wyniku sprawdzenia oka- Zaletą podejścia 3 jest to, że jeśli już uzy-
bieżność. Wszystkie pozostałe sesje nie bę- zało się, że nasza aktualizacja jest niespój- skamy blokady (X) na odczytanych rekor-
dą mogły modyfikować danych tabeli re- na, wtedy należałoby wycofać zmiany in- dach, to mamy gwarancję pomyślnego za-
zerwacje aż do czasu zakończenia transak- strukcją ROLLBACK, najlepiej wykorzystu- twierdzenia transakcji. Ewentualny kon-
cji w Sesji 1. jąc punkt zapisu transakcji (ROLLBACK TO flikt dostępu do danych zostanie wykry-
Założenie indeksu na polu data pozwoli SAVEPOINT). Takie podejście może być sto- ty już we wczesnej fazie blokowania re-
bazie danych zakładać blokady dla każdego sowane wtedy, gdy logika weryfikacji spój- kordów przy odczycie, co pozwala unik-
z rekordów. Dzięki takiej granulacji blokad ności zapisu jest stosunkowo prosta. W na- nąć wycofania transakcji bądź wystąpienia
druga sesja może pomyślnie wstawić rekord szym przykładzie wystarczyło sprawdzić zakleszczeń.
o dacie 2009-10-01. Na Listingu 4 przedsta- pole ID_OSOBY. W ogólnym przypadku
wiliśmy listę blokad, które są zakładane przez sprawdzenie może wymagać porównania Optymistyczne blokowanie
zapytanie z Listingu 3 dla obu omówionych większej liczby pól. Wadą tego rozwiąza- Aktualizacja rekordów zgodnie ze sche-
przypadków. nia może być także konieczność wycofania matem pokazanym na Rysunku 2 wymaga
zmian w przypadku wystąpienia niespój- zlokalizowania właściwych rekordów oraz
Podsumowanie nego zapisu. Instrukcja ROLLBACK jest sto- upewnienia się, czy rekordy te nie zosta-
poziomów CS, RR i RS sunkowo kosztowną operacją, dlatego jeśli ły w międzyczasie uaktualnione przez ko-
Poziomy izolacji RS i RR utrzymują bloka- zakładamy, że takie sytuacje mogą wystę- goś innego. Taka czynność może okazać się
dy aż do momentu zatwierdzenia transak- pować względnie często, wtedy lepiej jest nietrywialna, jeśli tabela składa się z dużej
cji. By zapewnić maksymalną współbież- wcześniej zablokować rekordy, tak jak w liczby pól. Tu z pomocą przychodzą specjal-
ność, a tym samym wydajność przetwa- Podejściu 3. ne funkcje do obsługi optymistycznego blo-
rzania, przerwa pomiędzy odczytaniem W Podejściu 2 wykorzystujemy kursor kowania dostępne od wersji DB2 9.5, które
danych a zatwierdzeniem powinna być działający w poziomie izolacji CS i aktuali- pozwalają szybko zlokalizować dany rekord
możliwie krótka. Organizacja aplikacji, w zujemy rekord po rekordzie. Gdyby okaza- oraz sprawdzić, czy był zmodyfikowany od
której najpierw prezentujemy użytkowni- ło się, że któryś z rekordów jest już zaktu- ostatniego odczytu.
kowi na ekranie zestaw rekordów odczy- alizowany przez innego użytkownika (np. Do zlokalizowania odczytanego rekordu
tanych w trybie RR lub RS, a następnie rezerwacja na jeden dzień z interesujących można wykorzystać funkcję RID_BIT (ang.
czekamy na decyzję użytkownika, nie za- nas 5 dni), wtedy wycofujemy zmiany. Po- row identifier), która zwraca adres rekordu.
wsze jest najlepszym rozwiązaniem. Przy dejście z wykorzystaniem kursorów pozwa- Do sprawdzenia, czy rekord był modyfiko-
takim podejściu dane byłyby blokowane la na implementację bardziej złożonej logi- wany od ostatniego odczytu, może posłużyć
tak długo, jak długo użytkownik przeglą- ki. Obsługa kursorów jest jednak bardziej wyrażenie ROW CHANGE TOKEN. Odczytując da-
dałby je na ekranie. Dużo lepszym podej- kosztowna niż wykonanie pojedynczej in- ne, powinniśmy dodatkowo pobrać adres re-
ściem jest zaprezentowanie użytkowniko- strukcji SELECT z UPDATE, głównie ze wzglę- kordu oraz token ostatniej modyfikacji (patrz
wi danych na ekranie bez blokowania, a du na konieczność wykonania bardzo du- Listing 5).
kiedy już wstępnie podejmie decyzję, wte- żej ilości instrukcji SQL FETCH. Po kursory Funkcja RID_BIT zwraca identyfikator re-
dy powinniśmy wykorzystać odpowiedni warto sięgnąć wtedy, gdy logika przetwarza- kordu w postaci ciągu znaków VARCHAR(16)
poziom izolacji, by w spójny sposób uak- nia jest trudna do uzyskania pojedynczą in- FOR BIT DATA. Klauzula FOR BIT DATA powodu-
tualnić bazę danych. „Spójne uaktualnie- strukcją SQL. je, że ciąg znaków traktowany jest jak zestaw
nie” oznacza, że zaktualizujemy właściwe
rekordy w zamierzony sposób. Jeśli ktoś Listing 7. Automatyczna aktualizacja pola CZAS_AKTUALIZACJI zdefiniowanego
w międzyczasie dokona modyfikacji inte- jako ROW CHANGE TIMESTAMP
resujących nas rekordów, wtedy proces za-
pisu powinien to wykryć. Schemat takie- db2 update rezerwacje set id_osoby = id_osoby
go uaktualnienia został przedstawiony na db2 commit
Rysunku 2. db2 select data, dzien, id_osoby,czas_aktualizacji from rezerwacje
Odnosząc się do wcześniej opisywanego
przykładu, rezerwację na 5 kolejnych dni mo-
żemy zrealizować na kilka sposobów z wyko- DATA DZIEN ID_OSOBY CZAS_AKTUALIZACJI
rzystaniem dowolnego z omówionych pozio- ---------- --------- ----------- --------------------------
mów izolacji: 2009-01-01 czwartek – 2009-06-12-12.15.41.343000
2009-01-02 piątek – 2009-06-12-12.15.41.343001
• od razu aktualizujemy dane i sprawdza- 2009-01-03 sobota – 2009-06-12-12.15.41.343002
my spójność aktualizacji;
• wykorzystujemy kursor działający i ak-
tualizujemy rekord po rekordzie.

www.sdjournal.org 57
Tworzenie aplikacji

danych binarnych i nie jest poddawany kon- tuacjach, w których rozdzielczość znaczni- podmianie danych i zaczytać rekordy jesz-
wersji stron kodowych. Okno poleceń DB2 ka jest mniejsza niż liczba modyfikacji w da- cze raz).
prezentuje dane tego typu heksadecymalnie ( nym przedziale czasowym (więcej niż 1 mi-
x'1400…824'). ROW CHANGE TOKEN zwraca war- lion modyfikacji na sekundę). Takie zacho- Podsumowanie
tość typu BIGINT. wanie znacznika pozwala zagwarantować je- Kluczem do stworzenia maksymalnie
Aktualizując wybrany rekord w warunku go unikatowość. współbieżnej aplikacji jest odpowied-
WHERE, podajemy poprzednio pobrany adres Znacznik czasowy ROW CHANGE TIMESTAMP nie zaprojektowanie tabel oraz indeksów.
rekordu oraz token modyfikacji: najlepiej dodać w postaci ukrytej kolumny Równie istotnym elementem jest wyko-
(ang. hidden column), tak by dodanie kolum- rzystanie odpowiednich poziomów izo-
db2 update rezerwacje set od_osoby = 300 ny nie wymuszało modyfikacji istniejących lacji, by zagwarantować spójność wyko-
where rid_bit(rezerwacje) = x'140 aplikacji. Dla naszej tabeli rezerwacje znacz- nywanych operacji oraz maksymalną wy-
08200000000000000000002795824' and nik czasowy dodamy, wykorzystując instruk- dajność. DB2 udostępnia techniki zarów-
row change token for rezerwacje = cję ALTER TABLE: no optymistycznego, jak i pesymistyczne-
3999328423385235456 go blokowania danych. W optymistycz-
alter table rezerwacje add column czas_ nym blokowaniu przyjmuje się założe-
Jeśli okaże się, że w międzyczasie ktoś aktualizacji timestamp not null nie, że odczytane przez aplikację rekordy
zmienił wartość rekordu, wtedy automa- implicitly hidden generated always nie będą w międzyczasie zmodyfikowane
tycznie zmieni się token modyfikacji i ak- for each row on update as row przez inną aplikację, więc nie ma potrze-
tualizacja nie zostanie wykonana, ponie- change timestamp; by zakładania blokad. Takie rozwiązanie
waż aktualizowany rekord nie zostanie od- gwarantuje maksymalną współbieżność.
naleziony. Instrukcja UPDATE zakończy się Po dodaniu kolumny tabela będzie zachowy- Gdyby okazało się, że raz na jakiś czas in-
ostrzeżeniem: wała się dokładnie tak samo jak przed jej do- na aplikacja zmodyfikuje odczytane przez
daniem. Zapytania nie będą świadome ist- nas dane, wtedy musimy powtórzyć wyko-
SQL0100W No row was found for FETCH, nienia kolumny czas_aktualizacji: naną przez nas pracę. W przypadku pesy-
UPDATE or DELETE; or the result mistycznego blokowania przyjmujemy za-
of a query is an empty table. db2 select * from rezerwacje łożenie, że istnieje bardzo duża szansa, że
SQLSTATE=02000 odczytane dane za chwilę będą modyfiko-
DATA DZIEN ID_OSOBY wane przez inną osobę. W takim przypad-
Korzystanie z identyfikatora rekordu oraz ---------- ------------- ----------- ku opłaca się już na samym początku za-
tokenu modyfikacji nie wymaga specjal- 2009-01-01 czwartek - blokować dane, by mieć gwarancję wyko-
nego konfigurowania tabeli. Identyfika- 2009-01-02 piątek - nania założonych modyfikacji. Przyjęcie
tor rekordu jest po prostu adresem logicz- 2009-01-03 sobota - odpowiednich założeń musi być oparte
nym rekordu. Token modyfikacji jest spe- o przewidywaną charakterystykę aplika-
cjalnym znacznikiem umieszczanym na By sprawdzić zawartość kolumny czas_ak- cji oraz sposób, w jaki użytkownicy będą
stronie, na której znajdują się rekordy, i tualizacji, musimy jawnie podać jej nazwę z niej korzystać.
jest zmieniany za każdym razem, kiedy ba- bądź wykorzystać wyrażenie ROW CHANGE
za aktualizuje stronę. Łatwo się domyślić, TIMESTAMP (patrz Listing 6)
że przemieszczenie rekordu z jednej stro- Jak widać, po wykonaniu instrukcji ALTER
ny na inną (na przykład podczas reorgani- TABLE kolumna czas_aktualizacji zosta-
zacji tabeli poleceniem REOGR) spowodu- ła wypełniona stałą wartością 0001-01-01-
je zmianę adresu oraz zmianę tokenu mo- 00.00.00.000000. Wystarczy zaktualizować
dyfikacji. Token modyfikacji ROW CHANGE dowolne pole tabeli, by przekonać się, że ko-
TOKEN tak naprawdę zmieniany jest za każ- lumna czas_aktualizacji jest także zmieniana
dym razem, kiedy jakikolwiek z rekordów (patrz Listing 7).
na stronie zostanie zaktualizowany. Wraz Aktualizacja rekordu z wykorzysta-
ze wzrostem liczby modyfikacji na tabe- niem znacznika czasowego wygląda na-
li wzrasta prawdopodobieństwo, że apli- stępująco:
kacja wykorzystująca token nie odnajdzie
wcześniej odczytanego rekordu, mimo iż update rezerwacje set id_osoby = 150
rekord nie był zmodyfikowany (ang. fal- where
se positives). (rid_bit(rezerwacje) = x'530041080000000 Artur Wroński
By zabezpieczyć się przed takimi przy- 000000000043A47BA' and Jest pracownikiem działu oprogramowania IBM
padkami, możliwe jest dodanie dodatko- row change timestamp for rezerwacje = (IBM Software Group) i specjalizuje się w zagad-
wej kolumny ROW CHANGE TIMESTAMP, któ- '2009-06-12-12.15.41.343222'); nieniach baz danych DB2 oraz Informix.
ra będzie przechowywała unikatowy znacz- Kontakt z autorem: artur.wronski@pl.ibm.com
nik czasowy (ang. timestamp) aktualizacji Jeśli w transakcji będziemy chcieli uaktual-
każdego rekordu. ROW CHANGE TIMESTAMP nić większą liczbę rekordów, wtedy powyż- Krzysztof Mikołajewski
jest pewnego rodzaju licznikiem, którego szą instrukcję UPDATE musimy wykonać wie- Krzysztof Mikołajewski pracuje w dziale usług
wartość oparta jest o bieżący czas. Znacz- le razy, za każdym razem sprawdzając licz- technologicznych IBM Software Services. Zajmu-
nik w przybliżeniu odpowiada aktualne- bę zaktualizowanych wierszy. W przypad- je się zagadnieniami baz danych DB2, Informix
mu czasowi modyfikacji rekordu (CURRENT ku gdyby instrukcja UPDATE nie odszukała oraz narzędziami do integracji danych, stosowa-
TIMESTAMP). Określenie „przybliżony” nale- rekordu o zadanym identyfikatorze i znacz- nymi w hurtowniach danych.
ży rozumieć w ten sposób, że znacznik mo- niku czasowym, wtedy aplikacja powinna Kontakt z autorem:
że chwilowo wyprzedzić bieżący czas w sy- obsłużyć taką sytuację (np. poinformować o krzysztof.mikolajewski@pl.ibm.com

58 SDJ Extra 35
Administracja

Backup od A do Z
Artur Wroński

Na administratorze bazy danych spoczywa wiele obowiązków. Jednym


z nich, w moim przekonaniu najważniejszym, jest odpowiednie
zabezpieczenie danych poprzez wykonywanie kopii zapasowych, czyli
tzw. backup-ów. W ramach artykułu przybliżę dostępne w DB2 techniki
ich tworzenia.

Z
anim jednak skoncentruję się na odpo- mięć, odpowiednie wątki obsługujące żąda- stu wyłączenie zasilania w komputerze. Oczywi-
wiednich narzędziach i przedstawię nia itp.) automatycznie podczas pierwszego ście takiej operacji wykonywać na bazie danych
przykłady ich użycia, chciałbym pod- podłączenia się któregokolwiek z użytkowni- nie wolno, ponieważ baza nie zostanie popraw-
kreślić, iż żadna technika zabezpieczania danych ków. Jeśli baza danych jest w trybie quiesce nie zamknięta i pozostanie w niespójnym stanie!
nie zastąpi kopii bezpieczeństwa wykonywanych (określanym także jako tzw. tryb wygaszonej Wówczas próba wykonania backup-u offline bazy
z poziomu bazy danych. Zapis lustrzany na nie- bazy danych), wtedy wyłącznie administra- skutkuje wyświetleniem komunikatu o błędzie
zależne dyski (ang. mirroring), replikacja bazy da- torzy bazy, posiadający odpowiedni poziom SQL1015N The database is in an inconsistent
nych na wiele ośrodków, wyładowanie danych z uprawnień quiesce, będą mogli się do danej state. Stan niespójności oznacza, że baza danych
bazy do postaci tekstowej czy kopia plików bazy bazy danych podłączyć. Innymi słowy wyko- na dyskach zawiera dane pochodzące z transak-
danych wykonanych z poziomu systemu opera- nanie polecenia quiesce gwarantuje, że ża- cji, które nie zostały zatwierdzone. By o tym się
cyjnego mogą być jedynie uzupełnieniem bac- den zwykły użytkownik bazy danych nie bę- przekonać, wystarczy wyświetlić konfigurację
kup-ów, a nie podstawowym elementem zabez- dzie mógł aktywować bazy danych, więc bac- bazy (get db cfg for sample) i poszukać parame-
pieczania danych. Mój punkt widzenia przybliżę kup offline ma szansę się wykonać. tru informacyjnego „Database is consistent”. War-
w następnych sekcjach artykułu. Wszystkie pole- Wykonanie w skrypcie polecenia deactivate tość „NO” oznacza, że baza jest niespójna i dla ta-
cenia zawarte w tym artykule oparłem na bazie db sample jest konieczne wyłącznie wtedy, jeśli kiej bazy backup offline nie może być wykonany.
przykładów SAMPLE, którą można utworzyć, wy- baza danych była wcześniej aktywowana polece- Co ciekawe, parametr ten przyjmuje także war-
dając polecenie: db2sampl –sql. niem activate db sample. W praktyce stosun- tość „NO” podczas normalnej pracy, gdy użyt-
kowo rzadko aktywuje i deaktywuje się bazę da- kownicy modyfikują dane. Wcale nie oznacza to,
Pierwszy backup nych w jawny sposób. Jeśli baza była aktywowa- że z bazą są jakieś problemy, a jedynie tylko tyle,
Najprostszą formą backup-u jest tzw. archiwum na poprzez podłączenie się do niej, wtedy ostat- że są rozpoczęte transakcje, a stan plików bazy na
offline. Ten rodzaj kopii bezpieczeństwa wykonu- ni użytkownik, który odłącza się od bazy, inicju- dyskach może nie odzwierciedlać stanu operacji
je się przy nieaktywnej bazie danych. Wystarczy, je proces deaktywacji bazy. Takie podejście po- wykonanych w pamięci bazy. Wszystkie mody-
że w oknie poleceń tekstowych DB2 wpiszesz: zwala na efektywniejsze wykorzystanie pamię- fikacje danych w DB2 są wykonane w pamięci
ci komputera w przypadku wielu baz, ponie- operacyjnej (w tzw. puli buforów) i okresowo są
db2 backup db sample waż bazy, z których nikt nie korzysta, nie kon- przenoszone na dysk. Zapis do plików bazy (tzw.
sumują zasobów. Jeśli baza była jednak aktywo- kontenerów) odbywa się zupełnie asynchronicz-
Jeśli baza danych była wcześniej aktywo- wana jawnie, wtedy nawet odłączenie wszyst- nie i jest odpowiednio kolejkowany, by zoptyma-
wana przez administratora poleceniem db2 kich użytkowników od bazy (np. poleceniem lizować dostęp do systemu dyskowego.
activate db sample bądź pośrednio poprzez quiesce, tak jak w skrypcie na Listingu 1) nie Możesz być zaskoczony, ale skrypt przedsta-
podłączenie się użytkowników do bazy, wte- inicjuje procesu zwalniania zasobów. wiony na Listingu 1 powinien poprawnie wy-
dy dostaniesz komunikat o błędzie SQL1035N Istnieje jeszcze kilka metod odłączania użyt- konać backup offline nawet dla takiej bazy, która
The database is currently in use. W ta- kowników od bazy. Użytkowników możesz była niepoprawnie zamknięta. Dlaczego? Dlate-
kiej sytuacji musisz odłączyć użytkowników odłączyć także poleceniem force application, go że w pierwszej linii skryptu łączymy się do ba-
od bazy, deaktywować bazę danych (jeśli by- podając odpowiednie numery sesji, np.: force zy danych, a taka operacja domyślnie inicjuje pro-
ła wcześniej jawnie aktywowana poleceniem application (69,77,100). Wtedy jednak nie ces automatycznego uspójniania bazy po niepo-
activate database) i dopiero wtedy mo- masz gwarancji, że pomiędzy wykonaniem tej prawnym zamknięciu. Taki proces określany jest
żesz wykonać polecenie tworzące kopię bez- operacji a rozpoczęciem backup-u offline ktoś nie jako crash recovery. Na podstawie informacji z pli-
pieczeństwa. Na Listingu 1 załączyłem przy- podłączy się do bazy, co spowoduje, że wykona- ków dziennika transakcji (tzw. logów transakcyj-
kładowy skrypt, który wykonuje te operacje. nie backup-u offline nie powiedzie się. Inną, bar- nych) wycofywane są niezatwierdzone transak-
Polecenie quiesce przeprowadza bazę w tryb dzo destruktywną metodą zatrzymywania zaso- cje (ang. rollback) oraz nanoszone są na dysk te
administracyjny z jednoczesnym i natych- bów bazy jest na przykład zabicie z poziomu sys- transakcje, które były już zatwierdzone (ang. rol-
miastowym odłączeniem użytkowników od temu operacyjnego głównego procesu menadże- lforward). Jak już wcześniej wspomniałem, baza
bazy. Standardowo baza danych jest bowiem ra DB2 (db2syscs.exe w systemach Windows lub nie gwarantuje, że wykonane w pamięci zmia-
aktywowana, tzn. startowane są zasoby (pa- db2sysc w systemach Linux/UNIX) lub po pro- ny zostaną od razu naniesione na dysk do odpo-

60 SDJ Extra 35
Backup od A do Z

wiednich kontenerów, natomiast gwarantuje, razu archiwum określa się poprzez podanie (offline/online). Przykładowy fragment raportu
że każda zatwierdzona transakcja jest zapisana znacznika czasowego. Poniższy przykład od- wygenerowanego przez db2ckbkp pokazany jest
na dysk do plików dziennika transakcji. Jak wi- twarza bazę danych z katalogu c:\temp, z bac- na Listingu 2. Podanie opcji –h (mała litera „h”)
dać, dziennik transakcji jest bardzo ważnym ele- kup-u wykonanego dnia 2009.05.04 o godzi- przygotuje dokładnie ten sam raport, przy czym
mentem bazy danych. Awaria systemu, która po- nie 01.32.19 (godzina.minuta.sekunda): dodatkowo sprawdzi spójność obrazu, bez ko-
wiązana jest z uszkodzeniem bądź utratą plików nieczności odtworzenia bazy danych.
dziennika transakcji, zwykle wiąże się z koniecz- db2 restore db sample from "c:\temp" taken W tym miejscu chciałbym odnieść się do
nością odtworzenia bazy z backup-u. at 20090504013219 stwierdzenia z początku artykułu, że backup
Rezultatem pomyślnego zakończenia polece- z narzędziami DB2 jest najlepszą formą zabez-
nia db2 backup db sample jest utworzenie odpo- W poleceniu restore możesz podać skróco- pieczania danych. Przede wszystkim gwarantu-
wiedniego pliku, który jest binarnym obrazem ny punkt w czasie, np. taken at 20090504. je nam spójność oraz niezmienialność danych,
spójnej bazy danych. Nazwa pliku archiwum Ważne jest, by podany znacznik czasowy co nie zawsze jest łatwe do uzyskania np. w przy-
przyjmuje następującą postać: jednoznacznie identyfikował obraz archi- padku eksportu danych. Porównując z bezpo-
wum. Jeśli w dniu 2009.05.04 był wykony- średnią kopią systemu plików, backup zawsze
SAMPLE.0.DB2.NODE0000.CATN0000.2009050322 wany tylko jeden backup, wtedy wystarczy zajmuje mniej miejsca, ponieważ zawiera tylko
4103.001 podać 20090504. Jeśli danego dnia backup te strony, które faktycznie zawierają dane. Jest
wykonywany był wiele razy, należy doprecy- jeszcze jedna bardzo użyteczna właściwość bac-
Domyślnie plik backup-u tworzony jest w ka- zować godzinę, np. 2009050401. kup-u – podczas odtwarzania mamy możliwość
talogu, w którym zostało wykonane polecenie Jeśli nie jesteś pewny co do nazwy obrazu ar- przedefiniowania kontenerów. Funkcjonalność
backup-u. Bardzo dobrą praktyką jest podanie chiwum, zawsze możesz sprawdzić szczegóły ob- ta jest szczególnie użyteczna, jeśli odtwarzamy
w poleceniu backup database ścieżki, gdzie razu narzędziem db2ckbkp (db2 check backup). bazę danych na innym komputerze, na którym
ma być umieszczony obraz archiwum, ponie- Narzędzie uruchomione z opcją –H podaje wie- nie ma utworzonej dokładnie takiej samej struk-
waż pełna treść poleceń backup database zo- le cennych informacji, takich jak znacznik cza- tury systemu plików. Innym przypadkiem, w
staje dodatkowo zapisywana do pliku z histo- sowy zakończenia backup-u, poprawna oczeki- którym może wystąpić konieczność przedefinio-
rią operacji administracyjnych bazy (mamy wana nazwa pliku obrazu czy rodzaj archiwum wania ścieżek kontenerów, jest klonowanie bazy
wówczas informacje o lokalizacji naszego bac-
kup-u). W pliku backup-u zostaną zachowa- Listing 1. Skrypt wykonujący backup bazy w trybie OFFLINE
ne strony z danymi oraz indeksami. Co waż-
ne, zapisywane są tylko te, które zawierają da- connect to sample;
ne – strony puste nie są kopiowane, stąd ob- quiesce database immediate force connections;
raz archiwum zwykle zajmuje mniej niż pli- connect reset;
ki bazy na dyskach. Jeśli dodatkowo włączy- deactivate db sample;
my opcję kompresji backup-u (dostępna jest w backup database sample to "c:\temp";
cenie wszystkich edycji DB2), wtedy tworzony connect to sample;
obraz powinien być kilkukrotnie mniejszy (po- unquiesce database;
lecenie: backup db sample compress). connect reset;
W obrazie archiwum umieszczona jest także
konfiguracja bazy, informacje o kontenerach, a Listing 2. Sprawdzenie pliku archiwum narzędziem db2ckbkp
także plik z historią operacji administracyjnych.
W nazwie pliku archiwum zakodowany jest do- db2ckbkp -H SAMPLE.0.DB2.NODE0000.CATN0000.20090503224103.001
kładny czas wykonania archiwum, czyli tzw.
znacznik czasowy (ang. timestamp). Dla podane-
go przykładu 20090503224103 oznacza 3 maja Server Database Name -- SAMPLE
2009, 22-gą godzinę, 41-szą minutę oraz 3-cią Timestamp -- 20090504013219
sekundę. Nazwa obrazu backup-u zawiera tak- Instance -- DB2
że informację o nazwie bazy danych, dla której [..]
wykonywana była kopia bezpieczeństwa (SAM- Backup Mode -- 0
PLE) oraz nazwę instancji (DB2). By odtworzyć Includes Logs -- 0
bazę danych z backup-u, wystarczy wpisać w Compression -- 1
oknie poleceń tekstowych: DB Codeset -- UTF-8
LogPath
db2 restore db sample -- C:\DB2\NODE0000\SQL00001\SQLOGDIR\

Narzędzie odtwarzające bazę danych będzie The proper image file name would be:
oczekiwało, że w katalogu, z którego było wy- SAMPLE.0.DB2.NODE0000.CATN0000.20090504013219.001
konywane polecenie, znajdować się będzie ob-
raz archiwum, a nazwa pliku obrazu będzie Listing 3. Przykłady tworzenia obszarów tabel ze względnymi ścieżkami
zgodna z postacią przedstawioną wcześniej.
Oczywiście możesz bezpośrednio w skład- create tablespce obszar1
ni polecenia restore podać ścieżkę, z której create tablespce obszar2 managed by automatic storage
chcesz wczytać backup. Jeśli w danej ścieżce create tablespace obszar3 managed by database using (file 'obszar3' 10000)
istnieje więcej niż jeden obraz archiwum, wte- autoresize yes
dy musisz wskazać, który obraz archiwum ma create tablespace obszar4 managed by system using ( 'obszar4')
być odtworzony. Wybranie konkretnego ob-

www.sdjournal.org 61
Administracja

w ramach tego samego komputera – kopia bazy W większości dużych i wymagających baz noczesnym przedefiniowaniem kontenerów.
będzie musiała wykorzystać inny zestaw plików, danych stosuje się jednak bezwzględne ścież- Klauzula REDIRECT wykorzystana w poleceniu
tak by pliki dwóch baz danych nie ulegały wza- ki do plików obszarów tabel, ponieważ takie RESTORE instruuje narzędzie, że administra-
jemnemu nadpisywaniu. Poniższe dwa polece- obszary dają administratorowi precyzyjną tor odtwarzający bazę danych będzie powtór-
nia pozwolą na szybkie powielenie przykładowej kontrolę nad położeniem pliku, nazwą, roz- nie definiował ścieżki do kontenerów. Od te-
bazy danych SAMPLE. W rezultacie powstanie no- miarem oraz ewentualnym wykorzystaniem go momentu odtwarzanie bazy jest wstrzyma-
wa baza danych TESTDB, która ma dokładnie taką mechanizmu powiększania plików. Załóż- ne aż do czasu, gdy zostanie wydane polecenie
samą zawartość jak baza SAMPLE: my, że w przykładowej bazie danych admi- kontynuacji odtwarzania (klauzula CONTINUE),
nistrator utworzył dodatkowy obszar tabel które rozpocznie właściwe wgrywanie obrazu
db2 backup db sample TESTSPACE poleceniem jak na Listingu 4. backup-u. Zdefiniowanie nowych ścieżek dla
db2 restore db sample into testdb Utworzenie klonu bazy danych zawierają- kontenerów realizowane jest poleceniem SET
cej obszar TESTSPACE w tym samym środowi- TABLESPACE CONTAINERS, w którym nale-
Obydwa polecenia wykonają się poprawnie, za- sku będzie wymagało już przedefiniowania ży podać identyfikator obszaru tabel. W mo-
kładając, że były wykonywane z tego samego ka- kontenerów bazy, ponieważ pliki c:\DATA1\ jej przykładowej bazie danych obszar TESTDB
talogu oraz w katalogu tym nie znajdował się testspace.1 oraz c:\DATA2\testspace.2 nie miał identyfikator o numerze 7. Po zainicjo-
wcześniej żaden obraz archiwum bazy SAMPLE. mogą jednocześnie być używane przez dwie waniu odtwarzania z przekierowaniem za-
Sklonowanie bazy danych przykładów, która bazy danych. Taki rodzaj odtworzenia bazy da- wsze możesz sprawdzić identyfikatory obsza-
przychodzi z instalacją DB2, powiedzie się bez nych określany jest jako „odtwarzanie z prze- rów tabel oraz kontenery danych obszarów ta-
konieczności powtórnego definiowania ścieżek kierowaniem kontenerów” (ang. redirected re- bel poleceniami LIST TABLESPACES oraz LIST
kontenerów, ponieważ baza SAMPLE zawiera wy- store). Odtworzenie bazy danych bez prze- TABLESPACE CONTAINERS FOR <nr obszaru>,
łącznie względne ścieżki kontenerów. Względ- kierowania kontenerów zakończyłoby się po- czyli innymi słowy możesz interaktywnie od-
ne ścieżki kontenerów wykorzystywane są dla prawnie, jednak obszar tabel TESTSPACE nie pytywać obraz archiwum. W załączonym
wszystkich domyślnych obszarów tabel po- zostałby odtworzony, ponieważ DB2 wykry- przykładzie założyłem, że cała operacja wy-
wstałych przy kreowaniu bazy danych (CREATE łoby, że pliki są już wykorzystywane przez in- kona się ze skryptu, stąd też dodałem klauzu-
DATABASE), obszarów AUTOMATIC STORAGE oraz ną bazę (tu: SAMPLE). Na Listingu 5 załączyłem lę WITHOUT PROMPTING, która zakłada brak in-
obszarów, dla których po prostu nie podano skrypt, który odtwarza bazę danych pod nową terakcji z użytkownikiem. Gdybym nie podał
bezwzględnej ścieżki, tak jak na Listingu 3. nazwą TESTDB (dokładniej klonuje bazę) z jed- tej opcji w sytuacji, gdyby baza danych TESTDB
byłaby już utworzona, narzędzie RESTORE
Listing 4. Przykład utworzenia obszaru tabel z bezwzględnymi ścieżkami wstrzymałoby pracę i poprosiłoby o decyzję,
czy nadpisać istniejącą bazę.
create tablespace testspace managed by database Łatwo sobie wyobrazić, że operacja odtwa-
using (file 'c:\DATA1\testspace.1' 10000, file 'd:\DATA2\testspace.2' 10000) rzania z przekierowaniem może przysporzyć
autoresize yes maxsize 1 G; wiele pracy, jeśli baza danych składa się z bar-
create table testtab (id int) in testspace; dzo dużej liczby obszarów tabel (np. w sys-
insert into testtab values (1), (2), (3), (4), (5); temach SAP, gdzie wykorzystywanych mo-
że być nawet kilkadziesiąt kontenerów). W
Listing 5. Odtworzenie bazy danych z przekierowaniem kontenerów takich przypadkach najlepiej przygotować
skrypt, który będzie zawierał wszystkie po-
restore db sample into testdb redirect without prompting; trzebne instrukcje definiujące kontenery ba-
set tablespace containers for 7 using (file 'testdb.testspace' 20000); zy danych. Taki skrypt można automatycznie
restore db sample continue; wygenerować poniższym poleceniem:

Listing 6. Fragment skryptu wygenerowanego klauzulą RESTORE REDIRECT GENERATE SCRIPT db2 restore db sample into testdb redirect
generate script testdb.db2
-- ** Tablespace name = TESTSPACE
-- ** Tablespace ID = 7 Wygenerowany skrypt (Listing 6) będzie po-
-- ** Tablespace Type = Database managed space dobny do tego, który już wcześniej posłużył
nam do odtworzenia bazy danych w Listin-
-- ** Tablespace Content Type = All permanent data. Large table gu 5, z tą różnicą, że kontenery będą odnosiły
space. się do plików aktualnie wykorzystywanych w
-- ** Tablespace Page size (bytes) = 8192 bazie SAMPLE. Przed uruchomieniem skryptu
-- ** Tablespace Extent size (pages) = 32 należy oczywiście zmienić ścieżki kontene-
-- ** Using automatic storage = No rów, tak by były poprawne w nowym środo-
-- ** Auto-resize enabled = Yes wisku. Wygenerowany automatycznie skrypt
-- ** Total number of pages = 20000 znacznie ułatwia odtwarzanie z przekiero-
-- ** Number of usable pages = 19904 waniem, ponieważ proponuje instrukcje SET
-- ** High water mark (pages) = 160 TABLESPACE CONTAINERS wyłącznie dla obsza-
-- ***************************************************************************** rów tabel, które mogą tego wymagać: przykła-
SET TABLESPACE CONTAINERS FOR 7 dowo pomija obszary automatycznie zarzą-
USING ( dzanych przez bazę danych. Wygenerowany
FILE 'c:\DATA1\testspace.1' 10000, automatycznie skrypt zawiera także dodat-
FILE 'd:\DATA2\testspace.2' 10000 kowe informacje opisujące wszystkie obszary
); tabel, takie jak rozmiar obszaru, rozmiar stro-
ny, znacznik włączenia automatycznego po-

62 SDJ Extra 35
Backup od A do Z

większania plików (AUTORESIZE) czy znacz- nia na miejsce w dzienniku transakcji aż do db2 restore db sample
nik automatycznego zarządzania obszarem osiągnięcia limitu łącznej liczby logów okre- db2 rollforward db sample to 2009-04-03-
(AUTOMATIC STORAGE). ślonych przez sumę LOGPRIMARY i LOGSECOND. 14.21.56 using local time and stop
Backup offline ma jedną wielką zaletę – po- Innymi słowy, dostępny dla transakcji obszar
nieważ zawiera spójny obraz bazy danych, dla- roboczy dziennika wyznaczony jest przez su- Do wykonania operacji rollforward potrzebne
tego odtwarzanie bazy danych z takiego archi- mę dzienników podstawowych LOGPRIMARY będą pliki dziennika – stąd prosty wniosek, że
wum jest bardzo proste. Backup offline ma jed- oraz dodatkowych LOGSECOND. Jedyna różni- pliki dziennika powinny być odpowiednio za-
nak także jedną znaczną wadę – jego wykona- ca pomiędzy tymi typami logów związana bezpieczone, tak by były pod ręką podczas od-
nie wymaga odłączenia użytkowników od ba- jest z momentem przydzielania i zwalniania twarzania bazy. DB2 można tak skonfigurować,
zy. W wielu systemach, które pracują w trybie dla nich miejsca. by pliki dziennika były automatycznie archiwi-
ciągłym 24x7, po prostu nie ma możliwości Domyślnie po utworzeniu bazy danych dzien- zowane. Konfigurację dziennika transakcji naj-
wstrzymania pracy użytkowników. W takich nik transakcji pracuje w trybie cyklicznym, tzn. prościej wykonać, wykorzystując DB2 Control
przypadkach z pomocą przychodzi archiwum transakcje zapisywane są najpierw do pierwsze- Center: uruchom narzędzie, wpisując db2cc,
online, które może być wykonywane na aktyw- go pliku dziennika, potem do drugiego, trzeciego zaznacz bazę danych, którą chcesz konfiguro-
nej bazie danych. By wykonać backup podczas itd. Po zapisaniu ostatniego pliku dziennika ba- wać, kliknij prawym klawiszem i wybierz „Con-
normalnej pracy bazy danych, w poleceniu za znów zaczyna pisać do pierwszego pliku i cały figure Database Logging…”. Na pierwszym ekranie
BACKUP należy dodać słowo kluczowe online: proces powtarza się aż w nieskończoność. wybierz tryb archiwalny dziennika. Na następ-
W trybie archiwalnym pliki dziennika nig- nym ekranie masz możliwość skonfigurowania
db2 backup db sample online dy nie są nadpisywane. Gdy zostanie zapisany metody archiwizacji dziennika. Zalecaną meto-
pierwszy plik dziennika, baza zaczyna pisać do dą archiwizowania plików dziennika jest zlece-
Powyższe polecenie powiedzie się jednak tyl- następnego w kolejności pliku i jednocześnie nie tego zadania samej bazie danych, tak jak po-
ko wtedy, gdy dziennik transakcji bazy danych rozpoczyna przydzielanie miejsca dla nowe- kazałem to na Rysunku 1. Pliki dziennika moż-
jest odpowiednio skonfigurowany do pracy w go pliku o najwyższym kolejnym numerze. Ta- na składować na dysku z wykorzystaniem IBM
trybie archiwalnym (ang. archive logging). ka organizacja dzienników transakcji pozwala Tivoli Storage Manager (TSM) bądź przy pomo-
przechować pełną historię operacji na bazie da- cy dowolnego wspieranego oprogramowania
Konfiguracja nych. Archiwalne dzienniki transakcji w połą- backup-owego (Vendor DLL). Jeśli ze względów
dziennika transakcji czeniu z obrazem backup-u pozwalają na od- kosztowych nie będziesz dysponował bibliote-
Dziennik transakcji w DB2 to zestaw plików, tworzenie bazy danych do dowolnego punk- ką taśmową i wybierzesz dysk, upewnij się, że
do których baza danych zapisuje wszystkie in- tu w czasie. Odtworzenie bazy danych z wyko- archiwalne pliki dziennika są składowane na
formacje o modyfikacjach danych. To właśnie rzystaniem archiwalnych dzienników transak- innym fizycznym dysku, niż baza danych. Ta-
dzięki dziennikowi transakcji możliwe jest cji składa się z dwóch faz: kie podejście zapewni większe bezpieczeństwo
wycofywanie transakcji (rollback) oraz auto- logów – w przeciwnym przypadku ewentual-
matyczne uspójnianie bazy danych po awarii • Restore – odtworzenia archiwum (online na awaria dysków bazy pociągnie za sobą także
(crash recovery). Pliki dziennika transakcji alo- bądź offline); awarię archiwum dziennika transakcji.
kowane są na dysku w momencie aktywacji • Rollforward – powtórzenia transakcji z Plik dziennika transakcji jest automatycznie
bazy danych. Liczba plików dziennika okre- dzienników do określonego punktu w archiwizowany zaraz po jego zapełnieniu. Ła-
ślona jest przez parametr bazy LOGPRIMARY, czasie. two dojść do wniosku, że rozmiar pliku dzien-
natomiast rozmiar pojedynczego pliku przez nika pośrednio wpływa na bezpieczeństwo da-
parametr LOGFILSIZ (wyrażony jest w stro- Poniżej przedstawiłem przykład odtworze- nych. Bardzo duży plik oznacza, że będzie on
nach 4KB). Ustawienie parametrów dzienni- nia bazy danych do punktu w czasie: archiwizowany stosunkowo rzadko, ponieważ
ka transakcji na następujące wartości:

LOGFILSIZ = 10000
LOGPRIMARY = 30

oznacza, że przy starcie bazy danych zosta-


nie zaalokowane około 1.2 GB logów w pli-
kach o automatycznie generowanych na-
zwach S0000000.LOG, S0000001.LOG,
S0000002.LOG, …, S0000029.LOG. Oczy-
wiście pliki dziennika nie są alokowane przy
każdorazowej aktywacji bazy danych, a je-
dynie za pierwszym razem albo gdy zosta-
ły zmienione parametry dziennika, takie jak
rozmiar pliku, liczba plików czy ścieżka pli-
ków. Istnieje jeszcze jeden parametr mają-
cy wpływ na liczbę zaalokowanych plików
dziennika – LOGSECOND. Parametr ten okre-
śla liczbę plików, które mogą być dodatko-
wo przydzielone, jeśli w podstawowym ob-
szarze dziennika określanym przez parametr
LOGPRIMARY brakuje już miejsca, by obsłużyć
bieżącą transakcję. Dodatkowe logi alokowa-
ne są dynamicznie, zależnie od zapotrzebowa- Rysunek 1. Ekran konfiguracji archiwalnego trybu dziennika transakcji

www.sdjournal.org 63
Administracja

może minąć dużo czasu zanim zostanie on za- nie archiwalnego trybu pracy dziennika trans- danych, więc po włączeniu archiwalnego try-
pełniony. Natomiast zbyt mały plik może ne- akcji odpowiada parametr LOGARCHMETH1. Pa- bu wykorzystałem narzędzie db2dart do usu-
gatywnie wpłynąć na wydajność ze względu rametr ten jednocześnie definiuje metodę ar- nięcia znacznika BACKUP PENDING.
na bardzo częste odwoływanie się do systemu chiwizacji. Poniżej przedstawiłem instrukcję
backup-owego. Rozmiar pliku dziennika najle- zmiany parametrów odpowiadającą wprowa- db2dart sample /CHST /WHAT DBBP OFF
piej dopasować do aktywności systemu, tak by dzonym wartościom z Rysunku 1:
przykładowo pomieścił transakcje za 30 mi- Po pomyślnym wykonaniu powyższego po-
nut przetwarzania. Baza danych automatycz- UPDATE DB CFG FOR SAMPLE USING lecenia użytkownicy będą mogli już praco-
nie usuwa zarchiwowane pliki dziennika z bie- logarchmeth1 "DISK:D:\DB2_ARCH_ wać na bazie danych.
żącego katalogu, jednak dopiero wtedy, gdy już LOGS" failarchpath "C:\DB2_TEMP_ By zademonstrować wykorzystanie backup-
nie są potrzebne do bieżącego przetwarzania. ARCH_LOGS" ów online, przygotowałem skrypt do załadowa-
Jeśli dziennik zawiera aktywną (niezatwier- nia przykładowej tabeli tab1 milionem rekor-
dzoną) transakcję, wtedy może być potrzeb- Po zmianie trybu pracy dziennika transak- dów (Listing 7). Skrypt uruchomiłem z jednego
ny do wycofania zmian, gdyby aplikacja zde- cji z cyklicznego na archiwalny baza danych okna linii poleceń DB2 (db2 –td@ –vf nazwa_
cydowała się wykonać instrukcję rollback. Na wymusza zrobienie archiwum offline. Jeśli skryptu), natomiast z drugiego okna urucho-
Rysunku 1 przedstawiłem przykładowy ekran nie wykonamy backup-u, DB2 nie pozwoli miłem backup w trybie online (db2 backup db
konfiguracji dziennika transakcji narzędzia podłączyć się do bazy danych, generując ko- sample online compress). Backup bazy danych
DB2 Control Center – dla konfigurowanej munikat, że baza danych jest w stanie ocze- wykonał się równolegle z procesem ładowania
bazy archiwalne pliki dziennika będą przeno- kiwania na backup: danych. Plik backup-u online odzwierciedla stan
szone na dysk do katalogu D:\DB2_ARCH_LOGS bazy danych na określony punkt w czasie i jest
(Primary archive log path). Gdyby okazało się, SQL1116N A connection to or activation swojego rodzaju migawką (ang. snapshot) da-
że podstawowe miejsce archiwizowania dzien- of database "SAMPLE" cannot be nych. Baza danych pilnuje, by w obrazie archi-
nika jest niedostępne (np. system plików jest made because of BACKUP PENDING. wum nie znalazły się strony zmodyfikowane już
zapełniony; w przypadku biblioteki taśmowej SQLSTATE=57019 po uruchomieniu backup-u (dokładniej: strony
może to oznaczać chwilową niedostępność starsze, niż znacznik czasowy archiwum). Jeśli
związaną z pozycjonowaniem taśmy), wtedy Bez początkowego punktu odniesienia nie da któraś ze stron zostanie napisana nową zawarto-
plik dziennika będzie tymczasowo przenie- się odtworzyć zmian zapisanych w dzienni- ścią, wtedy DB2 sięga do dziennika transakcji,
siony do katalogu C:\DB2_TEMP_ARCH_LOGS kach transakcji. Archiwalne dzienniki trans- by stamtąd pobrać starszą wersję strony.
(Failure archive log path). Plik ten będzie auto- akcji są bezużyteczne bez backup-u, stąd ko- Podczas ładowania danych dzienniki trans-
matycznie umieszczony we właściwym archi- nieczność wykonania archiwum całościowego. akcji były sukcesywnie zapełniane i przenoszo-
wum, jak tylko baza wykryje, że podstawowe Istnieje możliwość rozpoczęcia pracy z bazą ne do archiwum, czyli w naszym przypadku
archiwum jest już dostępne. bez konieczności wykonywania backup-u. Na- do katalogu D:\DB2_ARCH_LOGS. Tak napraw-
Na następnych ekranach można doprecyzo- rzędziem db2dart możesz wyłączyć stan ocze- dę DB2 w katalogu wskazywanym przez pa-
wać pozostałe parametry dziennika oraz para- kiwania na backup (BACKUP PENDING), a archi- rametr LOGARCHMETH1 tworzy szereg dodatko-
metry backup-u. Na ostatnim ekranie narzę- wum całościowe wykonać w trybie online przy wych podkatalogów, by jednoznacznie iden-
dzia konfigurującego znajduje się podsumo- pracujących użytkownikach. Pamiętaj jednak, tyfikować logi, gdyby z tej samej ścieżki archi-
wanie wykonywanych operacji. Warto przej- by nie wykonywać takiej operacji na systemie wum korzystało wiele baz danych. Pełna ścież-
rzeć wygenerowany skrypt (zakładka Suma- produkcyjnym, gdyż do momentu zakończe- ka archiwalnych logów ma postać:
ry->przycisk Show Command), by zapoznać nia backup-u wprowadzane transakcje nie bę-
się z parametrami DB2, które odpowiadają za dą zabezpieczone. Ponieważ na potrzeby napi- D:\DB2_ARCH_LOGS\DB2\SAMPLE\NODE0000\
konfigurację dziennika transakcji. Za włącze- sania tego artykułu pracuję na testowej bazie C0000000

Listing 7. Skrypt ładujący przykładową tabelę TAB1 milionem rekordów


Na tej ścieżce znajdować się będą pliki archi-
walnych dzienników:
CREATE TABLE tab1 (id INT, czas TIMESTAMP)@
CREATE PROCEDURE laduj_tab1() ...
BEGIN 2009-05-11 23:56 4 104 192 S0000006.LOG
DECLARE i INT DEFAULT 0; 2009-05-11 23:56 4 104 192 S0000007.LOG
2009-05-11 23:56 4 104 192 S0000008.LOG
-- Zatwierdź długą transakcję, gdy wystąpi komunikat zapełnienia dziennika 2009-05-11 23:57 4 104 192 S0000009.LOG
DECLARE CONTINUE HANDLER FOR SQLSTATE '57011' ...
COMMIT;
Zarchiwizowane dzienniki transakcji peł-
WHILE (i < 1000000) nią kluczową rolę przy odtwarzaniu backup-
DO u wykonanego w trybie online. Tak naprawdę
INSERT INTO tab1 VALUES ( i, current timestamp); bez zarchiwowanych dzienników transakcji
SET i = i + 1; backup jest bezużyteczny! Dlaczego? Rezulta-
END WHILE; tem wykonania polecenia RESTORE DATABASE
COMMIT; jest utworzenie bazy danych, której stan jest
END @ dokładnym odzwierciedleniem stanu bazy z
momentu wykonania archiwum. Backup on-
CALL laduj_tab1() @ line wykonywaliśmy równolegle z aplikacją ła-
dującą dane, co oznacza, że odtworzona baza
danych jest niespójna, ponieważ zawiera nie-

64 SDJ Extra 35
Backup od A do Z

zatwierdzone transakcje. Próba podłączenia line. Backup online bez dzienników transakcji Pierwsze polecenie odtworzy bazę i jedno-
się skutkuje błędem, informującym że baza jest bezwartościowy, ponieważ tylko przy uży- cześnie przekopiuje dzienniki transakcji za-
danych jest w stanie oczekiwania na wykona- ciu logów można wyprowadzić bazę ze stanu warte w obrazie archiwum do katalogu c:\
nie operacji ROLLFORWARD. ROLL-FORWARD PENDING. temp. Drugie polecenie przetworzy wszystkie
Utrata logów mogłaby wiązać się z jedno- dzienniki transakcji (klauzula to TO END OF
db2 restore db sample replace existing czesną utratą backup-ów online. By zabezpie- LOGS) z katalogu c:\temp (klauzula OVERFLOW
db2 connect to sample czyć się przed taką sytuacją, DB2 standardo- LOG PATH) i udostępni bazę użytkownikom
SQL1117N A connection to or activation of wo dołącza pliki dziennika do obrazu bac- (klauzula AND STOP). W przypadku backup-
database "SAMPLE" cannot be made kup-u. Musisz jednak pamiętać, że takie za- ów wykonanych w trybie offline istnieje moż-
because of ROLL-FORWARD PENDING. chowanie bazy domyślnie dostępne jest od liwość udostępnienia bazy danych użytkow-
SQLSTATE=57019 wersji 9.5. We wcześniejszych wersjach, np. nikom bez konieczności wykonywania pole-
9.1 czy 8.2, logi należy dołączać w jawny spo- cenia ROLLFORWARD. W tym celu należy wyko-
W takiej sytuacji tylko przy pomocy dzien- sób poprzez użycie klauzuli INCLUDE LOGS: rzystać klauzulę WITHOUT ROLLING FORWARD:
ników transakcji będzie można uspójnić ba-
zę i udostępnić ją użytkownikom. Wykona- db2 backup db sample online include logs db2 restore db sample without rolling
nie polecenia: forward
Po wykonaniu tego polecenia pliki dziennika
db2 ROLLFORWARD DB SAMPLE TO END OF LOGS potrzebne do odtworzenia bazy danych (na Odzyskanie bazy
moment zakończenia wykonywania całościo- jednym poleceniem
odczyta wszystkie dostępne archiwalne pli- wego archiwum) zostaną dokopiowane do ob- Dla uproszczenia odtwarzania bazy danych po
ki logów i powtórnie wykona zapisane w nich razu archiwum. Dołączenie logów zawierają- awarii dostępne jest także polecenie RECOVER
transakcje. W składni polecenia ROLLFORWARD cych aktywne transakcje jest zupełnie nieza- DATABASE, które automatyzuje proces dogry-
nie musiałem podawać lokalizacji odtwarza- leżne od mechanizmu archiwacji dziennika wania transakcji z dzienników. Poniższe po-
nych dzienników, ponieważ jest ona zapisana transakcji. W rezultacie aktywne dzienniki ko- lecenie automatycznie sięgnie po odpowied-
w konfiguracji bazy, która także jest odtwa- piowane są w dwa miejsca. Odpowiednią klau- ni obraz backup-u oraz po odpowiednie pliki
rzana podczas polecenia RESTORE. Wykona- zulą LOGTARGET polecenia RESTORE możesz od- dziennika transakcji, tak by przywrócić bazę
nie polecenia ROLLFORWARD może być powta- zyskać pliki dziennika dołączone wcześniej do danych na określony punkt w czasie:
rzane wielokrotnie. Takie podejście często sto- obrazu archiwum. Zakładając, że archiwum
suje się przy migracjach bazy na inny, wydaj- logów nie jest dostępne (np. utraciliśmy archi- db2 recover database baza1 to 2009-05-13-
niejszy komputer (w ramach tego samego sys- wum logów, ale mamy backup bazy online), od- 09.07.51.000000 using local time
temu operacyjnego), by zminimalizować czas tworzenie bazy online wygląda następująco:
przestoju związany z przełączeniem aplika- Polecenie RECOVER wykorzystuje systemowy
cji na nowy system. Na pierwotnym systemie db2 restore db sample logtarget c:\temp plik bazy danych Recovery History File, w któ-
wykonujemy backup online, który wgrywamy db2 rollforward db sample to end of logs rym przechowywana jest historia operacji ad-
na system docelowy. W tym czasie na źródło- and stop overflow log path (c: ministracyjnych. Poleceniem list history
wym systemie odkładają się dzienniki transak- \temp) możesz sprawdzić, kiedy były wykonywane
cji, które na bieżąco przenosimy do docelowe-
go systemu i wgrywamy ich zawartość, wielo- Listing 8. Sprawdzenie stanu przetworzonych logów dla operacji ROLLFORWARD
krotnie wykonując operację ROLLFORWARD. Po
zatrzymaniu bazy źródłowej wystarczy prze- db2 rollforward db sample query status
nieść i dograć tylko ostatni log (logi), a następ- Rollforward Status
nie podłączyć użytkowników do bazy w no-
wym środowisku. Czas przestoju aplikacji jest Input database alias = sample
równy czasowi wgrywania ostatniego logu. Number of nodes have returned status = 1
Przy wielokrotnym wgrywaniu logów bardzo Node number = 0
pomocne jest polecenie ROLLFORWARD z klauzu- Rollforward status = DB working
lą QUERY STATUS pokazujące numer następ- Next log file to be read = S0000015.LOG
nego logu, który będzie przetwarzany przy ko- Log files processed = S0000000.LOG – S0000015.LOG
lejnym wykonaniu polecenia ROLLFORWARD (Li- Last committed transaction = 2009-05-13-09.07.51.000000 UTC
sting 8).
Jeśli chcemy zakończyć operację dogry- DB20000I The ROLLFORWARD command completed successfully.
wania kolejnych logów i udostępnić bazę da-
nych użytkownikom, musimy wydać polece- Listing 9. Dostęp do historii operacji administracyjnych z widoku systemowego
nie ROLLFORWARD z klauzulą STOP bądź rów-
noważną klauzulą COMPLETE. Przed udostęp- select eid, operation, start_time from sysibmadm.db_history
nieniem bazy do normalnej pracy wszystkie EID OPERATION START_TIME
niezatwierdzone transakcje zostaną automa- --- --------- --------------
tycznie wycofane, tak by baza była spójna. In- 1 O 20090511235132
formacje potrzebne do wycofania transakcji 2 A 20090511235132
zostaną pobrane z wcześniej wykorzystanych 3 X 20090511235637
archiwalnych dzienników transakcji. Jak wi- 4 B 20090511235638
dać, archiwalne dzienniki transakcji pełnią 5 R 20090514000647
bardzo ważną rolę, ponieważ bez nich nie da 6 F 20090523145136
się uspójnić bazy odtworzonej z backup-u on-

www.sdjournal.org 65
Administracja

operacje administracyjne na bazie danych. informacji, w szczególności zawiera informa- Najpierw w pierwszym oknie wykonałem
Przykładowo, poniższe polecenie pokaże, kie- cje o zdarzeniach, które zostały wykonane już archiwum całościowe bazy danych:
dy i na jaki nośnik były archiwowane poszcze- po wykonaniu backup-u. Porównując skład-
gólne dzienniki transakcji: nię obu poleceń, warto zwrócić uwagę, że do- db2 backup db sample online compress
danie słowa REPLACE zupełnie zmienia sens
db2 list history archive log since 200905 polecenia. W takim przypadku odtwarzana W moim systemie archiwum zostało opatrzo-
for sample jest zarówno baza danych, jak i plik z historią. ne znacznikiem czasowym 20090528141351,
który umownie nazwałem TS1. W archiwum
Zawartość pliku z historią można także po- Odtwarzanie bazy znalazły się wszystkie obszary tabel, włącza-
dejrzeć, sięgając do widoku systemowego w trybie online jąc obszar USERSPACE1, IBMDB2SAMPLEREL
SYSIBMADM.DB _ HISTORY. Przykładowo, po- Konieczność odtworzenia bazy danych z ar- oraz systemowy słownik bazy danych (ang.
niższa instrukcja SQL poda czasy rozpoczę- chiwum może oznaczać określoną przerwę system catalog). Następnie z drugiego okna
cia operacji administracyjnych, rodzaj opera- w pracy systemu. Jeśli zbyt rzadko będziesz utworzyłem nowy obszar tabel OBSZAR1, a w
cji (O – usunięcie obszaru tabel, A – dodanie wykonywał archiwum całościowe, wtedy od- nim nową tabelę tab1, którą załadowałem da-
obszaru tabel, X – archiwizacja logu, B – bac- tworzenie bazy danych może wydłużyć się ze nymi z tabeli org. Tabela org jest jedną z przy-
kup bazy, R – odtworzenie bazy, F – operacja względu na konieczność przetworzenia dużej kładowych tabel bazy SAMPLE i znajduje się w
powtórzenia transakcji z logów) oraz identyfi- ilości archiwalnych dzienników. Przygotowu- obszarze tabel USERSPACE1.
kator wpisu do pliku historii (patrz Listing 9). jąc odpowiednią strategię archiwacji, możesz
Plik z historią operacji administracyjnych wykorzystać nie tylko archiwum całościowe, db2 create tablespace obszar1
jest także zawarty w obrazie backup-u ba- ale także archiwum danego obszaru tabel, ar- db2 create table tab1 like org in obszar1
zy danych. Odpowiednią opcją polecenia chiwa przyrostowe, delty oraz archiwizowane db2 insert into tab1 select * from org
RESTORE można odtworzyć plik historii. W na bieżąco dzienniki transakcji.
przykładzie poniżej aktualnie używany plik z W celu przyspieszenia odtwarzania bazy da- Po załadowaniu tabeli wykonałem backup
historią zostanie nadpisany plikiem wyodręb- nych istnieje możliwość odtworzenia na począ- online obszaru OBSZAR1 oraz backup obsza-
nionym z obrazu backup-u. Dodanie słowa tek tylko wybranych obszarów tabel. Po uru- ru systemowego SYSCATSPACE, który zawie-
kluczowego ONLINE pozwoli podmienić plik chomieniu kluczowych aplikacji, które pracu- ra wszystkie definicje obiektów.
historii w trakcie pracy bazy danych: ją na tabelach z tych obszarów, możesz odtwo-
rzyć pozostałe obszary już w trakcie pracy ba- db2 backup db sample tablespace(obszar1,sy
db2 restore db sample history file online zy danych (odtwarzanie online), a następnie do- scatspace) online compress
grać modyfikacje z dziennika transakcji. Wybra-
Wykorzystanie tego polecenia może okazać nie takiej strategii odtwarzania wymaga jednak Archiwum zostało opatrzone znacznikiem
się przydatne, gdy odtwarzamy obraz bac- przemyślanego podziału bazy danych na logicz- czasowym 20090528182420, który umow-
kup-u do istniejącej bazy danych. W takiej ne obszary, na których aplikacje mogą praco- nie nazwałem TS2.
sytuacji DB2 standardowo zachowuje plik wać niezależnie od siebie (np. dane bieżące i da- Następnie w drugim oknie linii poleceń
z historią znajdujący się na dyskach. Gdy- ne z zeszłych lat). W dokumentacji DB2 Infor- uaktualniłem tabelę ORG oraz tabelę TAB1, by
by okazało się, że jest on uszkodzony, wtedy mation Center znajdziesz wiele scenariuszy od- zasymulować pracę użytkowników wykona-
powyższe polecenie pozwoli przywrócić je- twarzania danych online (szukaj po słowie klu- ną już po zrobieniu backup-u obszaru tabel.
go zawartość. Plik z historii można nadpisać czowym REBUILD oraz RESTORE TABLESPACE).
także podczas odtwarzania bazy danych: Odtwarzanie online zademonstruję na przykła- db2 update tab1 set location = 'Denver!'
dzie bazy danych SAMPLE, która ma włączoną where location = 'Denver'
db2 restore db sample replace history file archiwizację dziennika transakcji. W tym ce- db2 update org set location = 'Denver!'
lu uruchomię dwa okna linii poleceń DB2.W where location = 'Denver'
Jednak lepiej jest zachować istniejący plik na pierwszym będę wykonywał operacje admini-
dyskach bazy, ponieważ zawiera on komplet stracyjne, a w drugim instrukcje SQL. Poszczególne kroki opisane w przykładzie
zobrazowałem na Rysunku 2.
SYSCATSPACE SYSCATSPACE
Następnie deaktywowałem bazę danych,
by mieć gwarancję, że bieżący plik transak-
cji zostanie przeniesiony do archiwum. Prze-
USERSPACE1 USERSPACE1 niesienie do archiwum częściowo zapełnio-
nego logu mogę także wymusić poleceniem
IMBDB2SAMPLERE IMBDB2SAMPLERE ARCHIVE LOG, tak jak na przykładzie poniżej:

OBSZAR 1 db2 archive log for database sample

Teraz spróbuję usunąć bazę danych polece-


niem DROP DATABASE, a następnie odtworzyć
Backup online ją z archiwum. Proces odtwarzania będzie za-
obszaru 1
leżał od przyjętych założeń. Na potrzeby tego
Sesja 1 Czas
ćwiczenia założyłem, że w obszarze OBSZAR1
znajdują się bieżące dane niezbędne do działa-
Sesja 2 TS1 TS2 Madyfikacje tabeli w nia mojej aplikacji, dlatego też obszar ten nale-
obszarach OBSZAR1 i ży odtworzyć w pierwszej kolejności. Założy-
USERSPACE1
łem także, że pozostałe obszary tabel (USER-
Rysunek 2. Strategia backup-u z wykorzystaniem backup-u obszaru tabel SPACE1 oraz IBMDB2SAMPLEREL) zawierają da-

66 SDJ Extra 35
Backup od A do Z

ne historyczne, dlatego też mogą być odtwo- kim wywołaniem jednak nie osiągniemy za- Błędy administratora można zminimalizować
rzone w późniejszym czasie. mierzonego efektu, by jak najszybciej udostęp- poprzez podnoszenie kwalifikacji oraz poprzez
Wykorzystując klauzulę REBUILD WITH nić bazę użytkownikom. Proces odtwarzania zautomatyzowanie wszystkich powtarzalnych
TABLESPACE, odtwarzam OBSZAR1 oraz słow- jest prostszy, natomiast baza będzie dostępna operacji, takich jak wykonywanie backup-ów.
nik systemowy SYSCATSPACE, bez którego dopiero po odtworzeniu wszystkich obszarów Harmonogramowanie backup-ów zgodnie z
żadna baza danych nie może funkcjonować: tabel znajdujących się w backup-ach TS1 i TS2. określonym kalendarzem możemy zrealizować,
W tym miejscu chciałbym zwrócić uwagę, wykorzystując Centrum Zadań (Task Center).
db2 restore db sample rebuild with że podany przykład odtwarzania online opie- Uruchamianie backup-ów możemy także zlecić
tablespace (syscatspace, obszar1) rał się na założeniu, że odtwarzana baza da- samej bazie danych. By skonfigurować automa-
taken at 20090528182420 nych jest usunięta w całości. Zależnie od rodza- tyczne backup-owanie bazy, w narzędziu DB2
db2 rollforward db sample to end of logs ju awarii może zdarzyć się, że część plików ba- Control Center kliknij prawym klawiszem nad
and stop zy została usunięta, natomiast część pozosta- bazą danych i wybierz opcję automatycznej kon-
ła na dyskach. Narzędzie odtwarzające bazę na serwacji (Configure Automatic Maintenance). Na
Po wykonaniu powyższych operacji tabela podstawie plików konfiguracyjnych bazy zasta- odpowiednich ekranach narzędzia będziesz miał
TAB1 z obszaru OBSZAR1 jest dostępna i zawie- nych na dyskach jest w stanie określić, jakie pli- możliwość zdefiniowania reguł określających, jak
ra modyfikacje wykonane po czasie TS2. Użyt- ki przynależały do uszkodzonej bazy danych, tak często DB2 będzie wykonywało backup. Narzę-
kownicy mogą już pracować z tą tabelą. Tabela by można było je bezpiecznie nadpisać zawar- dzie pozwala także zdefiniować czasowe okno
ORG z obszaru USERSPACE1 jest natomiast cią- tością z backup-u. Gdyby pliki konfiguracyjne konserwacji bazy, w którym będą wyzwalane
gle niedostępna i wymaga odtworzenia z bac- nie były dostępne (np. katalog SQL00001 został- automatyczne operacje. Na Rysunku 5 przed-
kup-u (pozostałe obszary tabel są już widocz- by usunięty), wtedy może okazać się koniecz- stawiłem przykładowy ekran konfiguracji au-
ne, jednak nie zawierają danych). Odtwarzanie ne ręczne wyczyszczenie katalogów zajmowa- tomatycznych backup-ów – w tym przypadku
reszty obszarów tabel może być już wykonane nych przez poprzednią bazę danych (także ręcz- backup-y będą wykonywane nie rzadziej niż raz
przy aktywnej bazie danych: ne odkatalogowanie bazy poleceniem UNCATALOG na dwa dni oraz na tyle często, by ilość transakcji
DATABASE oraz usunięcie lokalnego wykazu baz odłożonych w logach pomiędzy backup-ami nie
db2 restore db sample tablespace SQLDBDIR). Takie zachowanie ma zapobiec nad- przekroczyła 100 MB.
(IBMDB2SAMPLEREL, USERSPACE1) pisaniu plików, co do których baza nie ma pew- W firmach, które muszą zarządzać kilkoma
online taken at 20090528141351 ności, że pochodzą od uszkodzonej bazy, a nie od bazami danych, trudno wyobrazić sobie życie
innych baz, aplikacji czy użytkowników. W przy- bez dedykowanego oprogramowania do auto-
db2 rollforward db sample to end padkach awarii systemu plików (awarii dysków) matyzacji backup-u, takiego jak IBM Tivoli Sto-
of logs and stop tablespace standardowo najpierw odtwarza się system ope- rage Manager (TSM). Zadania realizowane przez
(IBMDB2SAMPLEREL, USERSPACE1) racyjny (np. binarna bazy), a następnie bazę da- TSM znacznie wybiegają poza funkcje obsługi
online nych z backup-u. Innym możliwym podejściem bibliotek taśmowych. TSM automatycznie mon-
jest odtworzenie „czystego” systemu operacyjne- tuje taśmy, dokonuje konsolidacji i defragmenta-
Po wykonaniu powyższych operacji tabe- go, następnie powtórna instalacja oprogramowa- cji danych na odpowiednich taśmach, sprawdza-
la ORG będzie dostępna dla użytkowników. nia i dopiero na samym końcu odtworzenie bazy jąc ich poprawność. TSM pozwala na scentralizo-
Kolejność wykonanych operacji odtwarzania z backup-u. Takie podejście zajmuje jednak wię- wane backup-owanie zarówno baz danych, jak i
bazy została przedstawiona na Rysunku 3. cej czasu i stosowane jest stosunkowo rzadko. systemów plików (zcentralizowane harmonogra-
Polecenie RESTORE z klauzulą REBUILD w mowanie). Wykorzystanie TSM pozwala dużo
razie potrzeby może odwoływać się także do Tivoli Storage Manager szybciej odtworzyć bazę danych, ponieważ star-
wcześniej wykonanych backup-ów. W poda- Z awariami sprzętu najłatwiej poradzić sobie sze obrazy backup-ów mogą być automatycznie
nym przykładzie słownik systemowy został poprzez zastosowanie redundancji, czyli nad- migrowane na wolniejsze nośniki (taśmy, dyski).
odtworzony bezpośrednio z backup-u identy- miarowych elementów systemu. Jak jednak po- TSM automatycznie zarządza także kluczami
fikowanym znacznikiem TS2 (backup obsza- radzić sobie z błędami człowieka? Jak pokazują szyfrowania, co pozwala na odpowiednią ochro-
rów). Gdyby backup TS2 nie zawierał słowni- statystyki, czynnik ludzki to druga najczęstsza nę backup-ów przed ewentualną kradzieżą no-
ka systemowego bazy danych, przedstawiony przyczyna utraty danych (patrz Rysunek 4). śników, na których są one składowane.
scenariusz odtwarzania także powiódłby się,
przy czym słownik odtworzony byłby automa-
SYSCATSPACE
tycznie z backup-u TS1, a wszystkie zmiany na
słowniku byłyby naniesione z dziennika trans-
USERSPACE1
akcji. By przyspieszyć proces odtwarzania, naj- USERSPACE1
lepiej jednak dołączyć słownik systemowy do
backup-owanego obszaru tabel. Tak naprawdę IMBDB2SAMPLERE
IMBDB2SAMPLERE
do odtworzenia całej bazy danych wystarczy
wskazać wyłącznie drugi backup TS2: OBSZAR 1
ROLLFORWARD
operacji w Obszarze1
db2 restore db sample rebuild with all wykonanych po TS2
tablespaces in database taken at
20090528182420
db2 rollforward db sample to end of logs
RESTORE RESTORE Czas
and stop
Obszaru1 z backup-u TS1
backupu TS2
Narzędzie automatycznie sięgnie po poprzed-
ni backup i odtworzy także pozostałe (IBMD-
B2SAMPLEREL, USERSPACE1) obszary tabel. Ta- Rysunek 3. Kolejność odtwarzania z wykorzystaniem backup-u obszaru tabel

www.sdjournal.org 67
Administracja

Wykorzystanie TSM do backup-owania db2 set util_impact_priority for 29 to 10 Tak wykonaną kopię plików bazy danych mo-
baz relacyjnych wymaga zastosowania kom- żemy już backup-ować na taśmę z drugiego
ponentu IBM Tivoli Storage Manager for Da- Po wykonaniu powyższego polecenia zada- komputera bez obciążania podstawowego sys-
tabases. W przypadku DB2 ta funkcjonalność nie o identyfikatorze 29 (backup z Listin- temu. Procedura odtworzenia bazy danych po-
jest wbudowana w bazę danych (standardo- gu 10) będzie konsumowało do 10% dostęp- lega na nadpisaniu plików uszkodzonej bazy
wa licencja DB2 oraz Informix Dynamic Se- nych zasobów. plikami z tak zrobionego archiwum. Wykorzy-
rver obejmuje także licencję klienta TSM do Co jednak zrobić w sytuacji, w której z jed- stując narzędzie db2inidb, zmieniamy stan sko-
wykonywania backup-ów bazy). Po skonfigu- nej strony obniżenie priorytetu backup-u po- piowanych plików bazy danych, by można by-
rowaniu środowiska TSM backup wykonuje woduje jego wydłużenie do nieakceptowalne- ło jeszcze dograć dzienniki transakcji. Po wy-
się, podając klauzulę USE TSM: go poziomu, a z drugiej strony podwyższenie konaniu poniższego polecenia baza danych
priorytetu powoduje nieakceptowalne obcią- znajdzie się w stanie ROLL-FORWARD PENDING:
db2 backup db sample use tsm żenie bazy, negatywnie wpływające na czasy
odpowiedzi? W takich przypadkach najlepiej db2inidb sample as mirror
Czytelnikom zainteresowanym dokładniej- wykorzystać technikę rozdzielenia zapisu lu-
szym rozpoznaniem środowiska TSM pole- strzanego (ang. split mirror). W efekcie końcowym stan bazy odpowiada do-
cam publikacje RedBooks: Backing up DB2 Na pracującej bazie danych wstrzymuje się kładnie stanowi, jaki uzyskalibyśmy, odtwarza-
with IBM Tivoli Storage Management (SG24- wszystkie operacje zapisu na dysk, wykonu- jąc bazę z backup-u w tradycyjny sposób, a nie
6247-00 ) oraz SAP Backup using Tivoli Stora- jąc polecenie: poprzez kopiowanie plików z poziomu syste-
ge Manager (SG24-7686-00). mu operacyjnego. Po dograniu logów baza da-
db2 connect to sample nych jest już dostępna dla użytkowników:
Backup bazy 10 TB i większej db2 set write suspend for database
W przypadku bazy danych znacznych roz- db2 rollforward db sample to end of logs
miarów backup online może wykonywać się W tym stanie baza nie wykona żadnych ope- and stop
stosunkowo długo. Backup można przyspie- racji modyfikujących dane na dyskach, więc
szyć, wykorzystując kilka urządzeń, na które można bezpiecznie skopiować pliki bazy bez Muszę jeszcze dodać ważną uwagę, że pod-
ma być składowany (np. kilka urządzeń taśmo- obawy, że ich zawartość zostanie podmie- czas kopiowania plików bazy z archiwum na-
wych bądź kilka dysków) i uruchamiając od- niona w trakcie tej operacji. W stanie WRITE leży pominąć bieżące dzienniki transakcji,
powiednią liczbę równoległych sesji (klauzula SUSPEND baza będzie akceptowała zapytania a w szczególności ostatni bieżący plik, który
PARALLELISM polecenia BACKUP). DB2 dostar- SQL, natomiast wszystkie instrukcje modyfi- był częściowo zapełniony w momencie roz-
cza także narzędzia do kontroli zasobów zuży- kujące dane zostaną wstrzymane („zawisną”). dzielania mirroring-u. Pozwoli to uniknąć sy-
wanych przez backup, więc mamy możliwość Najszybsze skopiowanie plików bazy uzysku- tuacji, w której baza będzie widziała dwa pliki
ograniczania wpływu długo wykonującego się je się poprzez odłączenie zapasowego zesta- o tej samej nazwie, lecz o różnej zawartości (je-
backup-u na bieżące przetwarzanie. Aktualny wu dysków (kopii mirroring-u) i podłączenie den w bieżącej lokalizacji częściowo zapełnio-
stan zaawansowania backup-u można wyświe- ich do dodatkowego komputera – taką moż- ny, a drugi w archiwum zapełniony w całości).
tlić poleceniem LIST UTILITIES SHOW DETAIL. liwość oferują nowoczesne modele macierzy Listę plików do skopiowania w stanie wstrzy-
Przykładowy wynik działania polecenia po- dyskowych, a operacja rozdzielenia zapisu manych zapisów można uzyskać, odwołując się
kazałem na Listingu 10. Warto zwrócić uwa- trwa bardzo krótko (pojedyncze sekundy). do odpowiedniego widoku systemowego:
gę na element określający priorytet backup-u: Po wznowieniu zapisów użytkownicy mo-
wartość „Unthrottled” oznacza, że backup pra- gą dalej pracować na bazie danych: db2 select * from sysibmadm.dbpaths
cuje z pełną mocą. Priorytet backup-u można
ograniczyć poleceniem: db2 set write resume for database Od wersji DB2 9.5 mechanizm macierzo-
wych backup-ów bazy danych został zin-
7% 3% tegrowany z określonymi modelami macie-
rzy, co pozwala na pełną automatyzację te-
14% 44%
go procesu. Czytelników zainteresowanych
tą funkcjonalnością odsyłam do dokumen-
tacji – DB2 Advanced Copy Services (ACS).

Odtworzenie usuniętej tabeli


Na zakończenie artykułu chciałbym jeszcze
omówić metodę odtworzenia tabeli usuniętej in-
strukcją DROP TABLE. DB2 dostarcza specjalny
mechanizm zabezpieczania danych usuniętych
razem z tabelą. Mechanizm ten włącza się (wyłą-
cza) niezależnie dla każdego z obszarów tabel:

32% db2 alter tablespace userspace1 dropped


Awaria sprzętu table recovery on
Błąd człowieka
Błąd oprogramowania Domyślnie, mechanizm ten jest włączony
Wirusy dla każdego z obszarów tabel w bazie. By
Zniszczenia (np. pożar) odtworzyć usuniętą tabelę w pierwszym
kroku należy z pliku historii pobrać iden-
Rysunek 4. Przyczyny utraty danych. Źródło: na podstawie badań Ontrack tyfikator usuniętej tabeli:

68 SDJ Extra 35
Backup od A do Z

db2 list history dropped table all for W ostatnim kroku należy wykonać operację ceniem IMPORT lub LOAD). Definicja usu-
sample ROLLFORWARD z klauzulą RECOVER niętej tabeli jest podawana razem z identy-
DROPPED TABLE, tak jak poniżej: fikatorem usuniętej tabeli w poleceniu list
Identyfikator ma postać history.
0000000000007d2a00020004 i jedno- db2 rollforward database sample to end Przy odzyskiwaniu danych z usuniętych ta-
znacznie określa wersję tabeli w czasie (ta- of logs and complete tablespace bel należy zwrócić szczególną uwagę na da-
bela o tej samej nazwie mogła być wielo- (userspace1) online recover dropped tę usunięcia tabeli. W rzeczywistym syste-
krotnie tworzona i usuwana). table 0000000000007d2a00020004 to mie tabela o tej samej nazwie może być wie-
W następnym kroku należy z backup-u od- c:\temp\exp lokrotnie tworzona i usuwana, więc musimy
tworzyć obszar tabel, w którym znajdowała określić, którą wersję tabeli będziemy chcie-
się usunięta tabela. Najlepiej wykonać odtwa- Wykonanie powyższego polecenia spowodu- li odzyskać. Przy odzyskiwaniu danych tą me-
rzanie w trybie online, by nie ograniczać do- je przywrócenie obszaru tabel i jednoczesny todą DB2 celowo wykonuje zrzut tekstowy
stępności pozostałych obszarów: eksport danych usuniętej tabeli do pliku w zawartości usuniętej tabeli, ponieważ tabela
katalogu c:\temp\exp. Na samym końcu po- o tej samej nazwie mogła być już powtórnie
db2 restore db sample zostaje powtórnie utworzyć tabelę i załado- utworzona. Przytoczona metoda może wy-
tablespace(userspace1) online wać dane z tak wygenerowanego pliku (pole- dawać się mało wygodna, ponieważ wyma-
ga odtworzenia całego obszaru tabel. W ofer-
cie IBM dostępne jest także dodatkowe narzę-
DB2 Recovery Expert dzie DB2 Recovery Expert, które pozwala od-
IBM udostępnia także dodatkowe, odpłatne narzędzie IBM DB2 Recovery Expert, które auto- zyskać usuniętą tabelę kilkoma kliknięciami
matyzuje większość operacji związanych z backup-owaniem i odtwarzaniem bazy danych.
myszki, bez konieczności odtwarzania obsza-
Narzędzie daje także możliwość odtwarzania usuniętych obiektów bez konieczności odtwa-
rzania całego obszaru tabel oraz analizę dziennika transakcji z możliwością wycofania po- ru tabel. Narzędzie to wykorzystuje dodat-
szczególnych zmian na bazie danych. kowe repozytorium, w którym gromadzi in-
formacje o zmianach struktury bazy danych.
Narzędzie pozwala także na analizę dzienni-
Listing 10. Wyświetlenie stanu zaawansowania backup-u ka bazy danych i wygenerowanie instrukcji
SQL anulujących działanie określonej trans-
db2 list utilities show detail akcji. Narzędzie jest szczególnie przydatne
tam, gdzie istnieje potrzeba wykonania ręcz-
ID = 29 nej korekty danych powstałych na skutek błę-
Type = BACKUP du użytkownika.
Database Name = SAMPLE
Partition Number = 0 Podsumowanie
Description = offline db W artykule przedstawiłem szereg technik
Start Time = 2009-06-01 13:28:09.465627 tworzenia kopii bezpieczeństwa oraz odtwa-
State = Executing rzania bazy danych dostępnych w DB2. Do-
Invocation Type = User bór odpowiedniej techniki zależy od okre-
Throttling: ślonych potrzeb związanych z czasem wyko-
Priority = Unthrottled nywania backup-u, czasem odtwarzania, roz-
Progress Monitoring: miaru bazy danych czy dostępnego sprzę-
Estimated Percentage Complete = 32 tu. Jeśli nie będziesz do końca pewien, któ-
Total Work = 75595657 bytes rą z technik zastosować, mogę poradzić: za-
Completed Work = 23972655 bytes stosuj prostszą i łatwiejszą w implementacji.
Start Time = 2009-06-01 13:28:09.465640 Nie sztuką jest zrobić backup, ale wielką sztu-
ką jest przywrócić działającą bazę użytkowni-
kom! Dlatego bardzo ważnym elementem
wdrożenia jest testowanie procedur odtwa-
rzania bazy po awarii. Jeśli już przygotujesz
taką procedurę, poprośmy inną osobę o jej
zastosowanie. Zaangażuj kogoś, kto do końca
nie rozumie mechanizmów funkcjonowania
backup-ów w DB2. Wytwórz presję na takiej
osobie – wszystko po to, by przećwiczyć od-
twarzanie bazy w warunkach zbliżonych do
rzeczywistej awarii.

Artur Wroński
Jest pracownikiem działu oprogramowania IBM
(IBM Software Group) i specjalizuje się w zagad-
nieniach baz danych DB2 oraz Informix.
Rysunek 5. Konfiguracja reguł automatycznego backup-owania bazy Kontakt z autorem: artur.wronski@pl.ibm.com

www.sdjournal.org 69
Administracja

Mechanizm zarządzania
obciążeniem w DB2
Rafał Stryjek, Przemysław Kantyka

Nowoczesne systemy muszą radzić sobie z różnymi typami obciążeń.


Na tej samej bazie danych uruchamiane są aplikacje transakcyjne,
złożone raporty miesięczne, krótkie raporty operacyjne, a także procesy
ładowania danych. Nie wszystkie aplikacje są tak samo ważne, dlaczego
więc baza danych miałaby je traktować w taki sam sposób?

M
enadżer obciążenia DB2 pozwa- tym samym czasie bez konieczności wyko- wanych usług. Najważniejszy, z punktu wi-
la zarządzać priorytetami za- rzystania dedykowanych serwerów dla naj- dzenia biznesowego, jest szybki dostęp do
dań wykonywanych w bazie da- bardziej wymagających zadań. Dzięki temu bazy danych przez aplikacje obsługujące
nych. Daje możliwość wyboru, która z apli- możliwe jest utrzymanie płynności w prze- zapis informacji bilingowych. Dostęp dla
kacji powinna otrzymać więcej zasobów, tak twarzaniu transakcji w operacyjnej części aplikacji obsługujących doładowania kont
by spełnić oczekiwania użytkowników biz- bazy danych przy jednoczesnym wykony- pre-paid może być realizowany z mniej-
nesowych. Czytając ten artykuł, zapoznasz waniu długich i kompleksowych zapytań szym priorytetem. Najmniejszy priorytet
się z możliwościami sterowania obciąże- w części analitycznej (OLAP). Pozwala to będą miały zaś zadania generujące rachun-
niem w DB2. zoptymalizować systemy, w których z róż- ki telefoniczne. Jednocześnie baza danych
Menadżer obciążenia DB2 stanowi boga- nych przyczyn (np. organizacyjnych) źró- musi być dostępna przez cały czas dla re-
ty zestaw narzędzi administracyjnych po- dłem danych dla aplikacji analitycznych plikacji i zadań administracyjnych, takich
zwalających na sterowanie mocą oblicze- jest baza operacyjna bądź gdy wydzielone jak wykonywanie kopii zapasowej, zadania
niową dla poszczególnych aktywności w środowisko hurtowni danych współdzieli konserwacyjne czy optymalizacyjne. Anali-
bazie danych. Dzięki temu ważniejszym, z nią zasoby fizyczne serwera. Tym samym tycy biznesowi mogą również zażądać moż-
z biznesowego punktu widzenia, czyn- rozwiązanie to może być źródłem oszczęd- liwości przygotowania w tle dziennego i ob-
nościom możemy przydzielić większe za- ności – unikamy bowiem zakupu oddziel- szernego raportowania. Istnieje również ry-
soby i wyższy priorytet. Z drugiej strony nego serwera i dodatkowych licencji opro- zyko, iż stworzone przez programistę SQL
mechanizm pozwala na spowolnienie czy gramowania. Co więcej, mechanizm WLM zapytania będą nadmiernie obciążały bazę
wręcz zatrzymanie zbyt obciążających za- wspomaga dyscyplinę w pisaniu zapytań danych, spowalniając w znaczący sposób jej
dań, bądź zawieszenie ich wykonania i od- przez odgórną eliminację zbyt kosztow- działanie.
roczenie w czasie. Pozwala to efektywniej nych konstrukcji SQL bądź ich raportowa- Zadania, za których realizację odpowie-
wykorzystywać maszynę i posiadać więk- nie administratorowi. Wszystko to spra- dzialny jest serwer baz danych, można
szą nad nią kontrolę. Z kolei mechanizm wia, iż poprawne wykorzystanie mechani- mnożyć. W celu zapewnienia ich współ-
zbierania statystyk stanowi cenne źródło zmu gwarantuje wydajniejszą pracę istot- bieżnego i efektywnego wykonywania wraz
informacji o zbyt obciążających fragmen- nych części systemu informatycznego. Dla- z zachowaniem odpowiedniego poziomu
tach systemu. Oparta na nim analiza tren- tego warto dobrze poznać pełnię możliwo- kontroli konieczne jest użycie narzędzi do
dów i najbardziej wymagających aktywno- ści Workload Management. zarządzania obciążeniem (WLM). Dzięki
ści pozwala na określenie sposobu wyko- nim można nadać aplikacjom bilingowym
rzystania zasobów serwera i może przez to Scenariusz użycia wysoki priorytet tak, aby jak najmniej cza-
stanowić system wczesnego ostrzegania (na Wyobraźmy sobie system bazodanowy su oczekiwały na zasoby, a aplikacjom ana-
przykład o możliwości przekroczenia jed- w firmie telekomunikacyjnej. Tego typu lizy danych – niższy. Wraz z upływem cza-
nego z progów). oprogramowanie działa w systemie 24/7, su i szybkim przyrostem danych (kilka GB
Do wersji 9.1 zarządzanie obciążeniem gdzie wiele aktywności musi być wykony- tygodniowo) następuje spowolnienie sys-
DB2 było realizowane poprzez zewnętrz- wanych jednocześnie z zapewnieniem cią- temu bazodanowego, co skutkuje obser-
ne narzędzia, takie jak IBM Query Patrol- głości dostępu i wysokiego poziomu ofero- wowanym przez użytkowników wydłuże-
ler i IBM DB2 Governor. Od wersji DB2
9.5 kompleksowy mechanizm (Workload Listing 1. Aktywacja mechanizmu monitorowania
Management – WLM) został wbudowany w
silnik bazy danych. Mechanizm ten umoż- ALTER SERVICE CLASS SYSDEFAULTSUBCLASS UNDER SYSDEFAULTUSERCLASS COLLECT AGGREGATE
liwia wgląd w działanie systemu bazy da- ACTIVITY DATA BASE;
nych oraz precyzyjną kontrolę nad zasoba- ALTER WORKLOAD SYSDEFAULTUSERWORKLOAD COLLECT ACTIVITY DATA ON COORDINATOR WITH
mi oraz wydajnością. Aktywności bazy da- DETAILS;
nych można podzielić na klasy, zapewniając
obsługę wielu użytkowników i aplikacji w

70 SDJ Extra 35
Mechanizm zarządzania obciążeniem w DB2

Listing 2a. Skrypty symulujące obciążenie bazy danych dla bazy SAMPLE

Plik: work1.db2 create procedure stp4


-- wyłączenie automatycznego zatwierdzania transakcji language sql
update command options using c off; begin
-- podłączenie do bazy danych SAMPLE call stp3;
connect to sample; end;
-- wyświetlenie nazwy bieżącej aplikacji klienckiej create procedure stp5
values(current client_applname); language sql
--Kursory / Operacje odczytu (DML) begin
declare c1 cursor for select * from org; call stp4;
declare c2 cursor for select * from employee; end;
declare c3 cursor for select * from sales; call stp5;
open c1; commit;
open c2; drop procedure stp5;
open c3; drop procedure stp4;
fetch c1; drop procedure stp3;
fetch c2; drop procedure stp2;
fetch c3; commit;
close c1; connect reset;
close c2; terminate;
close c3;
commit; Plik work2.db2
-- Operacje zapisu (DML) -- wyłączenie automatycznego zatwierdzania transakcji
insert into org values (99, 'WLM Team', 831, 'Northern', update command options using c off;
'Canada'); -- podłączenie do bazy danych SAMPLE
insert into sales values(current date, 'GOUNOT', connect to sample;
'Ontario', 999); -- wyświetlenie nazwy bieżącej aplikacji klienckiej
update org set deptnumb = 999 where deptnumb = 99; values(current client_applname);
update sales set sales = 1000 where sales = 999; --Kursory / Operacje odczytu (DML)
delete from org where deptnumb = 999; declare c1 cursor for select * from org;
delete from sales where sales = 1000; declare c2 cursor for select * from employee;
commit; declare c3 cursor for select * from inventory;
-- Zmiany struktur danych (DDL) open c1;
create table tbl1 (col1 int, col2 char(10), col3 int); open c2;
create unique index indx1 on tbl1(col1, col2); open c3;
alter table tbl1 add constraint cons1 check (col1 > 0); fetch c1;
-- Ładowanie danych (LOAD) fetch c2;
load client from data.del of del insert into tbl1; fetch c3;
-- Zmiany struktur danych (DDL) close c1;
drop table tbl1; close c2;
commit; close c3;
-- Zagnieżdżone zapytania commit;
create procedure stp2 -- Operacje zapisu (DML)
language sql insert into org values (99, 'WLM Team', 831, 'Northern',
dynamic result sets 1 'Canada');
begin insert into inventory values('999-999-08', 100, 'Warehouse');
declare callstmt varchar(2000); update org set deptnumb = 999 where deptnumb = 99;
declare callselect_cur cursor with return to caller for update inventory set quantity = 1000 where quantity = 100;
s1; delete from org where deptnumb = 999;
set callstmt = 'select count(c.parm_count) delete from inventory where quantity = 1000;
from sysibm.systables as A, commit;
sysibm.systablespaces as B, -- Zmiany struktur danych (DDL)
sysibm.sysroutines as C'; create table tbl2 (col1 int, col2 char(10), col3 int);
prepare s1 from callstmt; create unique index indx1 on tbl2(col1, col2);
open callselect_cur; alter table tbl2 add constraint cons1 check (col1 > 0);
end; -- Ładowanie danych (LOAD)
create procedure stp3 load client from data.del of del insert into tbl2;
language sql -- Zmiany struktur danych (DDL)
begin drop table tbl2;
call stp2; commit;
end; -- Zagnieżdżone zapytania

www.sdjournal.org 71
Administracja

niem czasu reakcji systemu. Wówczas ad- ce na zbieranie istotnych informacji o sys- SYSTEMDEFAULTUSERCLASS. Poprzez mena-
ministrator powinien dokładnie znać przy- temie. Podczas instalacji serwera baz da- dżer obciążenia (ang. workloads) rozumie-
czyny. nych DB2 tworzone są obiekty umożliwia- my element nadzorujący aktywności, sta-
jące (między innymi) podstawowy moni- nowiący zbiór informacji, który pozwala
Podstawowy toring, tj. domyślny menadżer obciążenia na klasyfikacje działania użytkownika (ze
monitoring systemu dla aktywności użytkowników – SYSTEMD względu na rodzaj połączenia, charakter
Pierwszym poznawanym przez nas ele- EFAULTUSERWORKLOAD, oraz domyślna klasa działań itp.) w ramach bazy danych. Klasy
mentem będą mechanizmy pozwalają- serwisowa dla aktywności użytkowników serwisowe (ang. service classes) są natomiast
definicją sposobu obsługi tych zadań przez
Listing 2b. Skrypty symulujące obciążenie bazy danych dla bazy SAMPLE serwer. Szczegółowe informacje na temat
create procedure stp7 tych elementów zostaną przedstawione w
language sql kolejnych częściach artykułu.
dynamic result sets 1 Na Listingu 1 został przedstawiony pro-
begin ces aktywacji domyślnego monitorowania.
declare callstmt varchar(2000); W tym celu dla menadżera SYSTEMDEFAUL
declare callselect_cur cursor with return to caller for s1; TUSERWORKLOAD należy włączyć kolekcjono-
set callstmt = 'select count(c.parm_count) wanie danych o aktywnościach, a dla kla-
from sysibm.systables as A, sy SYSTEMDEFAULTSUBCLASS kolekcjonowa-
sysibm.systablespaces as B, nie danych zagregowanych na poziomie pod-
sysibm.sysroutines as C'; stawowym (klauzula COLLECT AGGREGATE
prepare s1 from callstmt; ACTIVITY DATA BASE).
open callselect_cur; Celem sprawdzenia poprawności działa-
end; nia mechanizmu monitorowania dokonamy
create procedure stp8 symulacji obciążenia bazy danych poprzez
language sql wykonanie skryptów work1.db2 i work2.db2,
begin przedstawionych na Listingu 2, wykonując
call stp7; polecenia:
end;
create procedure stp9 db2 –tvf work1.db2
language sql db2 –tvf work2.db2
begin
call stp8; Na bazie przeprowadzonych operacji me-
end; chanizm monitorowania generuje statysty-
create procedure stp10 ki i umieszcza je w pamięci. Dostęp do nich
language sql zapewniają funkcje tabelaryczne, które wy-
begin call wołujemy z poziomu zapytań SQL, np.: Li-
stp9; sting 3.
end; Wynik działania przykładowego kodu pre-
call stp10; zentuje Rysunek 1. Wyświetlony rekord za-
commit; wiera informacje o zdarzeniach, które zosta-
drop procedure stp10; ły wykonane w ramach domyślnej klasy ser-
drop procedure stp9; wisowej SYSDEFAULTUSERCLASS w podklasie
drop procedure stp8; SYSDEFAULTSUBCLASS. Kolumna COORD_ACT_
drop procedure stp7; COMPLETED_TOTAL informuje o aktywno-
commit; ściach zakończonych sukcesem, a kolumna
connect reset; COORD_ACT_LIFETIME_AVG przedstawia śred-
terminate; ni czas ich wykonania. Kolumna LAST_RESET
określa natomiast moment ostatniego reseto-
Listing 3. Zapytanie wybierające informacje o statystykach zgromadzonych w pamięci. wania statystyk.

SELECT VARCHAR(SERVICE_SUPERCLASS_NAME, 30) AS SUPERCLASS, Etapy zarządzania obciążeniem


VARCHAR(SERVICE_SUBCLASS_NAME, 30) AS SUBCLASS, Monitorowanie jest jednak tylko jednym z
LAST_RESET, etapów procesu zarządzania obciążeniem.
COORD_ACT_COMPLETED_TOTAL, Pełne wykorzystanie możliwości mechani-
COORD_ACT_LIFETIME_AVG zmu WLM wiąże się z implementacją pozo-
FROM TABLE(SYSPROC.WLM_GET_SERVICE_SUBCLASS_STATS('SYSDEFAULTUSERCLASS', stałych elementów.
'SYSDEFAULTSUBCLASS',-1 )) AS T; Diagram na Rysunku 2 przedstawia eta-
py mechanizmu zarządzania obciążeniem
wraz z kierunkową kolejnością wykonywa-
nych kroków. W przypadku gdy po przejściu

Rysunek 1. Statystyki domyślnego monitora dla podklasy SYSDEFAULTSUBCLASS

72 SDJ Extra 35
Mechanizm zarządzania obciążeniem w DB2

wszystkich kroków baza danych wciąż nie li 1 przedstawione zostały typy aktywności Dodatkowo dla instrukcji typu DML kla-
spełnia celów biznesowych, należy wykonać określone na poziomie menadżera obciąże- sy aktywności wprowadzają możliwość uży-
ponownie kroki od identyfikacji włącznie. nia DB2. cia predykatów (ang. predictive elements) po-
Tabela 1. Typy aktywności bazodanowych
Etap 1. Zdefiniowanie celów
Typ aktywności Opis
biznesowych
Pierwszy etap polega na zdefiniowaniu ce- Read (Czytanie) Zawiera wszystkie zapytania SELECT i Xquery odpowiadające za po-
bieranie danych.
lów biznesowych, które chcemy osiągnąć w
działaniu naszego systemu. Możemy wyróż- Write (Zapisywanie) Obejmuje wszystkie zapytania modyfikujące dane (INSERT, UPDATE,
DELETE, MERGE).
nić cele:
Call (Wywołanie) Wskazuje wszystkie uruchomienia procedur składowanych.
• ilościowe, np. czas odpowiedzi aplikacji DML Zawiera aktywności powstałe przez typy READ i WRITE.
podany w sekundach, wykonanie rapor- DDL Określa instrukcje SQL, które tworzą lub modyfikują obiekty bazy
tów do określonej godziny; danych.
• jakościowe, np. czas odpowiedzi aplika- Load (Wczytywanie) Zawiera aktywności zainicjowane przez narzędzie load.
cji powodujący u użytkowników poczu-
ALL (Wszystkie) Obejmuje wszystkie typy aktywności.
cie komfortowej pracy.

Celami biznesowymi dla firmy telekomuni- Listing 4. Wyświetlenie statystyk dla klas serwisowych
kacyjnej z naszego scenariusza mogą być:
SELECT VARCHAR(SERVICE_SUPERCLASS_NAME, 30) AS SUPERCLASS,
• zagwarantowanie szybkiego dostępu do VARCHAR(SERVICE_SUBCLASS_NAME, 30) AS SUBCLASS,
zapisu informacji bilingowych; COORD_ACT_COMPLETED_TOTAL
• zapewnienie dostępu do doładowań FROM TABLE(WLM_GET_SERVICE_SUBCLASS_STATS('','',-1)) AS T;
kont pre-paid z mniejszym priorytetem;
• ustawienie niższego priorytetu dla czę- SUPERCLASS SUBCLASS COORD_ACT_COMPLETED_TOTAL
ści systemu generującej rachunki telefo- ------------------------------ ------------------------------ --------------------
niczne; ------------
• zdefiniowanie priorytetu dla raporto- SYSDEFAULTSYSTEMCLASS SYSDEFAULTSUBCLASS 0
wania w tle, gwarantującego wysoki po- SYSDEFAULTMAINTENANCECLASS SYSDEFAULTSUBCLASS 0
ziom zasobów dla pozostałych aktywno- SYSDEFAULTUSERCLASS SYSDEFAULTSUBCLASS 75
ści;
• uniemożliwienie wykonywania przez Listing 5. Wyświetlenie statystyk dla menadżerów obciążenia
programistę SQL obciążających zapytań.
SELECT SUBSTR(WORKLOAD_NAME, 1, 22) AS WL_DEF_NAME,
Etap 2. Identyfikacja aktywności WLO_COMPLETED_TOTAL,
Sam proces zarządzania aktywnościami roz- CONCURRENT_WLO_ACT_TOP
poczyna się od ich poprawnego rozpoznania. FROM TABLE(WLM_GET_WORKLOAD_STATS(CAST(NULL AS VARCHAR(128)), -2)) AS WLSTATS;
Identyfikacja aktywności stanowi bowiem
etap, który pozwala serwerowi baz danych na WL_DEF_NAME WLO_COMPLETED_TOTAL CONCURRENT_WLO_ACT_TOP
poprawną klasyfikację procesu oraz zapew- ----------------------------------- ---------------------------- ----------------
nienie właściwego poziomu obsługi zadania. ------
Proces identyfikacji może być przeprowa- SYSDEFAULTUSERWORKLOAD 4 5
dzony za pomocą jednej z metod, np. na pod- SYSDEFAULTADMWORKLOAD 0 0
stawie źródła aktywności. W praktyce każda
z nich odwołuje się do jednego z dwóch ty-
pów obiektów w DB2, tj. menadżerów obcią-
żenia bądź klas aktywności.

Menadżerowie
obciążenia (ang. workloads)
Jest to klasa obiektów, które mogą zostać
użyte do zidentyfikowania nadchodzą-
cych zadań na bazie jego źródła. Ich atry-
buty, takie jak nazwa aplikacji, identy-
fikator użytkownika czy wykorzystywa-
ny obiekt roli, są automatycznie zbiera-
ne podczas zestawienia połączenia z ba-
zą danych.

Klasy aktywności (ang. work classes)


Klasy aktywności stanowią sposób klasyfi-
kacji nadchodzących aktywności w bazie
danych na podstawie ich typów. W Tabe- Rysunek 2. Etapy mechanizmu zarządzania obciążeniem

www.sdjournal.org 73
Administracja

dających szacunkowe informacje o zasobach kie aktywności uruchamiane były w pod- nizmów konserwacji baz danych. W przy-
serwera bazodanowego, które mogą być uży- klasie SYSDEFAULTSUBCLASS domyślnej kla- padku ich aktywności, wartości dla dwóch
te przez uruchamianą aktywność. Do predy- sy serwisowej dla aktywności użytkownika pierwszych rekordów byłyby również nie-
katów należą: SYSDEFAULTUSERCLASS. Sprawdźmy ponow- zerowe.
nie to przyporządkowanie, posługując się W naszej konfiguracji wszystkie aktyw-
• szacunkowy koszt – wyznaczony przez funkcją WLM _ GET _ SERVICE _ SUBCLASS _ ności powinny być również rozpoznawa-
kompilator zapytań SQL koszt wyrażo- STATS. Jednak tym razem w ramach para- ne przez domyślny menadżer obciążenia –
ny w umownych jednostkach timeron; metrów określających nazwę klasy i podkla- SYSDEFAULTUSERWORKLOAD. Celem weryfika-
• szacunkowa liczność – wyznaczona w sy pozostawimy puste ciągi znaków (patrz cji takiego przypisania skorzystamy w zapyta-
procesie kompilacji liczba zwracanych Listing 4). niu SQL z funkcji WLM_GET_WORKLOAD_STATS
rekordów. Otrzymany zbiór wynikowy potwier- (patrz Listing 5).
dza wykonanie naszych zadań w kla- Zgodnie z oczekiwaniami nasze aktyw-
Czas wykorzystać naszą wiedzę w prakty- sie SYSDEFAULTUSERCLASS. Jednak lista ności zostały zidentyfikowane za pomo-
ce. Na początku artykułu aktywowaliśmy klas serwisowych uległa rozszerzeniu o cą domyślnego menadżera. W zbiorze wy-
już podstawowe monitorowanie w oparciu o SYSDEFAULTSYSTEMCLASS oraz SYSDEFAULT nikowym możemy także zobaczyć statysty-
domyślne obiekty mechanizmu zarządzania MAINTENANCECLASS. Są to obiekty zastrze- ki dla menadżera zadań administracyjnych
obciążeniem. Jak wspominaliśmy, wszyst- żone dla zadań systemowych oraz mecha- SYSDEFAULTADMWORKLOAD.
Dokonajmy teraz rozszerzenia możliwości
Listing 6. Statystyki dla utworzonych klas serwisowych oraz menadżerów obciążenia naszego mechanizmu zarządzania aktywno-
ściami bazy danych. W tym celu definiujemy
SUPERCLASS SUBCLASS COORDACTCOMP dwie nowe klasy serwisowe o nazwach odpo-
------------------------------ ------------------------- -------------------- wiadającym naszym skryptom symulującym
SYSDEFAULTSYSTEMCLASS SYSDEFAULTSUBCLASS 0 obciążenie:
SYSDEFAULTMAINTENANCECLASS SYSDEFAULTSUBCLASS 12
SYSDEFAULTUSERCLASS SYSDEFAULTSUBCLASS 1 CREATE SERVICE CLASS work1_sc;
work1_sc SYSDEFAULTSUBCLASS 37 CREATE SERVICE CLASS work2_sc;
work2_sc SYSDEFAULTSUBCLASS 37
Następnie definiujemy menadżerów obcią-
WL_DEF_NAME WLO_COMPLETED_TOTAL CONCURRENT_WLO_ACT_TOP żenia dla każdego z zadań dokonujących
--------------------------------- ----------------------------- ------------------ mapowania na odpowiednie klasy serwi-
---------------- sowe. W tym celu wykorzystamy specjalną
work1_wl 1 5 zmienną rejestrową CLP, dzięki której na-
work2_wl 1 5 zwa aplikacji jest utożsamiana z wywoły-
SYSDEFAULTUSERWORKLOAD 1 0 wanym w oknie poleceń skryptem. Dodat-
SYSDEFAULTADMWORKLOAD 0 0 kowo celem zebrania dodatkowych danych
w definicji menadżerów obciążenia użyje-
Listing 7. Wyświetlanie dodatkowych informacji o aktywnościach my klauzuli COLLECT ACTIVITY DATA WITH
DETAILS:
SELECT SUBSTR(WORKLOADNAME, 1, 20) AS WL_DEF_NAME,
SUBSTR(APPL_NAME, 1, 20) AS APPL_NAME, CREATE WORKLOAD work1_wl CURRENT CLIENT_
SUBSTR(ACTIVITY_TYPE, 1, 10) AS ACT_TYPE APPLNAME ('CLP
FROM SYSIBM.SYSWORKLOADS, ACTIVITY_DB2ACTIVITIES work1.db2') SERVICE
WHERE WORKLOADID = WORKLOAD_ID; CLASS work1_sc
POSITION AT 1
WL_DEF_NAME APPL_NAME ACT_TYPE COLLECT ACTIVITY
------------------------- ------------- ---------- DATA WITH DETAILS;
... ... ... CREATE WORKLOAD work2_wl CURRENT CLIENT_
SYSDEFAULTUSERWORKLO db2bp OTHER APPLNAME ('CLP
SYSDEFAULTUSERWORKLO db2bp OTHER work2.db2') SERVICE
work1_wl db2bp READ_DML CLASS work2_sc
work1_wl db2bp READ_DML POSITION AT 2
work1_wl db2bp READ_DML COLLECT ACTIVITY
work1_wl db2bp READ_DML DATA WITH DETAILS;
work1_wl db2bp WRITE_DML
work1_wl db2bp WRITE_DML Ostatnim krokiem jest definicja monitorów
work1_wl db2bp WRITE_DML zdarzeń dla aktywności i statystyk oraz ich
work1_wl db2bp WRITE_DML aktywacja poleceniami:
work1_wl db2bp WRITE_DML
work1_wl db2bp WRITE_DML CREATE EVENT MONITOR DB2ACTIVITIES FOR
work1_wl db2bp DDL ACTIVITIES WRITE TO
work1_wl db2bp DDL TABLE;
... ... ... CREATE EVENT MONITOR DB2STATISTICS FOR
STATISTICS WRITE TO
TABLE;

74 SDJ Extra 35
Mechanizm zarządzania obciążeniem w DB2

SET EVENT MONITOR DB2ACTIVITIES STATE 1; • klasa systemu operacyjnego – umożli- systemowych o rodzinę systemów Li-
SET EVENT MONITOR DB2STATISTICS STATE 1; wia zarządzanie zasobami poprzez po- nux.
wiązanie klasy serwisowej DB2 z kla- • priorytet obsługi puli buforów (ang. buf-
Nasze obiekty są już gotowe. Aby je prze- są systemu operacyjnego posiadającego fer pool priority) – określa poziom wyko-
testować, resetujemy statystyki menadże- własny mechanizm zarządzania obcią- rzystania stron puli buforów przez ak-
ra połączeń, wywołując procedurę WLM _ żeniem. Dla wersji DB2 9.5 obsługiwa- tywności danej klasy serwisowej. Me-
COLLECT _ STATS: nym systemem operacyjnym jest IBM chanizm ten został wprowadzony w
AIX. Wersja 9.7 rozszerza obsługę klas wersji DB2 9.7.
CALL SYSPROC.WLM_COLLECT_STATS(); Tabela 2. Typy progów uruchomieniowych
Typ progu Opis
i uruchamiając ponownie nasze skrypty:
ACTIVITYTOTALTIME Określa czas, jaki aktywność potrzebuje na ukończenie swojego
(całkowity czas aktywności) działania (czas uruchomienia i czas oczekiwania w kolejce).
db2 –tvf work1.db2
db2 –tvf work2.db2
Wykorzystywany do detekcji zbyt długo trwających aktywności.
CPUTIME Definiuje maksymalny czas aktywności procesora dla danej ak-
Wykorzystując zapytania SQL z Listingu 4 (czas procesora) tywności.
i Listingu 5, wyświetlamy odświeżone sta-
tystyki. Rezultatem ich wykonania powin- Parametr ten został wprowadzony w wersji DB2 9.7. Pozwala na
ny być następujące zbiory rekordów (patrz detekcje aktywności, które w znaczącym stopniu obciążają CPU.
Listing 6). ESTIMATEDSQLCOST Kontroluje aktywności odczytu i modyfikacji danych (DML – RE-
Wykonanie naszych skryptów zosta- (szacunkowy koszt zapy- AD i WRITE) o wysokim koszcie działania na podstawie informacji
ło zatem zidentyfikowane przez menadże- tania) dostarczanych przez optymalizator DB2.
rów work1_wl i work2_wl oraz przekazane
Pozwala na wprowadzenie proaktywnego działania dla aktyw-
do odpowiadających im klas work1_sc oraz
ności ze zbyt kosztownym planem zapytań.
work2_sc.
SQLROWRETURNED Definiuje maksymalną liczbę zwracanych wierszy dla zapytania
Pozostaje jeszcze wyświetlić dodatkowe
(liczba zwróconych wierszy) SQL.
operacje zbierane przez menadżera obciąże-
nia oraz monitory zdarzeń. Skonstruujemy Wykorzystywany w celu uniknięcia nadmiernego obciążania ser-
w tym celu zapytanie SQL, które pokaże nam wera bazy danych zbyt dużą liczbą zwracanych wierszy.
aktywności, wskazując ich typ (klasę aktyw- SQLROWREAD Określa maksymalną liczbę rekordów, które mogą być odczytane
ności) oraz aplikację inicjalizującą oraz utoż- (liczba przeczytanych wier- przez zapytanie SQL.
samiony z nimi menadżer obciążenia (patrz szy)
Listing 7). Parametr wprowadzony w wersji DB2 9.7. Pozwala na detekcje
aktywności, które przetwarzają duże ilości rekordów.
Etap 3. Zarządzanie SQLTEMPSPACE Kontroluje wielkość zajmowaną przez obiekty tymczasowe.
Kolejnym i jednym z najważniejszych etapów (przestrzeń zajmowana
przez tabele tymczasowe) Wykorzystywany do wykrywania aktywności wykorzystujących
jest aktywne zarządzanie rozpoznanymi ak-
zbyt duże tabele tymczasowe.
tywnościami. Możliwe jest kontrolowanie
ich pracy i przydzielanie określonych prio-
rytetów w zależności od aktualnych potrzeb Listing 8. Skrypt symulujący obciążenie testujący mechanizm progów uruchomieniowych
biznesowych. W praktyce etap opiera się o de-
finicję hierarchii klas aktywności (super klas Plik: progi.db2
i podklas), progów uruchomieniowych oraz
zestawów aktywności. SELECT * FROM DEPARTMENT;
-- Dla poniższego zapytania nastąpi naruszenie progu "tr_sqlrows"
Super klasy i podklasy SELECT * FROM SALES;
W opisie poprzedniego etapu poznaliśmy po- -- Dla poniższego zapytania nastąpi naruszenie progu "tr_estcost"
jęcie klas serwisowych. Stanowią one środo- SELECT COUNT(*) FROM SYSCAT.TABLES, SYSCAT.TABLES, SYSCAT.TABLES;
wisko uruchomieniowe, w których możemy
zdefiniować zakres dostępnych zasobów dla Listing 9. Utworzenie dwóch progów uruchomieniowych
danej aktywności, takich jak:
CREATE THRESHOLD tr_estcost
• priorytet agenta (ang. agent priority) – FOR SERVICE CLASS threctrl_sc1 ACTIVITIES
określa poziom wykorzystania proceso- ENFORCEMENT DATABASE
ra przez agenta uruchomionych wątków WHEN ESTIMATEDSQLCOST > 30
w ramach danej klasy serwisowej. Prio- STOP EXECUTION;
rytet ten zostaje przełożony do systemu CREATE THRESHOLD tr_sqlrows
operacyjnego jako wartość relatywna do FOR SERVICE CLASS threctrl_sc1 ACTIVITIES
poziomu określonego dla innych wąt- ENFORCEMENT DATABASE
ków i procesów bazy danych. WHEN SQLROWSRETURNED > 30
• priorytet pobierania z wyprzedzeniem COLLECT ACTIVITY DATA WITH DETAILS AND VALUES
(ang. prefetch priority) – odpowiada za STOP EXECUTION;
właściwe kolejkowanie żądań typu pre-
fetch.

www.sdjournal.org 75
Administracja

Aby zmienić wyżej wymienione priorytety tywność do super klasy (domyślnej podklasy) • zatrzymanie wykonania (ang. stop execu-
dla aktywności uruchamianych w danej kla- bądź podklasy zdefiniowanej przez nas. tion) – aktywność zostaje zatrzymana w
sie serwisowej, przypisując im tym samym chwili przekroczenia zadanego progu, a
określone zasoby bazy danych, należy posłu- Progi (ang. thresholds) do aplikacji inicjalizującej zostaje prze-
żyć się zapytaniem ALTER SERVICE CLASS, np.: W ramach środowiska możliwe jest również kazany wyjątek.
zdefiniowanie progów uruchomieniowych. • kontynuowanie wykonania (ang. conti-
ALTER SERVICE CLASS klasa_sewisowa AGENT Pozwalają one na zdefiniowanie reakcji ser- nue execution) – po przekroczeniu pro-
PRIORITY -10 wera baz danych, gdy aktywność przekroczy gu aktywność nie zostaje zatrzymana.
PREFETCH PRIORITY – zdefiniowaną przez próg – wartość granicz- Mechanizm obciążenia zapisuje jedy-
MEDIUM ; ną. Progi te mogą być definiowane przez użyt- nie informacje o tym zdarzeniu na po-
kownika zarówno w celu kompleksowego za- trzeby późniejszej analizy przez admi-
W ramach mechanizmu zarządzania obcią- rządzania systemem, jak i wyłapywania ak- nistratora.
żeniem DB2 administrator może zdefinio- tywności nadmiernie wykorzystujących za- • przeniesienie aktywności do innej klasy
wać dwa typy klas serwisowych: super kla- soby. Tabela 2 przedstawia zdefiniowane w serwisowej (ang. remap activity) – aktyw-
sy i podklasy. Super klasa stanowi najwyż- DB2 typy progów uruchomieniowych. ność zostaje przeniesiona do innej klasy
szy poziom przyporządkowania aktywności, Po przekroczeniu wartości granicznej dla serwisowej, dla której został zdefiniowa-
natomiast podklasy są właściwymi środowi- zdefiniowanego progu uruchomieniowego ny inny poziom dostępnych zasobów i
skami wykonawczymi dla aktywności. Z te- mechanizm zarządzania obciążeniem podej- progi uruchomieniowe. Mechanizm ten
go powodu dla każdej utworzonej super kla- muje działanie określone przez użytkownika. został dodany w wersji DB2 9.7, umoż-
sy automatycznie tworzona jest domyślna W wersji DB2 9.7 umożliwia 4 typy reakcji: liwiając automatyczne przenoszenie za-
podklasa. Możliwe jest utworzenie dodatko- dań między klasami.
wych podklas serwisowych celem bardziej • zebranie danych (ang. collect data) – infor-
szczegółowego oddzielenia aktywności bądź macje na temat aktywności zostaną zebra- Aby sprawdzić mechanizm w praktyce,
zasobów. Jednakże niemożliwe jest tworze- ne w chwili przekroczenia wartości gra- zdefiniujemy nową klasę aktywności i me-
nie zagnieżdżonych struktur podklas – mo- nicznej progu. Samo zdarzenie jest zapisy- nadżer obciążenia dla skryptu progi.db2
gą one być jedynie elementem super klasy. wane domyślnie przez dedykowany moni- (patrz Listing 8):
Po nadejściu do bazy danych żądania od tor zdarzeń (threshold violations event mo-
użytkownika serwer identyfikuje je przez wła- nitor). Ten typ reakcji może stanowić uzu- CREATE SERVICE CLASS threctrl_sc1 ENABLE;
ściwy menadżer obciążenia. Ten przypisuje ak- pełnienie dla typów omówionych poniżej. CREATE WORKLOAD threctrl_wl1
CURRENT CLIENT_APPLNAME('CLP
Listing 10. Komunikaty o przekroczeniu progów progi.db2')
SERVICE CLASS threctrl_sc1;
… … … …
03/31/2006 LEE Manitoba 3 Następnie definiujemy dwa progi urucho-
03/31/2006 GOUNOT Ontario-South 2 mieniowe: tr _ estcost i tr _ sqlrows
SQL4712N The threshold "TR_SQLROWS" has been exceeded. Reason code = "8". (patrz Listing 9).
SQLSTATE=5U026 Zadaniem pierwszego będzie zatrzymanie
każdej aktywności, której szacowany koszt
SELECT COUNT(*) FROM SYSCAT.TABLES, SYSCAT.TABLES, SYSCAT.TABLES przekroczy wartość 30. W przypadku dru-
SQL4712N The threshold "TR_ESTCOST" has been exceeded. Reason code = "7". giego mechanizm zarządzania obciążeniem
SQLSTATE=5U026 po zwróceniu przez bazę danych 30 wierszy
zatrzyma aktywność, jednocześnie zbierając
Listing 11. Klasyfikacja zapytań z wykorzystaniem szacowanego kosztu w celu zmiany dokładne statystyki. Test uruchamiamy po-
priorytetów obsługi
przez wywołanie skryptu poleceniem:
CREATE SERVICE CLASS olap_sc UNDER work1_sc AGENT PRIORITY 0 DISABLE;
db2 –tvf progi.db2
CREATE SERVICE CLASS oltp_sc UNDER work1_sc AGENT PRIORITY -6 DISABLE;
Wynik jego działania został przedstawiony
CREATE WORK CLASS SET oltp_olap_wcs( w Listingu 10.
WORK CLASS read_olap_wc WORK TYPE READ FOR TIMERONCOST FROM 10000.0 POSITION Należy podkreślić, iż istnieje klasa aktyw-
AT 1, ności, dla której progi uruchomieniowe nie
WORK CLASS all_oltp_wc WORK TYPE ALL POSITION AT 2 będą nigdy sprawdzane. Klasa ta jest związa-
); na z aktywnościami, które zostały zidentyfi-
CREATE WORK ACTION SET olap_oltp_mapping_wa FOR SERVICE CLASS work1_sc USING WORK kowane przez wspomnianego na łamach te-
CLASS SET oltp_olap_wcs ( go artykułu menadżera dla zadań administra-
WORK ACTION oltp_ma ON WORK CLASS all_oltp_wc MAP ACTIVITY TO oltp_sc, cyjnych (SYSDEFAULTADMWORKLOAD). W takim
WORK ACTION "olap_ma" ON WORK CLASS read_olap_wc MAP ACTIVITY TO olap_sc ) wypadku serwer danych zakłada, iż realizacja
DISABLE; takiego zadania wynika ze świadomej decyzji
administratora.
ALTER SERVICE CLASS olap_sc UNDER work1_sc ENABLE;
ALTER SERVICE CLASS oltp_sc UNDER work1_sc ENABLE; Zestaw aktywności
ALTER WORK ACTION SET olap_oltp_mapping_wa ENABLE; (ang. work action set)
Ostatnią klasą obiektów dla etapu zarządzania
są zestawy aktywności. Pozwalają one na agre-

76 SDJ Extra 35
gowanie aktywności, które są identyfikowane • monitor aktywności (ang. activity
przez jeden lub więcej typów (patrz: Klasy ak- event monitor) – zbiera informacje o
tywności). Zbiory takie mogą zostać zdefinio- indywidualnych aktywnościach po-
wane na poziomie bazy danych, a także przy- grupowanych ze względu na obiek-
pisane w ramach klas serwisowych. ty mechanizmu WLM.
Podejście takie pozwala na przypisanie ak- • monitor dla przekroczonych wartości
tywnościom listy zadań, które będą wywoły- granicznych progów (ang. threshold
wane w zależności od – określonych w ich de- violations event monitor) – zbierają-
finicji – klas aktywności i zakresu wykorzy- cy informacje o aktywnościach prze-
stywanych zasobów. W szczególności do za- kraczających zadany próg.
dań tych należy mapowanie danej aktywno- • monitor statystyk (ang. statistic event mo-
ści do podklasy serwisowej. Dzięki temu mo- nitor) – zbiera dane w postaci zagre-
żemy wyróżnić na przykład operację odczytu, gowanej, np. histogramy dla czasów
którego koszt przekroczy 10 000 jednostek ti- trwania i uruchomienia aktywności.
meron (patrz Listing 11).
Przykład taki może być odzwierciedlo- Oba typy monitorowania zostały przez nas
ny przez kosztowne zapytania analityczne wykorzystane podczas omawiania kolejnych
(OLAP) uruchamiane w tle z mniejszym etapów zarządzania obciążeniem.
priorytetem.
Podsumowanie
Etap 4. Monitorowanie Ideą artykułu było zapoznanie czytelnika z
Monitorowanie pozwala na weryfikację pro- podstawami mechanizmu WLM służące-
cesu pod kątem założonych celów bizneso- go do zarządzania obciążeniem celem lep-
wych oraz umożliwia analizę trendów ak- szego wykorzystania zasobów i tym samym
tywności w systemie. Jak zostało to określo- usprawnienia pracy systemu. Pokazano moż-
ne na początku artykułu, monitorowanie sta- liwości w zakresie najważniejszych etapów
nowi zazwyczaj pierwszy krok pracy z me- powiązanych z utrzymywaniem obciążenia,
chanizmem WLM ze względu na koniecz- tj. monitorowania, zarządzania, definicji
ność zdiagnozowania systemu. oraz identyfikacji aktywności. Serwer danych
Posługując się dostępnymi w DB2 funkcja- DB2 dostarcza tu wachlarz możliwości, któ-
mi tabelarycznymi, użytkownik uzyskuje do- re zostały zobrazowane za pomocą skryptów
stęp w czasie rzeczywistym do danych opera- odzwierciedlających rzeczywiste wykorzysta-
cyjnych, takich jak lista klas serwisowych, za- nie. Wykorzystanie zdobytej wiedzy pozwoli
wierająca informacje o liczbie uruchomio- lepiej i wydajniej zarządzać systemami klasy
nych w nich aktywności i średnim czasie wy- enterprise, w których wymagania jakościowe
konania (patrz Rysunek 1). Wiedza ta może są niezwykle istotne. Warto jeszcze raz pod-
zostać rozszerzona, przy wykorzystaniu mo- kreślić, iż wykorzystanie mechanizmu WLM
nitorów zdarzeń (ang. event monitors), o szcze- może wiązać się z uzyskaniem finansowych
gółowe informacje oraz statystyki dla zagrego- oszczędności. Jednak należy uważać, by nie
wanych wartości. Na zbieranie i analizę tych potraktować go jako panaceum na wszystkie
ostatnich warto zwrócić uwagę, planując stra- problemy bazodanowe, w szczególności nie-
tegię monitorowania bazy danych. Proces ta- optymalnie napisane zapytania SQL.
ki jest bowiem mniej obciążający dla serwera
niż zbieranie informacji o pojedynczym zda-
rzeniu, a uzyskiwane wyniki dają dobry, ogól- Rafał Stryjek
ny obraz wszystkich aktywności. Rafał Stryjek - doktorant Politechniki Łódzkiej.
W ramach etapu monitorowania możemy Certyfikowany Trener i Konsultant baz danych
wyróżnić dwa typy: Oracle wspierający pracowników największych
firm i instytucji w kraju. Prowadzi zaawansowane
• monitorowanie w czasie rzeczywistym – szkolenia w firmie Altkom Akademia S.A. Wcze-
oparte o statystyki reprezentujące ak- śniej współpracował z firmą IBM Polska z wyko-
tualne aktywności w bazie danych. Ich rzystaniem baz danych DB2 oraz Oracle.
analiza przeprowadzana jest z wykorzy- e-mail: rafal@stryjek.com
staniem jednej z pięciu funkcji tabela-
rycznych zwracających dane dla pozio- Przemysław Kantyka
mu: super klas, podklas, menadżerów Przemysław Kantyka - certyfikowany specja-
obciążenia, zestawu aktywności bądź lista bazodanowy z wieloletnim doświadcze-
progów uruchomieniowych. niem w pracy z bazami danych (głównie Orac-
• monitorowanie w oparciu o dane historycz- le) na potrzeby sektora finansowego. Jako Kon-
ne – mechanizm WLM pozwala również sultant i Trener wyszkolił dziesiątki osób z zakre-
na zbieranie informacji, które mogą być su zaawansowanych technologii bazodanowych.
użyte w przyszłości w celu analiz histo- Współpracował między innymi z firmami takimi
rycznych. Dla tworzenia tego typu infor- jak Comarch i Altkom Akademia S.A.
macji wyróżniamy 3 typy monitorów: e-mail: przemyslaw@kantyka.com

www.sdjournal.org
Administracja

Kompresja w DB2
Optymalizacja systemu dyskowego

W ostatnich latach rynek oprogramowania do zarządzania bazami danych


zupełnie zmienił swoje oblicze. Jeszcze kilka, kilkanaście lat temu bazy
danych należały do elitarnego oprogramowania i projektanci systemów
informatycznych byli wręcz skazani na korzystanie z komercyjnych
rozwiązań.

D
zisiaj o bazach danych Open Sour- sce na dyskach czy środki finansowe, któ- bazę danych, bardzo kusi skorzystanie z jak
ce można powiedzieć, że osiągnę- re mogę przeznaczyć na zakup i utrzyma- największych dysków, ponieważ większe
ły już odpowiedni poziom dojrza- nie systemów dyskowych. dyski przekładają się na mniejszą cenę sys-
łości, by stosować je w komercyjnych syste- Dla przeciętnego użytkownika kompu- temu dyskowego, jednak wybór większych
mach. Bazy danych stały się po prostu po- tera osobistego kompresja nie zawsze ko- dysków oznacza mniejszą wydajność. Bazy
wszechnym produktem, takim jak telewi- jarzy się z czymś pozytywnym, najczę- danych czytają małymi blokami, a wydaj-
zor czy samochód. W języku angielskim naj- ściej z oczekiwaniem na rozpakowanie ność każdego z dysków określona jest przez
łatwiej określić je jednym słowem – commo- plików. W wielu dziedzinach to właśnie liczbę operacji losowego odczytu/zapisu na
dity. Czy oznacza to, że dostępne na rynku inteligentne algorytmy kompresji wyzna- sekundę. Zrównoważona wydajność opera-
bazy danych nie różnią się od siebie i oferu- czają kierunki rozwoju. Przykładem mo- cji I/O bezpośrednio zależy od liczby dys-
ją podobne możliwości? Takie samo pytanie gą być choćby algorytmy kompresji wy- ków, a nie przestrzeni dyskowej! Tak jak po-
można postawić w stosunku do innych pro- korzystane do strumieniowego przeka- kazałem na Rysunku 1, by zapewnić 600
duktów commodity. Czy dziś ma znaczenie, zu obrazu wideo wysokiej rozdzielczości GB przestrzeni dyskowej, możemy skorzy-
jaki kupujemy samochód? Oczywiście, że (H.264/AVC), stosowane przez wiele cy- stać z czterech dysków po 150 GB bądź
ma! Wszystko jednak zależy od wymagań, frowych platform satelitarnych. Nawet z dwóch po 300 GB. Zastosowanie więk-
jakie stawiamy. Jeśli ktoś potrzebuje samo- poza informatyką można podać przykła- szych dysków zapewne będzie tańszym roz-
chodu, by raz w tygodniu odwiedzić rodzi- dy wykorzystania kompresji, przynoszą- wiązaniem, jednak pociągnie za sobą dwa
nę, która mieszka kilka kilometrów od na- ce odpowiednie korzyści. Producentom razy mniejszą wydajność mierzoną w licz-
szego domu, wtedy naprawdę nie ma zna- soków (np. pomarańczowych) opłaca się bie operacji I/O na sekundę.
czenia, czym będziemy się przemieszczać. zagęścić sok w miejscu, w którym jest on Specjaliści przygotowujący sprzęt pod testy
Jeśli jednak zaczniemy intensywnie używać produkowany, przetransportować zagęsz- wydajnościowe przetwarzania analitycznego
samochodu, wtedy nie bez znaczenia będzie czony sok do docelowego kraju, a następ- TPC-H (www.tpc.org) doskonale rozumieją
dla nas zużycie paliwa, bezpieczeństwo, nie- nie uzupełnić sok wodą w odpowiednich konieczność użycia bardzo dużej liczby dys-
zawodność czy komfort. Jeśli samochód sta- proporcjach. Taka operacja wymaga do- ków. Najlepszy wynik testu TPC-H dla bazy
nie się dla nas miejscem pracy – wtedy już datkowej pracy, jednak w ogólnym bilan- danych o rozmiarze 10 TB, zrealizowany na
na pewno zaczniemy wymagać więcej. Po- sie obniża koszty i przyspiesza proces wy- DB2 9.5 został osiągnięty przy wykorzysta-
dobnie jest i z bazami danych. Jeśli naszym tworzenia soku. niu macierzy dyskowej, której powierzchnia
jedynym wymaganiem będzie przechowa- Zanim omówię zasady działania kom- dyskowa była 11 razy większa niż rozmiar
nie kilku GB danych, wtedy wszystkie bazy presji w DB2 chciałbym zwrócić uwagę bazy danych! 110 TB to dużo? Drugi w ko-
będą tak samo dobre. Różnicę będzie moż- na trendy rozwoju sprzętu komputero- lejności wynik zrealizowany na bazie Oracle
na zauważyć przy bazie, która np. zarządza wego w ostatnich latach. Prędkość pro- 11g wykorzystywał macierz dyskową 44 razy
kilkoma terabajtami danych. cesorów z roku na rok systematycznie większą niż rozmiar bazy danych (440 TB)!
W tym artykule opiszę mechanizmy się zwiększa. Pojemność dysków także się Testy wydajnościowe TPC-H rządzą się swo-
kompresji danych dostępne w DB2, któ- zwiększa. Dziś dostępne są już dyski 600 imi prawami, które wszystko podporządko-
re stosowane są dla dużych baz danych. GB stosowane w macierzach z interfej- wują osiągnięciu najlepszego wyniku, i czasa-
Oczywiście duża baza jest bardzo subiek- sem Fiber Channel (dyski SATA II oferu- mi trudno je bezpośrednio odnieść do rzeczy-
tywnym określeniem. Dla mnie duża ba- ją jeszcze większe pojemności, jednak nie wistych rozwiązań. Podobnie jak nikogo nie
za to taka, która wymaga podjęcia specjal- zawsze nadają się do rozwiązań pod bazy dziwi fakt, że wykonanie kierownicy samo-
nych akcji, pozwalających na przełama- danych). Natomiast prędkość dysków po- chodu Formuły 1 kosztuje tyle samo co wy-
nie pewnych ograniczeń będących natu- zostaje bez zmian – wynika to z fizycz- produkowanie nowego, popularnego samo-
ralną konsekwencją rozmiaru bazy. Do ta- nych ograniczeń prędkości obrotowej ta- chodu osobowego. Przytoczyłem powyższe
kich ograniczeń mogę zaliczyć maksymal- lerza dyskowego, wynoszącego maksy- porównania, by zasygnalizować konieczność
ny czas, który mogę poświęcić na wykona- malnie 15 tysięcy obrotów na minutę. optymalizacji systemu dyskowego, np. przy
nie backup-u bazy danych, dostępne miej- Przygotowując architekturę sprzętu pod wykorzystaniu kompresji.

78 SDJ Extra 35
Kompresja w DB2

Jak działa kompresja w DB2? dużym nakładem pracy. Narzut związany z tzn. tabela o rozmiarze 100 GB po kompresji
DB2 implementuje kilka różnych algoryt- obsługą skompresowanej tabeli jest stosun- powinna zajmować 30-40 GB. Zmniejszenie
mów zależnie od tego, czy kompresowa- kowo niewielki. Wykorzystujemy dodatko- rozmiaru tabeli nie jest jedyną korzyścią wy-
ne są rekordy, indeksy czy np. backup bazy we cykle procesora głównie przy modyfika- nikającą z kompresji. Ponieważ format stron
danych. Dla kompresji tabel istotą jest zu- cji danych, by odszukać w słowniku wzorce. przechowywanych w pulach buforów jest ta-
pełnie inny format zapisu rekordu na stro- Odczyty danych praktycznie nie pociągają ki sam jak na dyskach, w tej samej ilości pa-
nie. By zrozumieć, jak działa kompresja, za sobą dodatkowego narzutu. W momencie mięci RAM serwera bazy danych znajdować
przypomnę podstawy organizacji danych w ewaluacji wartości rekordu bądź wysyłania się będzie więcej rekordów. Dzięki kompre-
DB2. Na dyskach dane zorganizowane są w strumienia danych do aplikacji, DB2 dyna- sji wirtualnie zwiększamy dostępną dla bazy
strony, które stanowią podstawową jednost- micznie podmienia zawartość znaczników. pamięć RAM. Kolejną korzyścią jest zwięk-
kę operacji wejścia/wyjścia. Jeśli chcemy za- Algorytmy są tak dopracowane, że rozmiar szenie przepustowości operacji I/O. Jak już
pytaniem SQL odczytać pojedynczy rekord, słownika wzorców praktycznie nie przekra- wspomniałem, baza danych czyta blokami
wtedy minimalną porcją danych, jaka zosta- cza 150 KB, niezależnie od rozmiaru tabe- (stronami). Z jednym odczytem, proporcjo-
nie odczytana z dysku, jest strona. Strona li. Słownik przechowywany jest zawsze w nalnie do współczynnika kompresji, czytamy
zostanie umieszczona w puli buforów (ca- pamięci podręcznej bazy danych, dlatego też większą liczbę rekordów – wirtualnie wzra-
che), która jest współdzielonym obszarem dostęp do niego jest bardzo szybki. sta przepustowość systemu dyskowego (patrz
pamięci RAM wykorzystywanym do obsłu- Główną korzyścią ze stosowania kompre- Rysunek 2). Kompresja pociąga za sobą nie-
gi wszystkich aplikacji. Jeśli inny użytkow- sji jest zmniejszenie szerokości rekordów. znaczny wzrost utylizacji procesora – takie
nik (bądź ten sam) będzie chciał odczytać Na tej samej stronie zostanie zapisanych du- zachowanie wpisuje się w omówiony wcze-
rekord ze strony, która znajduje się już w żo więcej rekordów. Współczynniki kompre- śniej trend wzrostu mocy procesorów.
puli buforów, wtedy odczyt będzie zrealizo- sji silnie zależą od samych danych. Na podsta-
wany bezpośrednio z pamięci bez koniecz- wie obserwacji rzeczywistych systemów (np. Włączenie kompresji
ności fizycznego odwoływania się do dys- SAP ERP) można powiedzieć, że przeciętny Do zademonstrowania poszczególnych kro-
ku. Rozmiar strony w DB2 jest definiowal- współczynnik kompresji wynosi ok. 60-70%, ków związanych z włączeniem kompresji wy-
ny (4 KB, 8 KB, 16 KB lub 32 KB), a na jed-
nej stronie zwykle mieści się typowo od kil- Listing 1. Sprawdzenie miejsca zajmowanego przez tabele bazy danych
ku do kilkuset rekordów (zależnie od szero-
kości rekordu). select char(tabname, 10) as table, data_object_l_size as "DATA SIZE [KB]",
Działanie kompresji polega na zreduko- index_object_l_size as "INDEX SIZE [KB]" from
waniu szerokości rekordu, tak by na stro- sysibmadm.admintabinfo where tabschema = 'TPCH' order by
nie można było upakować większą liczbę re- data_object_l_size desc;
kordów. Jeśli często powtarzający się w ta-
beli wzorzec występuje w rekordzie, wtedy TABLE DATA SIZE [KB] INDEX SIZE [KB]
podmieniany jest na odpowiedni 12-bitowy ---------- -------------------- --------------------
znacznik, którego definicja przechowywana LINEITEM 833024 144384
jest w specjalnym słowniku systemowym. ORDERS 183808 43264
Istotą algorytmu kompresji DB2 jest przygo- PARTSUPP 127872 45568
towanie odpowiedniego słownika wzorców. PART 30720 3456
W DB2 słownik wzorców budowany jest na CUSTOMER 27904 3968
podstawie zawartości całej tabeli (bądź wy- SUPPLIER 1792 512
różnionego fragmentu tabeli). Operacja ta- NATION 256 256
ka jest stosunkowo czasochłonna (wyma- REGION 256 256
ga przeskanowania dużej liczby rekordów)
i może znacznie obciążyć system, dlatego
też decyzja o zbudowaniu słownika najczę-
ściej podejmowana jest świadomie przez ad-
ministratora bazy danych. W momencie bu-
dowania słownika, DB2 ocenia całe wiersze,
szukając podobnych fragmentów lub powtó-
rzonych wpisów danych i to nie tylko dla
wybranych pól czy części pól, ale całych cią-
gów, rozciągających poprzez wiele kolumn
w wierszu. Zakładając, że słownik jest już
zbudowany, wtedy w momencie wstawie-
nia bądź aktualizacji rekordu, DB2 przepro-
wadza analizę rekordu pod kątem zgodności
wzorców i proponuje skrócony format zapi-
su rekordu. Jeśli w słowniku nie znajdują się
wzorce, które pasują do wstawianego (mo-
dyfikowanego) rekordu, wtedy rekord wpro-
wadzany jest w oryginalnej postaci, tak jak
dla tabel, które nie wykorzystują kompre-
sji. Słownik nie jest aktualizowany w trybie Rysunek 1. Zastosowanie dwa razy większych dysków zmniejszy wydajność mierzoną w liczbie
online, ponieważ wiązałoby się to ze zbyt operacji I/O na sekundę

www.sdjournal.org 79
Administracja

korzystałem tabele oraz dane przygotowa- są także funkcje, które pozwalają oszacować ADMIN_GET_TAB_COMPRESS_INFO_V97 z argu-
ne dla testu TPC-H, zgodnie ze specyfikacją współczynniki kompresji dla danych oraz in- mentem ESTIMATE, by wstępnie oszacować
opublikowaną na stronie www.tpc.org. Tabele deksów. Po załadowaniu danych odpowied- współczynniki kompresji. Funkcję urucho-
załadowałem plikami tekstowymi o rozmia- nim zapytaniem pokazanym na Listingu 1 miłem niezależnie dla każdej z tabel, poda-
rze 1 GB, które wygenerowałem programem sprawdziłem, ile miejsca zajmują poszcze- jąc nazwę tabeli jako drugi argument funk-
dbgen, dostarczanym razem z testem TPC-H. gólne tabele oraz ich indeksy. Do wygenero- cji, tak jak pokazałem to na Listingu 2. Oczy-
Włączenie kompresji ma sens dla tych tabel, wania raportu wykorzystałem widok admini- wiście mogłem wywołać funkcję tak, by wyli-
które zajmują dużo miejsca, oraz dla których stracyjny ADMINTABINFO ze schematu SY- czyć współczynniki dla wszystkich tabel (pu-
kompresja przyniesie odpowiednio duże ko- SIBMADM. Raport posortowałem malejąco sty ciąg znaków zamiast nazwy tabeli) i w wa-
rzyści (współczynniki kompresji będą odpo- od największych tabel do najmniejszych. Do runku WHERE zapytania wybrać interesujące
wiednio wysokie), dlatego też warto wyko- dalszej analizy wybrałem trzy największe ta- mnie rekordy. Takie podejście byłoby dużo
nać wstępną analizę potencjalnych zysków z bele, które zajmowały 95% rozmiaru wszyst- kosztowniejsze dla bardzo dużej bazy danych.
włączenia kompresji. DB2 dostarcza szereg kich tabel testu TPC-H (1.4 GB): LINEITEM W moim środowisku (notebook Lenovo T61,
odpowiednich widoków oraz funkcji admi- – 950 MB (dane + indeksy), ORDERS – 220 Intel Core2 duo, 2 GHz) wykonanie estyma-
nistracyjnych, które pozwalają na wyliczenie MB oraz PARTSUPP – 169 MB. cji dla największej tabeli LINEITEM zajęło 26
miejsca zajmowanego przez tabele, indeksy, Następnie dla każdej z trzech wybranych sekund, więc różnica byłaby niezauważalna
obiekty XML oraz obiekty BLOB. Dostępne tabel uruchomiłem funkcję tabelaryczną – w ogólnym przypadku lepiej wykonywać
takie analizy tabela po tabeli, przede wszyst-
kim ze względu na większą kontrolę. Szaco-
wane współczynniki kompresji przedstawi-
łem na Listingu 3. Jak widać, rozmiar słow-
nika kompresji jest podobny dla każdej z ta-
bel (ok. 40 KB), mimo iż tabele znacznie róż-
niły się rozmiarem.
Kompresję włączyłem instrukcją ALTER
TABLE oraz ALTER INDEX, dla każdej z trzech wy-
branych tabel oraz indeksów tych tabel. Poniżej
przedstawiłem przykładową instrukcję dla tabe-
li LINEITEM. Nazwy indeksów dla tabeli pobra-
łem poleceniem DESCRIBE INDEXES FOR TABLE
TPCH.LINEITEM:

alter table tpch.lineitem compress yes;


alter index tpch.l_okln compress yes;

Wykonanie instrukcji ALTER .. COMPRESS


zmienia definicję tabeli, natomiast nie two-
Rysunek 2. Zastosowanie kompresji pozwala zwiększyć wydajność systemu dyskowego i wirtualnie rzy słownika oraz nie wykonuje przebudo-
zwiększyć bufor bazy danych wania istniejących tabel do nowego, skróco-
nego formatu. Taką przebudowę połączoną
Listing 2. Oszacowanie współczynnika kompresji dla wybranej tabeli (TPCH.LINEITEM) z tworzeniem słownika można wykonać po-
leceniem REORG, tak jak pokazałem to poni-
select char(tabname,10) as table, compress_dict_size as "DICTIONARY SIZE [B]", żej. Wykonanie przebudowy największej ta-
pages_saved_percent as "PAGES SAVED [%]" from table(sysproc. beli LINEITEM zajęło w moim środowisku 4
admin_get_tab_compress_info_v97 ('TPCH','LINEITEM', minuty:
'ESTIMATE') ) as t where object_type = 'DATA' ;
reorg table tpch.lineitem use tempspace1
Listing 3. Wyniki wstępnego oszacowania współczynników kompresji (dane bez indeksów) reorg indexes all for table tpch.lineitem

TABLE DICTIONARY SIZE [B] PAGES SAVED [%] Po przebudowaniu wszystkich trzech ta-
---------- -------------------- --------------- bel (LINEITEM, ORDERS, PARTSUPP) sprawdzi-
LINEITEM 46208 60 łem, ile miejsca teraz zajmują tabele. Wynik
ORDERS 40192 61 został przedstawiony na Listingu 4. Jak wi-
PARTSUPP 43648 65 dać, rozmiar tabel znacznie się zmniejszył.
Łączny rozmiar bazy danych zmniejszył się
Tabela 1. Przykładowe dwa rekordy tabeli XML.PARTSUPP
ID PARTSUPP
1 <row><PS _ PARTKEY>1</PS _ PARTKEY><PS _ SUPPKEY>2</PS _ SUPPKEY><PS _ AVAILQTY>3325</PS _ AVAILQTY><PS _
SUPPLYCOST>7.7164E2</PS _ SUPPLYCOST><PS _ COMMENT>requests after the carefully ironic ideas cajole alongside
of the enticingly special accounts. fluffily regular deposits haggle about the blithely ironic deposits.
regular requests sleep c</PS _ COMMENT></row>

2 <row><PS _ PARTKEY>1</PS _ PARTKEY><PS _ SUPPKEY>2502</PS _ SUPPKEY><PS _ AVAILQTY>8076</PS _ AVAILQTY><PS _


SUPPLYCOST>9.9349E2</PS _ SUPPLYCOST><PS _ COMMENT>careful pinto beans wake slyly furiously silent pinto beans.
accounts wake pendi</PS _ COMMENT></row>

80 SDJ Extra 35
Kompresja w DB2

z 1.40 GB do 0.66 GB. Oczywiście rozmiar (patrz Listing 6 i porównaj go z Listingiem niżej przedstawiłem definicję tabeli, któ-
plików na dysku pozostał ten sam, a jedy- 4). Łączny rozmiar tabel skompresowanych ra przechowuje dokumenty XML na stro-
nie wewnętrzne wykorzystanie przestrzeni automatycznie wyniósł 0.68 GB – dla po- nie razem z podstawowymi danymi (klau-
zostało zredukowane. By zredukować także równania, kompresując tabele metodą of- zula INLINE):
rozmiar plików na dysku, można wykorzy- fline, rozmiar wynosił 0.66 GB. W niektó-
stać instrukcję ALTER TABLESPACE REDUCE, rych przypadkach metoda automatyczne- create tablespace xmlspace;
tak jak poniżej: go generowania słownika może dać gorsze create table xml.partsupp
współczynniki kompresji, nie wymaga jed- (id int, partsupp xml inline length 1000)
alter tablespace userspace1 reduce max nak reorganizacji i rozmiar plików na dysku in xmlspace compress yes;
jest zbliżony do faktycznego rozmiaru (nie
Wykonanie powyższej instrukcji spowoduje wymaga pomniejszania). Przy takiej definicji tabeli dokumenty XML
zmniejszenie rozmiaru kontenerów (plików) nieprzekraczające 1000 bajtów (klauzula
obszaru tabel USERSPACE1 poprzez usunięcie XML, BLOB LENGTH 1000) będą przechowywane na stro-
pustych ekstent-ów, nieprzydzielonych do żad- DB2 9.7 pozwala także kompresować do- nach razem z podstawowymi danych (po-
nego z obiektów. Porównałem rozmiary konte- kumenty XML oraz BLOB-y. Standardo- le ID). Jeśli rozmiar dokumentu przekroczy
nera tego obszaru tabel (plik C0000000.LRG wo obiekty typu BLOB przechowywa- zdefiniowany próg 1000 bajtów, wtedy za-
) sprzed i po wykonaniu tej instrukcji i wy- ne są w wydzielonej przestrzeni. Podob- wartość pola PARTSUPP zostanie automatycz-
nik odpowiada uzyskanemu współczynnikowi nie też dokumenty XML przechowywane nie przeniesiona do hierarchicznego repozy-
kompresji (patrz Listing 5). są nie na stronach z danymi podstawowy- torium. Przechowywanie mniejszych obiek-
mi, a w osobnym obszarze hierarchicznym. tów XML razem z pozostałymi danymi po-
Automatyczne DB2 umożliwia umieszczenie tego rodzaju zwala skorzystać z omówionych wcześniej al-
generowanie słownika obiektów na stronach razem z danymi pod- gorytmów kompresji. By zademonstrować
Przedstawione powyżej podejście kompresji stawowymi. Taka metoda przechowywania kompresję dokumentów XML, załaduję na-
istniejących danych wymaga reorganizacji ta- obiektów określana jest jako inlineing. Po- rzędziem LOAD tabelę XML.PARTSUPP danymi
beli w trybie offline, co oznacza, że tabela jest
niedostępna dla użytkowników na czas prze- Listing 4. Sprawdzenie miejsca zajmowanego przez tabele po kompresji
budowy. Do skompresowania tabeli podczas
normalnej pracy użytkowników można wy- SELECT CHAR(TABNAME, 10) AS TABLE, DATA_OBJECT_L_SIZE AS "DATA SIZE [KB]",
korzystać specjalną procedurę składowaną INDEX_OBJECT_L_SIZE AS "INDEX SIZE [KB]" FROM
ADMIN_MOVE_TABLE, która pozwala przenosić SYSIBMADM.ADMINTABINFO WHERE TABSCHEMA = 'TPCH' ORDER BY
tabele w trybie online pomiędzy różnymi ob- DATA_OBJECT_L_SIZE DESC;
szarami tabel. W trakcie przenoszenia istnie-
je możliwość zmiany atrybutów tabeli, w tym TABLE DATA SIZE [KB] INDEX SIZE [KB]
tych związanych z kompresją. ---------- -------------------- --------------------
Innym mechanizmem włączenia kom- LINEITEM 324864 115072
presji, nieograniczającym dostępności tabe- ORDERS 71040 37760
li, jest mechanizm automatycznego genero- PARTSUPP 43136 35584
wania słownika kompresji – ADC (Automa- PART 30720 3456
tic Dictionary Creation). Wykorzystanie te- CUSTOMER 27904 3968
go mechanizmu ogranicza się do utworze- SUPPLIER 1792 512
nia tabeli z włączonym atrybutem kompre- NATION 256 256
sji. Podczas wstawiania danych do tabeli, REGION 256 256
DB2 na bieżąco aktualizuje definicję słow-
nika kompresji. Rekordy wstawiane są jed- Listing 5. Porównanie rozmiaru plików bazy na dysku sprzed i po kompresji
nak w nieskompresowanym formacie aż do Directory of C:\DB2\NODE0000\TPCH\T0000002
momentu, kiedy DB2 uzna, że jakość wzor-
ców w słowniku jest na tyle dobra, że moż- 2009-07-19 22:54 1 509 949 440 C0000000.LRG
na zatwierdzić jego definicję. Od tego mo- 2009-07-19 22:35 0 SQLCRT.FLG
mentu słownik nie będzie już aktualizo- 2 File(s) 1 509 949 440 bytes
wany, a nowo wstawiane dane będą zapi-
sywane już w skompresowanym formacie.
Moment, w którym DB2 zaczyna zapisy- 2009-07-20 02:35 714 080 256 C0000000.LRG
wać rekordy w nowym formacie, jest au- 2009-07-19 22:35 0 SQLCRT.FLG
tomatycznie wybierany przez DB2. W ce- 2 File(s) 714 080 256 bytes
lu przetestowania mechanizmu ADC po-
wtórnie utworzyłem tabele oraz indek-
Tabela 2. Rozmiar i czas wykonania backup-ów
sy bazy TPCH, dodając do definicji tabel
klauzulę COMPRESS YES, a następnie załado- Rozmiar Czas Kompresja tabel Kompresja backup-u
backup-u
wałem dane narzędziem IMPORT. Narzędzie
IMPORT ładuje dane przy wykorzystaniu in- 1536 MB 5m 25s nie nie
strukcji SQL INSERT i dobrze oddaje spo- 532 MB 2m 02s nie tak
sób, w jaki interaktywne aplikacje wprowa- 608 MB 2m 09s tak nie
dzają dane. Rozmiar tabel tylko nieznacz-
456 MB 1m 36s tak tak
nie różnił się od kompresji metodą offline

www.sdjournal.org 81
Administracja

z tabeli TPCH.PARTSUPP. Narzędzie LOAD ładu- db2 backup db tpch compress Natomiast niezależnie od liczby dysków,
je dane w sposób blokowy (nietransakcyjny) i skompresowana wcześniej baza danych za-
podobnie jak narzędzie IMPORT obsługuje au- Opcjonalnie można także podać nazwę bi- wsze będzie się backup-ować szybciej, po-
tomatyczną kompresję. Polecenia ładujące ta- blioteki, która ma być wykorzystana do nieważ będzie mniej stron do odczytania.
belę przedstawiłem na Listingu 7. W pierw- kompresowania bloków danych (jeśli ma Regułę tę potwierdza praktyka. Jeden z
szej linii tworzę kursor oparty na zapytaniu być inna niż ta dostarczona z instalacją klientów DB2 i SAP ERP w Polsce przy wy-
przetwarzającym wszystkie rekordy z tabe- DB2). Przeprowadziłem kilka testów, by zo- korzystaniu kompresji DB2 zmniejszył pra-
li TPCH.PARTSUPP, natomiast w drugiej ładu- rientować się, jak kompresja wpływa na roz- wie o połowę rozmiar bazy danych (z 3 TB)
ję docelową tabelę, podając nazwę kursora K1 miar plików zawierających obraz backup-u i dzięki temu nie musiał zmieniać polityki
jako źródło ładowanych danych. Zapytanie oraz czas jego wykonania. Najpierw wyko- backup-owej, by wykonać backup w założo-
pobierające wiersze do załadowania wykorzy- nałem backup dla bazy nieskompresowanej nym oknie czasowym.
stuje funkcję XMLROW, która buduje dokument z wyłączoną opcją kompresji backup-u. Na-
XML zawierający wartości wszystkich pól ta- stępnie jeszcze raz wykonałem backup tej Wydajność
beli ubranych w znaczniki będące nazwami samej bazy, ale z włączoną opcją kompre- Bez dwóch zdań – kompresja zużywa moc
kolumn. W Tabeli 1 pokazałem przykładowe sji backup-u. Obydwa pomiary powtórzy- procesora! Jeśli ktoś w teście wydajnościo-
dwa rekordy z XML.PARTSUPP. łem dla bazy danych, która zawierała już wym chce wycisnąć maksimum, przy dodat-
Podobne ćwiczenie wykonałem dla tabeli o skompresowane dane. W Tabeli 2 przed- kowym założeniu, że dysponuje nieskończenie
identycznej strukturze co XML.PARTSUPP, lecz stawiłem wyniki doświadczenia. Jak wi- szybką macierzą dyskową, wtedy kompresji
nieskompresowanej. Nieskompresowana tabela dać, najdłużej wykonywał się backup bazy, włączać nie powinien. Oczywiście określenie
XML zajmowała 357 MB, natomiast utworzo- która nie zawierała skompresowanych tabel nieskończenie szybką wydaje się być przesadą,
na z klauzulą COMPRESS YES – 118 MB, co da- oraz dla której nie włączono kompresji bac- choć nie do końca. W laboratoryjnych testach
ło 70% współczynnik kompresji. Warto jeszcze kup-u. Na pierwszy rzut oka może dziwić, wydajnościowych (takich jak TPC-H) dokła-
wspomnieć, że dla obiektów XML DB2 budu- że włączenie kompresji backup-u spowodo- da się tyle dysków, aż uzyska się moment, w
je dodatkowy (drugi) słownik, ponieważ wzor- wało skrócenie czasu jego wykonania (dru- którym dyski odpowiadają na tyle szybko, że
ce dokumentów XML mogą znacząco różnić ga pozycja w tabeli). Można to jednak bar- da się osiągnąć 100% utylizację procesorów.
się od wzorców występujących w danych pod- dzo prosto wytłumaczyć. Podczas tworze- W rzeczywistych systemach, przede wszyst-
stawowych. nia archiwum, DB2 musi odczytać całą ba- kim ze względu na duże koszty, wymiaruje
zę danych, a następnie zapisać jej zawartość się systemy, zwracając w pierwszej kolejności
Tabele tymczasowe do pliku, będącego obrazem archiwum. W uwagę na wymaganą przestrzeń dyskową. W
Warto wspomnieć, że DB2 posiada także wbu- moim systemie baza była utworzona na dys- rzeczywistych systemach także nie zakłada
dowane mechanizmy kompresji tabel tymcza- ku C, natomiast obraz archiwum tworzony się 100% utylizacji procesorów – obciążenie
sowych. Kompresja dla takich tabel stosowana był na dysku D. Wąskim gardłem był zapis jest niejednorodne i zawsze rezerwuje się ja-
jest przez DB2 automatycznie. Baza samoczyn- na dysk, który zawierał docelowy obraz ar- kiś zapas mocy na skoki przetwarzania. Dlate-
nie sprawdza, czy wykorzystanie kompresji dla chiwum. Odczyt stron z dysku i ich kom- go też w rzeczywistych systemach opartych o
danej tabeli tymczasowej przyniesie korzyści, i presja w locie była szybsza niż sam zapis na DB2 stosuje się kompresję – najczęściej w du-
podejmuje decyzję o włączeniu bądź wyłącze- dysk D. Najlepszy rezultat został osiągnię- żych rozwiązaniach, np. takich jak SAP ERP
niu kompresji. ty dla kompresowanego backup-u i skom- czy SAP BI. Wnikliwszym czytelnikom po-
presowanej już bazy, ponieważ w tym przy- lecam opracowanie Waldemara Gaidy DB2
Backup padku ilość stron do skopiowania oraz za- 9 Row Compression in a SAP, w którym opi-
DB2 udostępnia także mechanizm kompresji pisania była najmniejsza. W ogólnym przy- sał wpływ kompresji na wydajność przetwa-
backup-ów, który na bieżąco pakuje bloki prze- padku czasy mogą się różnić. Jeśli dysponu- rzania na podstawie jednego z rzeczywistych
syłane do obrazu backup-u. By wykonać skom- jemy dostatecznie dużą liczbą dysków, wte- projektów (Google: waldemar gaida sap com-
presowany backup, wystarczy dodać klauzulę dy kompresja backup-u najprawdopodob- pression). Ogólny wniosek z opracowania jest
COMPRESS, tak jak w przykładzie poniżej: niej spowolni proces tworzenia archiwum. taki: dzięki kompresji procesy wsadowe dzia-
łają szybciej, system charakteryzuje się lep-
Listing 6. Rozmiary tabel ładowanych instrukcją SQL INSERT z automatyczną kompresją szymi czasami odpowiedzi, wzrasta śred-
nia utylizacja procesorów. Tak jak już wcze-
TABLE DATA SIZE [KB] INDEX SIZE [KB] śniej wspomniałem, oszczędne formaty za-
---------- -------------------- -------------------- pisu danych na dyskach z jednej strony wpi-
LINEITEM 339072 112128 sują się w trendy rozwoju sprzętu, a z drugiej
ORDERS 79744 40064 strony wpisują się w ideę Smarter Planet (Mą-
PARTSUPP 45568 41600 drzejszej Planety), propagowaną przez IBM,
CUSTOMER 15616 3072 zmierzającą do oszczędności oraz inteligent-
PART 12032 3200 niejszego i optymalniejszego działania.
SUPPLIER 1792 384
NATION 256 256
REGION 256 256
Artur Wroński
Listing 7. Załadowanie tabeli XML.PARTSUPP danymi XML Od piętnastu lat specjalizuje się w rozwiązaniach
declare k1 cursor for select row_number() over(), xmlrow( ps_partkey, ps_suppkey, przetwarzania danych. Aktualnie pracuje jako
ps_availqty, ps_supplycost, ps_comment) from tpch.partsupp; kierownik zespołu technicznego IBM Information
Management Software.
load from k1 of cursor insert into xml.partsupp ; Kontakt z autorem: artur.wronski@pl.ibm.com

82 SDJ Extra 35

You might also like