To co najważniejsze w 10g. Część 4.

Mobilne przestrzenie tabel, czyli Transportable Tablespaces

Jadwiga Gnybek Jadwiga_Gnybek@nofer.lodz.pl

W tym odcinku wędrówek po ciekawych, a mało znanych funkcjonalnościach Oracle 10g, przyjrzymy się bliżej możliwościom przenoszenia przestrzeni tabel pomiędzy różnymi platformami systemowymi, czyli funkcji transportable tablespaces.

Metod przenoszenia danych pomiędzy bazami jest wiele. DBA z zagadnieniem tym zmagali się od zarania dziejów. Czy zatem aktualna wersja bazy Oracle przynosi w tym temacie nowe rozwiązania? Bez wątpienia tak. Przyjrzyjmy się bliżej „jak działają” transportable tablespaces.

Jak to działa w telegraficznym skrócie. Przestrzeń tabel ustawiamy do pracy w trybie read-only, dokonujemy eksportu definiujących ją metadanych, z poziomu systemu operacyjnego przenosimy pliki dyskowe przechowujące dane zapisane w tej przestrzeni na maszynę docelową i – jak łatwo się domyślić – importujemy metadane do bazy pracującej pod OS maszyny docelowej.

W porównaniu do bardziej tradycyjnych metod przenoszenia danych polegających na przykład na wykorzystaniu mechanizmu eksportu danych do pliku lub przenoszenia ich poprzez połączenie baz danych (database link), sposób ten o ile nie jest prostszy, to na pewno szybszy – zwłaszcza dla dużych wolumenów danych. Podstawowym wyznacznikiem czasu potrzebnego na transfer danych jest tu bowiem czas potrzebny na przekopiowanie plików dyskowych tworzących fizyczne zasoby przenoszonej przestrzeni pomiędzy maszynami źródłową i docelową. Prawdopodobnie czas ten zależny będzie nie tylko od wielkości pliku, ale i systemów operacyjnych pomiędzy którymi następuje wymiana danych.

Wprawdzie mechanizmy takie istniały już w Oracle 9i, ale obwarowane były wieloma ograniczeniami. Transfer danych możliwy był jedynie pomiędzy niektórymi systemami operacyjnymi (np.: Solaris i HP-UX). Oracle 10g zniósł wiele z tych ograniczeń, choć nadal transfer taki możliwy jest jedynie pomiędzy systemami operacyjnymi mającymi zgodny porządek bajtów. Oczywiście nie czas tu i miejsce na roztrząsanie niuansu porządkowania bajtów w poszczególnych systemach plikowych. Warto jednak przypomnieć, że niektóre systemy operacyjne (takie jak na przykład Windows), przechowują wielobajtowe dane binarne zapisując najmniej znaczący bajt z najniższym adresem pamięci. Z tego powodu systemy te nazywane są czasem „little endian”. Zupełnie inaczej rzecz ma się w systemach takich jak Solaris, gdzie na najniższych adresach zapisywane są najbardziej znaczące bajty danych. Systemy te analogicznie nazywane są „big endian”. Łatwo zatem zgadnąć, że kopiowanie danych pomiędzy systemami tych grup zawsze wymaga procesu konwersji. Więcej informacji dotyczących tematu konwersji zapisu danych znaleźć można w artykule „Introduction to Endianness” opublikowanym na łamach Embedded Systems Programming w styczniu 2002. Oczywiście przenoszenie danych pomiędzy systemami należącymi do tej samej grupy endianów nie wymaga konwersji. Jak zatem dowiedzieć się, do jakiej grupy endianów należą systemy pomiędzy którymi planujemy wymienić dane? Najlepiej zapytać wyroczni, czyli bazy danych Oracle. Baza 10g już to wie, wystarczy jedynie zadać zapytanie postaci:

SQL> select * from v$transportable_platform order by platform_id;
PLATFORM_ID PLATFORM_NAME ENDIAN_FORMAT
---------------------------------------
1 Solaris[tm] OE (32-bit) Big
2 Solaris[tm] OE (64-bit) Big
3 HP-UX (64-bit) Big
4 HP-UX IA (64-bit) Big
5 HP Tru64 UNIX Little
6 AIX-Based Systems (64-bit) Big
7 Microsoft Windows IA (32-bit) Little
8 Microsoft Windows IA (64-bit) Little
9 IBM zSeries Based Linux Big
10 Linux IA (32-bit) Little
11 Linux IA (64-bit) Little
12 Microsoft Windows 64-bit for AMD Little
13 Linux 64-bit for AMD Little
15 HP Open VMS Little
16 Apple Mac OS Big

