środa, 30 listopada 2011

Zużycie Flash Recovery Area. Czyli ile jeszcze zostało miejsca na backupy?

Mieliście już przyjemność spotkać komunikat "archiver error" w alert logach w akompaniamencie padu instancji?  Skończyło się miejsce na archivelogi. Sprawdźcie czasem dla spokoju ducha ile zostało miejsca w FRA procentowo:














No dobrze, ale z jakiej wielkości?



To jest wartość w bajtach. Pamiętamy tylko że wartość tego parametru możemy sobie ustawić i na 1000 tera, rman nie sprawdza czy mamy w ogóle dostępną taką przestrzeń dyskową. Tak więc założenie jest takie , że przy ustawianiu maksymalnej wielkości dla FRA nie poniosła Was fantazja... :)

Duplikacja pliku kontrolnego w Oracle, lub utrata istniejącego.

Jak już pewnie wiecie, plik kontrolny jest niezwykle ważny. Jego utrata w przypadku gdy nie mamy kopii zapasowej może być "bolesna". Dobrze by więc było mieć je zduplifikowane - tzn. tak by były dwie kopie jednocześnie, równolegle uaktualniane. W razie utraty jednego, mamy jego kopię.
  1. Sprawdzamy gdzie w ogóle leży nasz plik kontrolny.
  2. Z poziomu systemu operacyjnego wykonujemy jego normalną fizyczną kopię.
  3. Zmieniamy parametr control_files podając poza lokalizacją pierwotną, lokalizację dodatkowego controlfile. Oczywiście ten parametr nie może być zmieniony dla włączonej instancji i trzeba zmieniać ten parametr z opcją scope=spfile, a następnie zrestartować instancję. Dlaczego? Ano dlatego że pliki kontrolne są podpinane do instancji w trybie mount, a nie możemy majdrować przy podpiętych do instancji plikach.
  4. Restart. W tej chwili oba pliki będą uzupełnianie równolegle, a w razie utraty jednego z controlfili, możemy nawet zmienić parametr control_files w spfile (eksportując go go pfile , zmieniając pfile, a następnie odtwarzając spfile z pfile)  w taki sposób by szukał tylko jednego pliku. Możemy również ( po wcześniejszym położeniu bazy) zrobić zwykłą kopię istniejącego pliku.


środa, 2 listopada 2011

Korzystanie z plików tekstowych przy użyciu pakietu UTL_FILE

Korzystanie z plików tekstowych przy użyciu pakietu UTL_FILE




Z poziomu PL SQL możemy korzystać z zewnętrznych plików przy pomocy pakietu UTL_FILE. Aby móc z niego korzystać należy uprzednio użytkownikowi nadać uprawnienia :



(z sysa) GRANT EXECUTE ON UTL_FILE TO HR;



Musimy też zadbać o to, by katalog do którego będziemy sięgać był widoczny z poziomu Oracle:



(z sysa)  CREATE DIRECTORY DANE AS 'C:\DANE'



oraz oczywiście by użytkownik miał do niego odpowiednie uprawnienia:



(z sysa)  GRANT READ,WRITE ON DIRECTORY DANE TO HR;






Pisanie do pliku


Poniższy kod dodaje do pliku mojedane.csv znajdującego się w katalogu c:\dane dwie linie:


declare
plik utl_file.file_type;
begin
plik:=utl_file.fopen('DANE','mojedane.csv','a');
utl_file.put_line(plik,'Romek;507000000;');
utl_file.put_line(plik,'Zenek;503000000;');
utl_file.fclose(plik);
end;



plik utl_file.file_type - jest to uchwyt do naszego fizycznego pliku na dysku. Musi być typu „file_type” znajdującego się w pakiecie utl_file.









