wtorek, 16 grudnia 2014

Odtwarzanie pliku kontrolnego bez kopii w autobackupie

Jeśli zdarzy się tak, że padnie nam baza a nie mieliśmy włączonego autobackupu pliku kontrolnego, możemy posłużyć się poniższą metodą. W moim przypadku padł system, nie miałem wcześniej włączonego autobackupu i zostałem z zawartością FRA. Ponieważ po padzie systemu i instalacji bazy od nowa, musiałem odtworzyć starą bazę na nowej, pojawił się problem z różnymi DBID. DBID (czyli taki unikalny identyfikator bazy) przechowywany jest w pliku kontrolnym, więc ten musiałem odzyskać w pierwszej kolejności. Podczas zwykłych backupów również jest robiony backup pliku kontrolnego, trzeba go będzie tylko wskazać przy odtwarzaniu. Ja znalazłem właściwy po nazwach katalogów (w FRA jest katalog backuppiece a w nim podkatalogi z datami i w nim są malutkie pliki tak po ok 1 MB zawierające właśnie backup pliku kontrolnego). Uruchamiamy RMANa, kładziemy bazkę do NOMOUNTa i wydajemy polecenie:

restore controlfile from 'ścieżka do backupu pliku kontrolnego w FRA';

Plik kontrolny mamy odzyskany. Przechodzimy więc do mounta:

alter database mount;

Musimy teraz zrobić porządek z położeniem plików backupów z których chcemy odzyskiwać bazę. Repo backupów znajduje się w pliku kontrolnym, tak więc mamy tam informacje o starych położeniach backupów. Dajemy więc:

CROSSCHECK BACKUP;
DELETE EXPIRED BACKUP;
CATALOG START WITH 'ŚCIEŻKA DO katalogu z backupami i archivelogami (nadrzędny katalog)';

Pierwsze dwie komendy służą wywaleniu informacji o backupach których fizycznie już nie ma wg. repo. Trzecia powoduje zarejestrowanie nowego położenia backupów i archivelogów. Dalej odtwarzanie przebiega jak zawsze:

RESTORE DATABASE;
RECOVER DATABASE;
ALTER DATABASE OPEN RESETLOGS;

Ostatnia komenda do otwarcie bazy, ale w związku z odtwarzaniem pliku kontrolnego musimy otworzyc bazę z użyciem resetlogsa. Warto pamiętać też o zrobieniu jakiegoś backupu, byśmy w razie czego mieli z czego otwarzać w ramach nowej inkarnacji która powstaje przy resetlogsie ;) Proponowałbym też zadbać o właściwe ustawienie parametru db_recovery_file_dest, bo nowe położenie FRA nie musi pokrywać się ze starym. Tą metodę możemy wykorzystać również przy duplikacji opisanej tutaj: http://andrzejklusiewicz.blogspot.com/2013/01/gotuj-z-oraclem-odtworzenie-bazy-w.html






poniedziałek, 15 grudnia 2014

Kurs Oracle PL/SQL. Funkcje strumieniowe

Istnieje możliwość tworzenia w PL/SQL na których wyniku możemy operować tak jak na tabeli – mam na myśli stosowanie SELECT, warunków WHERE i sortowania. Jest możliwość zastosowania funkcji zwracającej tablicę typu obiektowego, jednak stosowanie takich typów nie należy do wygodnych. Ponadto trzeba będzie poczekać na wynik do czasu aż wygeneruje się cały. Przypuśćmy, że chcemy dostać pierwsze X wierszy jak najszybciej. Reszta może zostać pobrana nieco później. Interesuje nas działanie podobne do wykonania zapytania SELECT na bardzo dużej tabeli w narzędziu takim jak SQL Developer. Stosunkowo szybko (o ile nie zastosowaliśmy np. sortowania) dostaniemy pierwsze 50 wierszy (tylko one zostały pobrane z bazy). Kolejne zostaną zfetchowane dopiero gdy przesuniemy suwak przy wyniku. Aby uzyskać taki efekt, możemy zastosować funkcję strumieniową – pipelined. Wiersze będą zwracane z funkcji jeden po drugim w takim tempie w jakim będą pobierane / generowane. Nie będziemy musieli czekać na wygenerowanie całego wyniku. Moim zdaniem ciekawa funkcjonalność w optymalizacji PL/SQL. Nic nie stoi też na przeszkodzie by użyć funkcji strumieniowych w połączeniu z typem obiektowym.

Zaczniemy od najprostszego przykładu. Stworzyłem funkcję zwracającą kolejne potęgi liczby 2. Funkcja będzie zwracać tablicę elementów typu number element po elemencie. Na wyniku tej funkcji wykorzystamy SELECT.