Endiany równe

Dla potrzeb dalszych rozważań załóżmy, że wymiana danych będzie przebiegała pomiędzy systemami Linux i Windows. Przenoszonym obiektem będzie przestrzeń tabel USERS, która na poziomie systemu operacyjnego reprezentowana jest przez jeden plik dyskowy o nazwie users_01.dbf. Jak już sprawdziliśmy, zarówno system źródłowy jak i docelowy należą do grupy „little endian”. Uprości nam to nieco dalsze działania.

W pierwszym kroku musimy zatem wprawić przestrzeń tabel USERS w tryb READ ONLY. Zadanie banalne nawet dla początkującego DBA:

alter tablespace users read only;

Teraz zadanie znacznie mniej oczywiste. Musimy wyeksportować metadane przenoszonej przestrzeni tabel. Aby tego dokonać z poziomu systemu operacyjnego wydajemy polecenie:

exp tablespaces=users transport_tablespace=y file=exp_ts_users.dmp

Ponieważ plik exp_ts_users.dmp zawiera jedynie metadane przestrzeni i nie zawiera danych w tej przestrzeni zapisanych, jego rozmiar znacząco odbiega od rozmiarów pliku users_01.dbf. Oczywiście jest od tego pliku o wielekroć mniejszy. W następnym ruchu oba (exp_ts_users.dmp, users_01.dbf) interesujące nas pliki muszą zostać przeniesione na maszynę docelową. Tu w sukurs przyjdą nam oczywiście mechanizmy FTP z opcją binarnego transportu danych.

Teraz zaczyna się najważniejsze. Musimy zaimportować do bazy na maszynie docelowej naszą wędrującą przestrzeń danych. Jak pokazuje składnia przykładowego polecenia, użyjemy do tego celu jednocześnie obu przetransportowanych plików:

imp tablespaces=users transport_tablespace=y file=exp_ts_users.dmp datafiles='users_01.dbf'

I już. Baza docelowa widzi już nową przestrzeń tabel. Przypomnijmy tylko, że ponieważ systemem źródłowym był Linux a docelowym Windows, operacja ta nie powiedzie się na bazach 9i, która nie wykonałaby ostatniego polecenia, zwracając komunikat o błędzie wynikającym z niemożności odczytania pliku users_01.dbf.

Przeprowadzenie operacji przenoszenia danych pomiędzy bazami w opisany powyżej sposób ma jeszcze jedną zaletę. Nie zachodzi w tym przypadku konieczność odświeżania indeksów, czego wymaga przenoszenie danych za pośrednictwem plików płaskich czyli przez eksport danych lub ładowanie SQL*Loaderem. Dane które na skutek naszych działań pojawiają się w bazie, są od ręki gotowe do użycia.

Taka wędrówka przestrzeni tabel znajduje zatem szczególnie dużo zastosowań w bazach hurtownianych, gdzie po operacji ładowania hurtowni danymi występuje konieczność powielania do innych lokalizacji małych datamartów, specjalizowanych dla określonej grupy odbiorców. Rozszerzenie w 10g możliwości migracji danych pomiędzy równymi systemami operacyjnymi znacząco wspiera tu budowę lokalnych małych serwerów dostarczających odbiorcom mniejsze fragmenty danych, wybranych z przepastnych zasobów data warehouse’u.

Przypomnijmy na koniec, że ten szybki sukces osiągnęliśmy przenosząc pliki pomiędzy systemami operacyjnymi należącymi do tej samej grupy endianów.

Endiany różne