plik:=utl_file.fopen('DANE','mojedane.csv','a'); - dowiązanie do uchwytu (dotychczas niezainicjowanego) pliku mojedane.csv znajdującego się w katalogu który wewnątrz bazy reprezentowany jest pod nazwą DANE. Z tą nazwą katalogu jest takie drobne utrudnienie – zawsze pisz dużymi literami w tym miejscu, nawet jeśli katalog podczas jego mapowania (create directory dane as 'c:\dane') nazwaliście małymi literami. Inaczej powie że nie ma takiego katalogu. Trzeci parametr określa rodzaj dostępu do pliku. „a” oznacza stworzenie pliku jeśli go nie ma, a jeśli jest to dopisanie czegoś do niego. Może być też „w” które oznacza że jeśli plik jest to zostanie zastąpiony nowym, lub „r” jeśli plik będziemy czytać.


utl_file.put_line(plik,'Romek;507000000;'); - dopisanie linijki do pliku który znajduje się pod uchwytem o nazwie „plik”.



utl_file.fclose(plik); - zamykamy dowiązanie do pliku, by przy ponownej próbie dostępu Oracle nie zgłosił nam że zasób jest zajęty.



Odczyt pliku



declare
plik utl_file.file_type;
linia varchar2(500);
begin
plik:=utl_file.fopen('DANE','mojedane.csv','r');
loop
utl_file.get_line(plik,linia);
dbms_output.put_line(linia);
end loop;
exception
when others then
utl_file.fclose(plik);
end;



plik:=utl_file.fopen('DANE','mojedane.csv','r'); - otwarcie pliku do odczytu.
utl_file.get_line(plik,linia); - wywołanie procedury z jednym parametrem wejściowym a drugim wyjściowym. Do zmiennej linia ładowana jest kolejna linia z pliku dowiązanego pod zmienną plik.



Część z obsługą wyjątków jest tutaj dlatego, że Oracle nie dostarcza metody sprawdzania czy w pliku znajduje się kolejna linia do przeczytania. W pewnym więc momencie będziemy próbowali odczytać linię której nie ma, więc zgłoszony zostanie wyjątek.

Wlaczanie cyklicznosci wykonywania zadan z uzyciem DBMS_SCHEDULER


Przede wszystkim garść podstawowych pojęć:

job – określa co ma być zrobione. Moze to być program pl sql albo skrypt na dysku. Przy definiowaniu joba możesz tez zdefiniować jego częstotliwość uruchamiania.

Schedule - to taki terminarz wykonywania jobów. Możesz zrobić schedula który odpala się codziennie o 15 i podpiąć pod niego kilka jobów. Dzięki temu on te joby odpala, a kiedy zmienisz częstotliwość schedula to i wszystkie joby będą się odpalały wg nowych ustawień i nie musisz dla każdego joba zmieniać tego oddzielnie.

Program – w nim możesz zdefiniować dzialania. Następnie możesz go podpiąć pod wiele jobów dzięki czemu one będą wywoływały program. I jak coś w nim zmienisz to zmiana ta będzie uwzględniona niezależnie od tego jaki job ją wykonuje.


Przykład tworzenia schedula:

BEGIN
  DBMS_SCHEDULER.create_schedule (
    schedule_name   => 'test_hourly_schedule',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'freq=hourly; byminute=0',
    end_date        => NULL,
    comments        => 'Repeats hourly, on the hour, for ever.');
END;

Kasowanie schedula:

BEGIN
  DBMS_SCHEDULER.drop_schedule (schedule_name => 'TEST_HOURLY_SCHEDULE');
END;


Przyklad tworzenia programu wykonującego jakiś kawałek kodu pl sql:

BEGIN
  -- PL/SQL Block.
  DBMS_SCHEDULER.create_program (
    program_name   => 'test_plsql_block_prog',
    program_type   => 'PLSQL_BLOCK',
    program_action => 'BEGIN DBMS_STATS.gather_schema_stats(''SCOTT''); END;',
    enabled        => TRUE,
    comments       => 'Program to gather SCOTT''s statistics using a PL/SQL block.');