W pierwszej kolejności tworzę typ tablicowy elementów typu number, widoczny w całym schemacie. Dalej tworzę funkcję która zwróci tyle kolejnych potęg liczby 2 ile podamy przez parametr.

Różnicę w stosunku do zwykłych funkcji zauważyć można w liniach 3, 7 i 9. W linii 3 zauważymy deklarację "PIPELINED", jest ona wymagana jeśli chcemy wykorzystywać funkcje w sposób opisanywcześniej. W linii 7 znajdziemy "pipe row". Oznacza on po prostu zwrot kolejnego elementu z funkcji. W linii 9 znajdziemy klauzulę return która jednak nic nie zwraca... Musi ona być z powodów formalnych. Sam zwrot danych zrealizowaliśmy już wcześniej z użyciem PIPE ROW :)

W liniach 12 i 13 zobaczymy sposób wykorzystania naszej nowej funkcji. Klauzula TABLE umożliwia nam stosowanie SELECT na wyniku funkcji. Oczywiście moglibyśmy tutaj użyć również WHERE czy ORDER BY.


Teraz nieco skomplikujemy sytuację. Funkcja nie będzie zwracała tablicy elementów typu prostego, a tablicę elementów typu rekordowego.

W pierwsze kolejności muszę zdeklarować sam zwracany typu rekordowy. Ponieważ nie mogę go zdeklarować w schemacie, deklaruję go w pakiecie. Przy okazji w tym samym pakiecie deklaruję również typ tablicowy złożony z elementów właśnie utworzonego typu rekordowego. Tutaj wymagane jest pewne wyjaśnienie z moje strony. Czemu w typie rekordowym mam same pola typu varchar2? Nie jest to w żaden sposób wymagane. Po prostu wszystkie typy proste inne niż grupa LOB czy typ LONG są konwertowalne do varchar2, a ja jeszcze nie wymyśliłem zapytania któego użyję :) To sprawia też że ten typ rekordowy będzie wielorazowego użytku na potrzeby ewentualnych innych zapytań.


Dalej tworzę funkcję wykorzystującą ten typ tablicowy. Konstrukcyjnie niewiele tutaj zmian w stosunku do poprzedniej funkcji. Tyma razem jednak przetwarzam wynik zapytania. Może rzucić się w oczy linia 29 z deklaracją pojedynczego elementu do którego wrzucam zaczytany z kursora wiersz. Po co mi on potrzebny jeśli funkcja ma zwracać tablicę? Zwracać będzie tablicę, ale wierszo po wierszu. W linii 35 wywołuję PIPE ROW która nie może przecież zwrócić nam tablicy. Dlatego potrzebuję takiego elementu jako kontenera na kolejne zwracane wiersze.


Kurs administracji Oracle. Tryb Flashback

Tryb flashback umożliwia oglądanie danych w bazie, w takim stanie w jakim były w określonym punkcie w czasie. Stan danych będzie pochodził z przestrzeni UNDO, a to oznacza że dostęp do stanu z przeszłości będzie możliwy tylko wtedy,gdy oryginalne postaci danych nie zostaną nadpisane.

Aby wykorzystać tę funkcjonalność użytkownik musi mieć nadane przez administratora uprawnienia do pakietu dbms_flashback:

grant execute on dbms_flashback to hr;

Z poziomu użytkownika HR odpytuję tabelkę EMPLOYEES wybierając kilka wierszy.


Następnie dokonuję zmiany na tych wierszach i zatwierdzam ją.


Zarówno moja, jak i każda inna sesja będą widziały dane po zmianie:


Następnie komendą