Teraz rzucimy się naprawdę na głęboką wodę i prześledzimy analogiczną operację wykonaną na bazach pracujących pod kontrolą systemów operacyjnych należących do różnych grup endianów. Załóżmy zatem, że źródłem danych znów będzie Linux ale baza docelowa pracuje pod kontrolą HP-UX, który należy do grupy „big endian”. Tym razem z pewnością nie wystarczy transfer potrzebnych plików z jednej maszyny na drugą. Pliki te trzeba poddać konwersji. Ku naszemu zdziwieniu, do konwersji pliku użyć możemy narzędzia będącego od dawna na wyposażeniu bazy Oracle. Wykorzystamy do tego celu Oracle 10g RMAN. Wydając polecenie o następującej składni:

RMAN> convert tablespace users
2> to platform 'HP-UX (64-bit)'
3> format='/home/oracle/rman_bkups/%N_%f';

uruchomimy proces, który przekonwertuje nam plik Linuksa do formatu pliku HP-UX. Oczywiście nie zrobi tego tak dosłownie. Zapisze bowiem dane przestrzeni USERS w pliku o standardzie swoistym dla tego narzędzia. Znajdziemy go w folderze /home/oracle/rman_bkups pod nazwą utworzoną według schematu:

<tablespace_name>_<absolute_datafile_no>.

Jeśli na naszą przestrzeń tabel składałoby się fizycznie więcej niż jeden plik, RMAN umożliwia zrównoleglenie prac nad transformacją każdego z tych plików. Dodanie do przedstawionej poprzednio składni polecenia opcji:

parallelism = 4

spowoduje uruchomienie czterech niezależnych kanałów mogących jednocześnie konwertować cztery pliki danych z bazy źródłowej. Oczywiście plik źródłowy nie został w czasie tej operacji w żaden sposób zmodyfikowany. Teraz wystarczy plik utworzony przez RMAN przetransportować na maszynę pracującą pod HP-UX i rozpakować go jak klasyczny backup.

Co ciekawe, operację konwersji pliku można przeprowadzić zarówno po stronie maszyny źródłowej jak i docelowej. W tym drugim przypadku najpierw przenosimy pliki do konwersji a później wydajemy polecenie konwersji. W tym jednak przypadku polecenie to będzie miało nieco inny format:

RMAN> convert
2> datafile '/usr/oradata/dw10/dw10/users01.dbf'
3> format '/home/oracle/rman_bkups/%N_%f'
4> ;

Po co ta wielość wyborów? Choćby po to, aby móc wybrać do konwersji maszynę w danej chwili mniej obciążoną lub silniejszą sprzętowo. Innym powodem może być fakt, że konwersja wymaga postawienia przestrzeni tabel w tryb READ ONLY. Jeśli krytyczny jest dla nas czas w jakim przestrzeń jest niedostępna do zapisu, to operacją zdecydowanie krótszą będzie wykonanie kopii plików na systemie źródłowym, udostępnienie przestrzeni w trybie READ WRITE, a następnie przeniesienie jej na stronę maszyny docelowej i dopiero tam uruchomienie konwersji. Jak widzimy, mechanizmy te dają administratorowi spore pole manewru, umożliwiające dostosowanie procedury przenoszenia danych do specyfiki systemu.

Jak wykorzystać External Tables w procesie wędrówki danych

Innym mechanizmem pozwalającym nam na przenoszenie danych pomiędzy bazami jest wykorzystanie do tego celu tabel zewnętrznych. Już baza 9i posiadła umiejętność tworzenia tabel poza plikami tworzącymi przestrzenie tabel. Dane w takim przypadku – choć fizycznie przechowywane w plikach płaskich, widziane są z perspektywy bazy tak samo jak te „regularnie” umieszczone wewnątrz bazy.

Przypuśćmy, że dla przykładu chcielibyśmy przenieść tabelę o nazwie DANE z bazy transakcji bieżących do bazy hurtownianej. W tym celu musimy wykonać kilka czynności. Po pierwsze wyrzucić tablicę DANE do pliku płaskiego:

spool dane_flat.txt
select <column_1> ||','|| <column_2> ||','|| ...
from dane;
spool off

W wyniku działania tego skryptu otrzymujemy oczywiście plik w bieżącym katalogu roboczym dane_flat.txt. Tak stworzony plik przenosimy na maszynę, na której pracuje instancja bazy hurtownianej. W tym celu możemy użyć na przykład banalnego FTP i przenieść nasz plik powiedzmy do katalogu /home/oracle/flat_dir. Teraz katalog ten kreujemy jako obiekt bazy hurtownianej:

create directory flat_dir as '/home/oracle/flat_dir';

Teraz już tylko tworzymy w bazie hurtownianej tabelę zewnętrzną:

create table dane_ext
(
... <columns of the table> ...
)
organization external
(
type oracle_loader
default directory admin
access parameters
(
records delimited by newline
badfile 'dane_ext.bad'
discardfile 'dane_ext.dis'
logfile 'dane_ext.log'
fields terminated by “," optionally enclosed by '“'
(
... <columns> ...
)
)
location ('dane_flat.txt')
)
reject limit unlimited;

I po wszystkim. Teraz z tymi danymi możemy zrobić wszystko. Przepisać je poleceniami SQL w inne miejsca bazy, czy wykorzystać bezpośrednio do odświeżenia hurtownianych raportów.

W całej tej operacji bezwzględnie najwięcej czasu zajmie nam wyciągnięcie danych do pliku płaskiego. Pokazany tu sposób wykorzystujący polecenia SQL*Plusa jest dość powolny. Jeśli zatem zależy nam na czasie, możemy operację tę oprogramować w Pro*C lub OCI.

Drugim elementem wymagającym od nas wykonywania czasochłonnych operacji jest konieczność „ręcznego” definiowania w bazie docelowej struktury przenoszonej tabeli. Oczywiście jeśli operacja ta wykonywana jest cyklicznie, będziemy mogli z powodzeniem wykorzystać raz utworzone skrypty, ale sprawę można przyspieszyć już za pierwszym wykonaniem takiego transferu. Jedynym warunkiem jest tu posiadanie bazy w wersji 10g. Wykorzystamy do tego proces tworzenia tabeli zewnętrznej na podstawie danych zapisanych w tabeli znajdującej się wewnątrz bazy. Tak jak poprzednio, transportować będziemy tabelę DANE, którą na czas podróży umieścimy w katalogu dyskowym DANE_DIR:

create directory dane_dir as '/home/oracle/ dane_dir';
create table dane_dump
organization external
(
type oracle_datapump
default directory dane_dir
location ('dane_dump.dmp')
)
as
select * from dane
/

Utworzony w ten sposób plik dane_dump.dmp nie jest plikiem tekstowym ASCII. Format tekstowy zachowany jest jedynie w zapisie części metadanych. Dane tabeli zapisane są w formacie natywnym bazy. Podobnie jak pliki eksportu, dane wyekstrahowane w tym formacie są przenaszalne pomiędzy bazami pracującymi w środowisku różnych systemów operacyjnych, a – co nie mniej ważne – wprowadzenie tak utworzonych plików do „nowej” bazy trwa znacząco krócej. Oczywiście niezbędne jest fizyczne przekopiowanie tych plików i podłączenie ich do bazy jako źródła danych tabeli zewnętrznej.

Na czym więc polega różnica?

Po pierwsze, tabela zewnętrzna tworzona jest szybciej, bez konieczności pisania skryptu SQL. Po drugie, plik ten (stanowiący źródło danych do tabeli zewnętrznej bazy docelowej) możemy tworzyć w trybie wielowątkowym uzupełniając wydaną poprzednio komendę o opcję – na przykład parallel 3, co powinno przyspieszyć operację 2-3 krotnie. Dalsze przyspieszenie przetwarzania uzyskać można poprzez wielowątkowe tworzenie wielu plików, z tym że operacja ta przynosi efekt jedynie dla maszyn posiadających więcej niż jeden procesor.

create table data_dump
organization external
(
type oracle_datapump
default directory data_dir
location ('data_dump_1.dmp','data_dump_2.dmp')
)
parallel 4
as
select * from data
/

Jak widać, w tym przypadku uruchamiając 4 wątki przetwarzania, tworzymy dwa pliki z danymi. Jeśli na dodatek skierujemy je na dwa niezależnie sterowane zasoby dyskowe, to operacja ma szansę zakończyć się zadawalająco szybko.

Tytułem posłowia, warto docenić wielość mechanizmów jakie 9i i 10g oddaje w ręce DBA. A wszystko po to, aby dane były jak najszybciej dostępne na maszynach pracujących jak najbliżej lokalizacji lub najbliżej funkcjonalnych potrzeb użytkowników aplikacji.