end;


Przyklad tworzenia programu wywołującego jakiś skrypt na dysku:
begin
 DBMS_SCHEDULER.create_program (
    program_name        => 'test_executable_prog',
    program_type        => 'EXECUTABLE',
    program_action      => '/u01/app/oracle/dba/gather_scott_stats.sh',
    number_of_arguments => 0,
    enabled             => TRUE,
    comments            => 'Program to gather SCOTT''s statistics us a shell script.');
end;


Przykład kasowania programu:
begin
DBMS_SCHEDULER.drop_program (program_name => 'test_plsql_block_prog');
end;


Możesz sobie stworzyć zwykłego najprostszego joba bez oddzielnego schedula i bez korzystania z programu, tylko takiego gdzie w samym jobie masz okreslone co ma być wykonane i kiedy (czestotliwość wykonywania tez). To się robi tak:


begin
DBMS_SCHEDULER.create_job (
    job_name        => 'test_full_job_definition',
    job_type        => 'PLSQL_BLOCK',
    job_action      => 'BEGIN DBMS_STATS.gather_schema_stats(''SCOTT''); END;',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'freq=hourly; byminute=0',
    end_date        => NULL,
    enabled         => TRUE,
    comments        => 'Job defined entirely by the CREATE JOB procedure.');
end;



Możesz też po wcześniejszym stworzeniu programu i schedula zrobić sobie joba związanego ze schedulem (więc nie musisz podawać częstotliwości, bo ta jest określona w schedulu do którego job jest podpięty). Dodatkowo nie piszesz kodu który ma zostać wykonany a jedynie nazwę programu który jest przez joba wywoływany (w nim jest przecież kod):
begin
DBMS_SCHEDULER.create_job (
    job_name      => 'test_prog_sched_job_definition',
    program_name  => 'test_plsql_block_prog',
    schedule_name => 'test_hourly_schedule',
    enabled       => TRUE,
    comments      => 'Job defined by an existing program and schedule.');
end;




Możliwości te możesz mieszać. Tutaj np. nie piszę kodu bezpośrednio w jobie tylko kod jest w programie a to program wywołuje z joba, ale np. już częstotliwość podaje w samym jobie:


begin
DBMS_SCHEDULER.create_job (
    job_name        => 'test_prog_job_definition',
    program_name    => 'test_plsql_block_prog',
    start_date      => SYSTIMESTAMP,
    repeat_interval => 'freq=hourly; byminute=0',
    end_date        => NULL,
    enabled         => TRUE,
    comments        => 'Job defined by existing program and inline schedule.');
end;


tudzież w drugą stronę. Podpinam pod schedula (czyli czestotliwość jest w schedulu i nie muszę jej podawać ręcznie, ale już sam kod który ma zostać wykonany piszę bezpośrednio w jobie:


begin
DBMS_SCHEDULER.create_job (
     job_name      => 'test_sched_job_definition',
     schedule_name => 'test_hourly_schedule',
     job_type      => 'PLSQL_BLOCK',
     job_action    => 'BEGIN DBMS_STATS.gather_schema_stats(''SCOTT''); END;',
     enabled       => TRUE,
     comments      => 'Job defined by existing schedule and inline program.');
END;


O a tutaj masz joba który jest podpięty do schedula ale wywołuje skrypt na dysku zamiast kodu pl sql:


begin
DBMS_SCHEDULER.create_job (
     job_name      => 'test_sched_job_definition',
     schedule_name => 'test_hourly_schedule',
     job_type      => 'EXECUTABLE',
     job_action    => 'c:\dupadupa\twojastara.bat',
     enabled       => TRUE,
     comments      => 'Job defined by existing schedule and inline program.');
END;
Konfiguracja i mieszanie jak widzisz dowolne.


Joba można oczywiście skasować:
begin
  DBMS_SCHEDULER.drop_job (job_name => 'test_full_job_definition');
end;