execute dbms_flashback.enable_at_time(to_date('29-11-2015 12:00:00','dd-mm-yyyy
hh24:mi:ss'));

sprawiam, że widzę dane w stanie w jakim były dwie godziny przed zmianami.

I przeglądam dane:


Baza danych dla mojej sesji jest jednak tylko do odczytu. Pozostając w trybie flashback nie mam możliwości dokonywania jakichkolwiek zmian na niej. Aby wyłączyć tryb flashback stosuję polecenie:

execute dbms_flashback.disable;



Kurs Oracle PL/SQL. Ukrywanie implementacji

Oracle udostępnia nam możliwość ukrycia implementacji kodu PLSQL. Czasem chcemy wdrożyć system, ale w taki sposób by nikt niepowołany nie mógł przeglądać jego źródeł.
Możemy tego dokonać w kilku prostych krokach. Najpierw zapisujemy do pliku tekstowego kod programu:


Następnie używamy programu WRAP który służy do zamiany tego kodu na postać zaszyfrowaną:


Dalej logujemy się sqlplusem lub innym klientem i wywołujemy ten zaszyfrowany kod tak jak normalny:


Kodu takiej procedury nie da się przejrzeć:


Natomiast bez problemu można ją wywołać i wszystko będzie działać jak zawsze:



czwartek, 9 stycznia 2014

Klauzula NOCOPY w PL/SQL

Klauzulę NOCOPY możemy stosować przy parametrach OUT oraz IN OUT . Sprawia ona że wartość przekazana przez parametr nie jest kopiowana (jak to się dzieje domyślnie) a przekazywana jest referencja. To oznacza, że przekazywany jest wskaźnik do obszaru pamięci, a nie wartość jako taka. Efekt jest taki, że zarówno procedura z parametrem jak i blok (lub inna procedura czy funkcja) ją wywołujący działają na TYCH SAMYCH danych, bo chodzi o tą samą przestrzeń w pamięci operacyjnej.





Z jednej strony stosowanie klauzuli NOCOPY może nam pomóc – zwłaszcza przy przekazywaniu przez parametr typu OUT dużych wartości np. długich tablic albo dużych obiektów. Z drugiej strony, jeśli np. w procedurze nastąpi jakiś wyjątek, to w naszej przekazanej zmiennej może znaleźć się coś innego niż byśmy się spodziewali. Poniżej przedstawiam przykład takiej sytuacji:





Jak widzimy, w wyniku wywołanego wyjątku, przetwarzanie w procedurze nie dobiegło do końca. W efekcie w zmiennej y bloku wywołującego znalazł się tekst „W trakcie przetwarzania” zamiast „Oryginalny oryginał”

piątek, 3 stycznia 2014

Parametry typu IN, OUT, IN OUT w procedurach i funkcjach PL/SQL

Dla procedur oraz funkcji możemy definiować opcjonalne parametry. Mogą występować w trzech typach:

IN – parametr tylko do odczytu, poprzez który dane zostają przekazane do podprogramu.


OUT – Służy do zwracania wartości z podprogramu. Ma wartość NULL do momentu kiedy zostanie zainicjalizowana.



IN OUT – Połączenie dwóch powyższych typów. Podczas wywoływania programu tym parametrem przekazywane są do niego wartości, a po zakończeniu wykonywania zwracane. Stosuje się go gdy dane wejściowe mają zostać zmienione podczas działania programu.






Podczas deklarowania parametrów dla procedury lub funkcji nie ma sztywnych ograniczeń co do ich ilości oraz kolejności. Parametry mogę zadeklarować na kilka różnych sposobów i poniżej omawiam to na przykładach:

wejsciowy1 – parametr wejścia typu varchar2, nie posiada wartości domyślnej i dlatego przy wywoływaniu podprogramu będę zmuszony ją podać.

wejsciowy2 oraz wejsciowy3 - dwa sposoby zadeklarowania wartości domyślnej dla parametru. Jeśli nie przypiszę żadnej wartości, przypisana zostanie automatycznie wartość występująca po DEFAULT lub znaku przypisania. Podczas wywoływania podprogramu nie muszę podawać wartości do tego parametru.

wejsciowy4 – ponieważ nie określiłem jaki ma to być typ parametru, Oracle domyślnie przyjmuje że jest ot parametr typu IN.

wejsciowy5 – parametr typu wejściowego numerycznego który będę musiał uzupełnić przy wywoływaniu procedury.

wyjsciowy – parametr wyjściowy typu number. Nie mogę określić dla niego wartości domyślnej, ani wartości wejściowej przy wywołaniu programu. Mogę to zrobić jedynie wewnątrz podprogramu.




dwustronny – parametr do którego nie mogę przypisać wartości domyślnej przy wywoływaniu podprogramu. Mogę podać do niego wartość podczas wywoływania podprogramu.


Mogę określać typ parametru, nie mogę natomiast długości. Zamiast więc stosować varchar2(243) muszę zastosować samo varchar2. 

Przykład wzajemnego wywoływania procedur oraz praktycznego przekazywania parametrów.




  1. Tworzę procedurę o nazwie „wypisywacz”, która po otrzymaniu danych w parametrach wejściowych (imię i nazwisko są domyślnie IN) ma wypisać na ekranie powitanie. Ponadto do parametru wyjściowego wzrost ma przypisać wartość 178.




    2. Z bloku anonimowego wywołuję przed momentem stworzoną procedurę podając wartości dla parametrów wejściowych, oraz nazwę zmiennej do której ma zostać przypisana wartość wyjściowa.




    Jak widać, po wywołaniu procedury „wypisywacz” wartość zmiennej do której została przypisana wartość wewnątrz procedury „wypisywacz” uległa zmianie.

    Parametrów wcale nie muszę wypisywać w dokładnie takiej kolejności w jakiej są zdeklarowane w definicji funkcji/procedury. Jedynym warunkiem jest określenie podczas wywoływania podprogramu do jakiej zmiennej przypisuję jaką wartość.