Projektowanie baz danych Bartosz Reichel PG 2011/2012
Zasady zaliczenia Laboratorium 50% Wykład (egzamin/zaliczenie) 50%
Literatura Oracle Database 11g. Programowanie w języku PL/SQL, Michael McLaughlin, Helion 2009 Oracle SQL Recipes A Problem-Solution Approach Oracle Database 11g i SQL. Programowanie; Jason Price, Helion 2009 Książka SQL. Zaawansowane techniki programowania, Joe Celko...
Przypomnienie Jak połączyć się z bazą danych? Czy koniecznie muszę pracować z bazą danych Oracle?
Kilka słó przypomnienia Posługiwanie się narzędziami, co będzie nam potrzebne Funkcje, procedury, PL/SQL Kilka przydatnych elementów
dbms_output Jest to paczka pozwalająca pisać z PL/SQL do bufora (w tym może to być np.. ekran konsoli) UWAGA: bufor jest zwalniany dopiero po skończonym bloku (a sama paczka nie zawiera czegoś w rodzaju flush). Zatem rezultat widoczny jest dopiero po skończonym bloku.
dbms_output.enable Pozwala odblokować możliwość przesyłania danych do bufora. Ważne w szczególności w takich środowiskach jak SQL Developer W przypadku konsoli i np.. SQL* Plus należy włączyć jeszcze opcje wyjścia na konsolę: SET SERVEROUTPUT ON (swoją drogą równoważne z dbms_output.enable(buffer_size => NULL);) dbms_output.enable(buffer_size IN INTEGER DEFAULT 20000);
PROCEDURE DBMS_OUTPUT.GET_LINES (lines OUT DBMS_OUTPUT.CHARARR, numlines IN OUT INTEGER);
dbms_output.disable Odwrotna do poprzedniej funkcji, blokuje wysyłanie danych do bufora
dbms_output.put oraz dbms_output.put_line Pierwsza z nich umieszcza text z parametru funkcji w buforze Druga z nich umieszcza tex z parametru dodając znak końca linii dbms_output.put(a IN VARCHAR2); dbms_output.put_line(a IN VARCHAR2);
Przykład Należy zwrócić uwagę na różnicę pomiędzy odblokowaniem bufora a odblokowaniem możliwości wyświetlania tekstu w konsoli Należy zauważyć (co było wspomniane), że wywołania znajdują się w definicji najprostszego bloku oracle.
dbms_output.new_line
dbms_output.get_line oraz dbms_output.get_lines Pierwsza z nich czyta jedną linie z bufora Druga linie z bufora Procedura może służyć do czytania np.. z pliku lub przeczytania w Java/.NET/... informacji z bufora do jakiejś zmiennej dbms_output.get_lines(lines OUT CHARARR, numlines IN OUT INTEGER);
Czytanie z konsoli (SQL Plus) set verify off; (pokazuje zmienne przed i po zapisie) set define '&';
W SQL Developer Uproszczona dość składnia Wiadomo, jest to rozwiązanie na szybko
Prompt dosłownie!!
A co z wartościami, które się powtarzają? SELECT &&test, &&test FROM dual; SELECT &&test, &&test FROM dual;
Pakiet UTL_FILE Pakiet umożliwiający czytanie zapisywanie do pliku. Daje możliwości na dostęp do pliku bezpośrednio z funkcji/procedur/... do plików co idealnie pasuje do problemów jakie należy rozwiązać na laboratorium (nie jest wymagane GUI ani aplikacja zewnętrzna). Posiada funkcje, które są odpowiednikami znanych funkcji (open, close, read, ) z większości języków takich jak np. C
Zasady bezpieczeństwa Domyślnie zasady nie pozwalają na zapis plików w systemie operacyjnym (ta zasada tyczy się nie tylko UTL_FILE) Ogólne zasady określone w spfile<sid>.ora (Server Parameter File) Znajdują się w $ORACLE_HOME/database (Win) lub $ORACLE_HOME/dbs (Lin)
http://download.oracle.com/docs/cd/b19306_01/appdev.102/b14258/u_file.htm
Skoro mamy te same funkcje to powinny nas obowiązywać te same zasady dysponowania zasobami systemowymi co w każdym innym przypadku!!!
Teoretycznie dokumentacja podaje, że można otwierać pliki zarówno po stronie serwera jak i po stronie klienta. Wiedząc jak działa serwer należy jednak mieć na uwadze, że musi on mieć dostęp do tych plików (Zapytanie jest wykonywane na serwerze). Możliwość wykorzystania spool Jeśli aplikacja ma współdziałać z lokalnymi plikami częściej wykorzystuje się inne rozwiązania.
SPOOL SET NEWPAGE 0 SET SPACE 0 SET LINESIZE 80 SET PAGESIZE 0 SET ECHO OFF SET FEEDBACK OFF SET HEADING OFF SET MARKUP HTML OFF SET ESCAPE \ SPOOL TEST.TXT select 'SELECT SYSDATE FROM DUAL' FROM DUAL; SPOOL OFF SQL> select 'SELECT SYSDATE FROM DUAL' FROM DUAL; SELECT SYSDATE FROM DUAL SQL> SPOOL OFF
Przypomnienie: podstawowe struktury sterujące IF CASE LOOP FOR WHILE
UWAGA Pamiętajmy o wartości NULL! not true prawdziwe dla false i NULL not false dla true i NULL Należy wykorzystać funkcję NVL!
NVL Funkcja z grupy funkcji (np. NVL2) decydujących co zrobić gdy wyrażenie zwróci NULL NVL(Wyrażenie, wartość) W przypadku gdy wyrażenie zwraca NULL funkcja NVL zwraca wartość w przeciwnym przypadku zwraca to co zwróciło wyrażenie.
Instrukcja IF Bloki w oracle (standardowo rozpoczynające się słowem BEGIN i kończące słowem END). Sprawdza warunek złożony z porównania, które musi zwrócić wartość logiczną (NVL, ), zatem może to być też funkcja Wartości mogą zostać skonwertowane niejawnie
IF [NOT] (wyrażenie/wartość) [[AND/OR] THEN Blok [ELSE BLOK] END IF;
Blok ELSIF Możliwość sprawdzania wielu bloków IF (warunek) THEN Blok ELSEIF (warunek) THEN Blok ELSEIF (warunek) THEN Blok ENDIF;
Instrukcja CASE Instrukcja znana z innych języków Brak możliwości przechodzenia między blokami (ogólny brak takiego mechanizmu) Jest to konstrukcja podobna do IF-THENELSIF-THEN-ELSE Na końcu MUSI (wedle dokumentacji) być ELSE!
CASE wersja z jawnym selektorem
CASE z selektorem niejawnym (wyszukiwaniem) Warunek false trzeba podawać jawnie!
Operatory porównania Logiczne (AND, OR, NOT) BETWEEN (AND) IN () IS EMPTY IS NULL IS A SET LIKE SUBMULTISET MEBER OF
Pętla LOOP Znajduje się w bloku BEGIN END Początek słowo LOOP Koniec END LOOP Warunki sterujące wejściem wyjściem z pętli: EXIT, EXIT WHEN, EXIT WHEN NOT, Konstrukcja IF
Pętla FOR Konstrukcja FOR (indeks) IN wartosc_min..wartosc..max LOOP Blok (powtarzany) END LOOP Indeks jest typu całkowitego
Pętla WHILE Konstrukcja: WHILE warunek wejscia LOOP Blok (powtarzany) END LOOP
GOTO Tak istnieje
Rozszerzenie instrukcji sterujących Kursory niejawne Kursory jawne Instrukcje masowe
Kursory Kursory są wynikami zapytania SELECT Pozwalają na przetwarzanie wiersz po wierszu ale też przy użyciu instrukcji masowych (np. FORALL) Są dwa rodzaje kursorów jawne i niejawne
Kursor niejawny Każda instrukcja SQL Z pakietu DML(DQL): (SELECT), INSERT, UPDATE, DELETE Kursory niejawne posiadają atrybuty: %FOUND, %ISOPEN, %NOTFOUND, %ROWCOUNT
Przykład niejawnego kursora wielowierszowego
Kursory jawne Należy zadeklarować w bloku DECLARATION Do programisty należy otwarcie, pobranie danych i zamknięcie kursora (OPEN, FETCH, CLOSE)
OPEN nazwa kursora [parametry, ] FETCH nazwa kursora INTO [zmienne, ] CLOSE nazwa kursora W tym przypadku znaczenie ma atrybut %ISOPEN pozwalający sprawdzić w jakim stanie znajduje się kursor.
Przykład wywołania jawnego
Ten sam przykład z pętlą FOR
Jaką pętlę wybrać? W pętlach prostych musimy otworzyć, pobrać i zamknąć kursor W pętli FOR dzieje się to niejako automatycznie Pętla FOR jest prostsza w użyciu (ale nie można przypisać zmiennych) Jednak pętla LOOP oraz WHILE daje większe możliwości (co może się przydać w bardziej zaawansowanych konstrukcjach).
Przypisanie w pętli FOR
Dynamiczne kursory Poszerzają możliwości (nie każda baza danych SQL udostępniająca kursory posiada takie możliwości) Możliwość modyfikowania zapytania tworzącego kursor
Przykład
Kursor przyjmuje parametry jako zmienne lokalne Może to być koszmarem w późniejszych działaniach na takiej bazie Można przekazywać parametry do kursora poprzez funkcję OPEN
Pakiety Znajduje się w schemacie użytkownika (czyli jest takim samym obiektem jak np. funkcja) Deklaracje dostępne w zasięgu pakietu maja dostęp do tego co zostało zdefiniowane przed natomiast nie mają dostępu do zadeklarowanych po. Paraser języka przechodzi przez kod tylko raz. Trzeba stosować referencje uprzedzające. Należy użytkownikowi nadać uprawnienia EXECUTE
Deklarowanie w bloku
Dostęp do pakietów Zmienne publiczne Typy publiczne Komponenty publiczne (np. funkcje)
Tworzenie pakietu
CREATE [OR REPLACE] PACKAGE nazwa [AUTH {DEFINER CURREN_USER}] IS [PRAGMA SERIALLY_REUSABLE;] [nazwa_zmiennej [CONSTANT] skalarny_typ_danych [:=wartość];] [nazwa_kolekcji [CONSTANT] typ_danych_kolekcji [:=konstruktor];] [nazwa_obiektu [CONSTANT] obiektowy_typ_danych [:=konstruktor];] [TYPE struktura_rekordów IS RECORD ( nazwa_pola1 typ_danych [,nazwa_pola2 typ_danych,, nazwa_polan typ_danych])] IS instrukcja_select; [TYPE kursor_ref IS REF CURSOR [RETURN {wiersz_katalogu struktura_rekordowa}];] [nazwa_wyjątku_użytkownika EXCEPTION; [PRAGMA EXCEPTION_INIT(nazwa_wyjątku_użytkownika, numer_błędu_oracle);]] [FUNCTION nazwa_funkcji [(parametr1 [IN][OUT] [NOCOPY] typ_danych_sql typ_danych_psql [,parametr2 [IN][OUT] [NOCOPY] typ_danych_sql typ_danych_psql )] RETURN {typ_danych_sql typ_danych_psql} [DETERMINISTIC PARALLEL_ENABLED] [PIPELINED] [RESULT_CACHE [RELIES_ON (nazwa_tabeli) ]];]
[PRAGMA RESTRICTED_REFERENCES ({DEFAULT nazwa_funkcji }, Opcja1 [, opcja2, ]);] [PROCEDURE nazwa_procedury [(parametr1 [IN][OUT] [NOCOPY] typ_danych_sql typ_danych_psql [,parametr2 [IN][OUT] [NOCOPY] typ_danych_sql typ_danych_psql )] END nazwa_pakietu; /
NOCOPY W Oracle PL/SQL mamy możliwość dwojakiego przetwarzanie parametrów przez funkcję procedury albo przez referencje albo przez wartość W przypadku przetwarzania przez wartość dokonywana jest kopia parametru. Zmieniając wartość zmiennej wewnątrz procedury/funkcji nie widać zmian po wyjściu z niej W przypadku referencji zmiany są widoczne
Domyślnie IN przez referencję IN OUT przez wartość OUT przez wartość W przypadku IN OUT i OUT procedura/funkcja zwraca wartości do parametrów pod warunkiem poprawnego zakończenia procedury
Za pomocą dyrektywy NOCOPY możemy przekazywać wszystkie parametry do procedury/funkcji przez referencję co może podnieść wydajność w przypadku dużych danych przekazywanych do. UWAGA: wszelkie zmiany są widoczne od razu, nawet jeśli procedura się wykona z błędem. Inaczej: nie ma mowy o ROLLBACK.
PRAGMA Dyrektywa kompilatora, wykonywana na poziomie kompilacji a nie wykonania
SERIALLY_REUSABLE Pozwala na wykorzystanie pakietu tylko podczas trwania wywołania do serwera. Paczka jeśli jest wykorzystywana ponownie inicjalizuje swoje zmienne i część inicializacyjną Pozwala lepiej zarządzać pamięcią (normalnie paczki pozostają aż do końca sesji) Instrukcje trzeba podać zarówno w specyfikacji paczki jak i w ciele paczki
Zmienne w pakietach Do zmiennych zadeklarowanych jako stałe nie można przypisywać wartości. Pakiet nie gwarantuje, że drugi użytkownik zastanie ten sam stan (zmienne współdzielone) Jeśli chce się używać obiektów współdzielonych lepiej jest użyć pakiety ze zdefiniowaną wartością do użytku seryjnego (SERIALLY_REUSABLE) Zmienne jeśli nie są publiczne są nadal dostępne w obrębie pakietu.
Podobne zachowanie można uzyskać przez ALTER PACKAGE shared_variables COMPILE SPECYFICATION;
Typy danych Dostępne z PL/SQL oraz SQL Mogą być dynamiczne i statyczne %ROWTYPE (pseudotyp) %TYPE (pseudotyp) KURSORY
Zmienne Zmienne zadeklarowane w ciele pakietu (BODY) nie są dostępne na zewnątrz
Odwołania do paczki
EXECUTE
Ogólna składnia EXECUTE ( olap_commands text IN VARCHAR2 OUT VARCHAR2); Może być podanych kilka komend oddzielonych znakami ;
%ROWTYPE Zadeklarujmy tablice w Oracle
Daje nam to możliwość związania typu z danym wierszem Strukturę taką możemy zadeklarować również w sekcji DECLARE Możemy wypełnić tą strukturę Struktura tak nie musi być używana tylko i wyłącznie w paczkach (może być w procedurach,...)
%TYPE Podobnie jak poprzednia struktura, z tym że pozwala nam związać zmienną z kolumną col_name table_name.column_name%type; Za pomocą TYPE nazwa_rekordu IS RECORD jesteśmy w stanie zdefiniować sobie dowolną konstrukcję wiersza (fragmentu)
PIPELINED Funkcje opatrzone tym słowem kluczowym, można traktować w przybliżeniu jako tabele Pojawiło się od oracle 9i Można stosować bezpośredni do funkcji Można stosować do funkcji w pakietach
RECORD (? OBJECT) W paczce możemy deklarować typy rekordowe, niestety obiektowych nie...
Przy okazji SHOW ERRORS
Funkcje z PIPELINE mają zastosowanie właśnie w pakietach
Deklaracje wewnętrzne
Kursory w pakietach Kursor współdzielony
Wczytywanie do rekordu Wykorzystanie rekordów Składni OPEN-FOR Silnego typowania Uproszczenie struktury (zawsze można stworzyć widok)
Składnia OPEN-FOR Uruchamia zapytanie związane z kursorem Pozwala wczytać do listy Istnieje wersja parametryzowana OPEN-FORUSING
Zależności pakietów SELECT name FROM dba_dependencies WHERE referenced_name = 'DBMS_OUTPUT' UNION SELECT referenced_name FROM dba_dependencies WHERE name = 'DBMS_OUTPUT';
Kolekcje SQL dane typu SQL PL/SQL dane typu SQL PL/SQL dane typu PL/SQL Uzupełnienie informacji o możliwościach zmiennych, parametrów funkcji/procedur z poprzedniego wykładu.
Dostępne kolekcje w Oracle Tablica VARRAY Tablice asocjacyjne Tabele zagnieżdżone Ogólny podział: listy, tablice
Ograniczenia kolekcji Dostępne typy tylko SQL dla SQL Dla SQL możliwość tworzenia kolekcji tylko 1D Dla PL/SQL możliwość tworzenia pseudo wielowymiarowych kolekcji za pomocą rekordów/obiektów Kolekcje (pseudo)wielowymiarowe można pajpować, dzięki temu można ich użyć z poziomu SQL
Kolekcje oparte o typ VARRAY Indeksowane za pomocą numerów (, n, n+1, ) Ciągłość indeksowania Określona stała liczba elementów
Ogólna definicja TYPE nazwa_typ IS {VARRAY VARYING ARRAY} (rozmiar) OF typ_elementu [NOT NULL] Często nazwa typu zawiera w sobie podciąg VARRAY ułatwiający/porządkujący kod.
Wykorzystanie typów Zmienne w PL/SQL Typy tablicowe
Ex1 - wypełnianie
Inicjalizowanie VARRAY
EXTEND Może być wywołany bez parametru (1 element) Może być podana liczba nowych elementów Sama inicjalizacja kolekcji nie przydziela miejsca na elementy (co może być trochę mylące, patrząc na definicje i mając nawyki c++, java, ) Funkcja pochodzi z tzw. API Collection dostępnego w Oracle.
UWAGA Zwracam uwagę, korzystaliśmy z dwóch możliwości deklaracji kolekcji! Podejście deklarowania typu kolekcji pozwala nam związać ją z pakietem!
NULL nie zalecane Jeśli strumieniujemy nasze dane to wartości NULL stanowią poważny problem. Naturalnie istnieje możliwość obsługi takich wartości jednak jeśli nie mamy ku temu powodów lepiej jest stosować strukturę postaci: CREATE OR REPLACE TYPE INTVARRAY AS VARRAY(5) OF INTEGER NOT NULL
Co nam to daje?
Używanie kolekcji w tabelach Powstaje problem czy taka tabela jest zgodna z zasadami projektowania? Standardowo SQL nie obsługuje rekordów, obiektów, kolekcji W przypadku Oracle można traktować to jako element rozszerzający, będący w zgodzie z normalizacją a pozwalający na większą elastyczność rozwiązań.
Kolumna będąca lista standardowo bez rozszerzeń Oracle była by zapisana jako ciąg kolumn tzn. kolumna_typ1, kolumna_typ2, Takie podejście jest niezgodne z normalizacją Powinno zbudować się kolejną tabelę pomocniczą Lub traktując rozszerzenia oracle zbudować kolekcje będącą wierszem UWAGA: Temat jest dyskusyjny, ma swoich zwolenników jak i przeciwników.
Muszą być typy SQL
Dodawanie
Dane w takiej postaci nie są atrakcyjne Można rzutować DQL <> DML i select
Aby dokonać rzutowania należy utworzyć nowy typ tablicowy (po części zapoznaliśmy się z nim przy strumieniowaniu)
Aktualizacja kolekcji
Update w SQL Wymagana jest aktualizacja całej kolekcji! Można pobrać kolekcje i zmienić jeden element ale może mieć to negatywne skutki jeśli chodzi o wydajność. Aktualizowanie fragmentu kolekcji możliwe jedynie za pomocą PL/SQL
Uzupełnienie - sterowanie W części instrukcji sterujących zabrakło instrukcji masowych, to jest uzupełnienie tej części (TODO - przenieść).
Instrukcje masowe FOR ALL BULK COLLECT INTO
FOR ALL Służy do przesłania z PL/SQL do SQL Składnia FORALL indeks IN dolna_granica..górna_granica wyrażenie_sql; Indeks tylko wewnątrz FORALL i dotyczy kolekcji Instrukcją SQL może być UPDATE, INSERT, DELETE z odwołaniem do kolekcji Pojawia się od wersji 10g
BULK COLLECT INTO Pozwala na przeniesienie z SQL do listy PL/SQL Możliwość sczytywania do rekordów z zapytania (kursor niejawny) Za pomocą jawnych kursorów
Przykład Najpierw tablica z danymi
CONNECT BY Pozwala wybrać dane mające jakiś hierarchiczny związek między sobą PRIOR w konstrukcji: START WITH warunek CONNECT BY [NOCYCLE] warunek, pozwala np.. wylistować strukturę drzewiastą LEVEL pseudokolumna, dla korzenia zwraca 1, potem 2, Klauzula ma znacznie więcej możliwości (możliwe, że do nich wrócimy).
Tablice asocjacyjne (Index-By Tables) Tablice asocjacyjne to zestawy par kluczwartość Klucz jest unikalny Klucz może być liczbą całkowitą lub literałem Definicja TYPE nazwa IS TABLE OF elementy [INDEX BY (BINARY_INTEGER)];
Dostępne indeksy BINARY_INTEGER PLS_INTEGER VARCHAR2(rozmiar) dostępny od oracle 9
Wnioski Mamy możliwość dynamicznego tworzenia zestawów Możemy używać kluczy w postaci liczby jak i napisów (!) wartość może wskazywać na dowolny typ Odpowiedni zestaw metod dla kolekcji pozwalający na sprawdzenie czy np.. element istnieje. UWAGA globalizacja i VARCHAR2
Tablice zagnieżdżone (nested tables)
VARRAY.vs. Nested Tables http://download.oracle.com/docs/cd/b10501_01/appdev.920/a96624 /pls81016_array_versus_nested_table.gif
Przykład Budowanie tablicy asocjacyjnej Sprawdzanie czy element istnieje Iteracja po kluczach
Metody kolekcji (tzw. API Collection) http://download.oracle.com/docs/cd/b19306_01/appdev.102/b14261/collection_method_call.gif
Poznane/niepoznane COUNT LIMIT DELETE PRIOR EXISTS TRIM FIRST LAST NEXT EXTEND
Operatory/funkcje działające na kolekcjach Operatory/funkcje SET (Operand z IS), CARDINALITY, POWERMULTISET Operatory MULTISET Warunkowe MEMBER OF,SUBMULTISET Operand EMPTY
SET Usuwa duplikaty z kolekcji (patrz DISTINCT w SQL) Składnia SET(kolekcja) Jako operand zmienna IS [NOT] A SET
CARDINALITY Zlicza elementy kolekcji Nie sprawdza ich niepowtarzalności Przykład > z SET
POWERMULTISET Pobiera tablice zagnieżdżoną i zwraca tablice zagnieżdżoną W przypadku gdy podany NULL zwraza NULL W przypadku pustej tablicy błąd Elementy tablicy muszą dawać się porównywać poprzez operatory porównania
Operatory MULTISET MULTISET EXCEPT MULTISET INTERSECT MULTISET UNION
MULTISET EXCEPT Usuwa przecięcie się zbiorów Najprostsza składnia kolekcja1 MULTISET EXCEPT kolekcja2 Możliwość pracy z ALL/DISTINCT Przykład >>
MULTISET INTERSECT Część wspólna zbiorów Przykład >>
MULTISET UNION Suma zbiorów (wraz z powtarzającymi się elementami) Przykład >>
Porównywanie kolekcji
MEMBER OF Operand Sprawdza czy należy do kolekcji zmienna MEMBER OF kolekcja
SUBMULTISET Sprawdza czy zbiór jest podzbiorem innego zbioru Składnia: kolekcja SUBMULTISET OF kolekcja Zwraca prawdę jeśli ten sam zbiór z lewej i prawej (każdy zbiór jest swoim podzbiorem patrz teoria cały zbiór jest swoim podzbiorem niewłaściwym ) przykład
EMPTY
Porównywanie kolekcji W sposób prosty pospolite przyrównanie Sprawdzenie czy jest w jakieś kolekcji (IN) PRZYKŁADY >>
TODO Uzupełnienie o kilka funkcji (POWERMULTISET_...)
Blokowanie w Oracle Co możemy zablokować? Po co nam blokowanie? Rodzaje blokowania
Po co? Kontrola spójności danych przy dostępie wielu użytkowników naraz Konkurencja w bazach danych
Ex. Użytkownik 1 dodaje wiersz (np. zarezerwuj hotel) Użytkownik 2 sprawdza czy hotel jest zarezerwowany ( w tym samym czasie ) Użytkownik 2 widzi możliwość rezerwacji Prowadzi to do zamazania informacji o poprzednim użytkowniku lub podwójnej rezerwacji (w zależności od konstrukcji DB)
Rodzaje blokowania Automatyczne Manualne
Blokowanie automatyczne Oracle blokuje automatycznie dane na poziomie wiersza. Minimalizuje to data block contention (np. w przypadku gdyby cała tabela była zablokowana) Możliwe są dwa typy: exclusive lock używany w przypadku zmiany danych. Tego trybu blokada może być użyta tylko raz w danym czasie w stosunku do zasobów. Drugim typem jest share lock, umożliwiającym odczyt zasobów (istnieje możliwość nałożenia wielu tego typu blokad na zasób w tym samym czasie).
data block contention Określa, w przypadku Oracle (można powiedzieć, że jest pewnego rodzaju miarą), jak długo dany blok musi oczekiwać na zakończenie konkurencyjnego zadania pracującego też na tym bloku danych.
Transakcje ACID: Atomowość (Atomic) wszystkie SQL zapytania w obrębie transakcji Spójność (Consistent) przed i po zakończeniu transakcji Izolacja (Isolated) transakcje nie mają na siebie wpływu Trwałość (Durable) zmiany po zatwierdzeniu transakcji są zapisywane nawet w przypadku awarii systemu
Przykład blokowania automatycznego Transakcja 1 Transakcja 2 SELECT (dane 1) SELECT (dane 1) INSERT UPDATE SELECT (dane 2) COMMIT SELECT (dane 1) SELECT (dane 2)
Blokowanie manualne Na poziomie transakcji SET TRANSACTION ISOLATION LEVEL SELECT... FOR UPDATE LOCK TABLE Na poziomie sesji
Poziomy izolacji transakcji (zjawiska występujące) Brudny odczyt (dirt reads) Niepowtarzalny odczyt (Nonrepeatable fuzzy ) Fantomy (Phantom reads/phantoms) Definicje: ANSI/ISO SQL (SQL92)
Brudny odczyt (dirt reads) Dotyczy czytania przez transakcje elementów zapisanych przez inna transakcje, które ni są jeszcze zatwierdzone. Może zdarzyć się, że druga transakcja cofnie (ROLLBACK) zmiany a pierwsza transakcja pozostanie z nieprawidłowymi danymi (dirty)
Niepowtarzalny odczyt (Nonrepeatable fuzzy ) Transakcja pierwsza dokonuje odczytu, transakcja druga dokonuje zmian na odczytanych przez pierwszą (UPDATE/DELETE). Transakcja pierwsza dokonując ponownego odczyty stwierdza, że dane się zmieniły. Nie ma możliwości ponownego odczytania jak na początku (niepowtarzalna).
Fantomy (Phantom reads/phantoms) Transakcja pierwsza dokonuje odczytu, transakcja druga dodaje wiersze (spełniające kryteria wyszukiwania pierwszej) (INSERT). Transakcja pierwsza dokonując ponownego odczyty stwierdza, że danych przybyło. Wiersze, które przybyły nazywane są fantomami.
Poziomy izolacji Poziom izolacji READ UNCOMMITED READ COMMITED (*) REPEATABLE READ SERIALIZABLE (*) Dirty read + - fuzzy Phantoms + + - + + + - (*) - poziomy izolacji obsługiwane przez Oracle, domyślnym poziomem jest READ COMMITED (w SQL SERIALIZABLE, poziom ten jest bardziej czasochłonny)
Ustawianie poziomu izolacji transakcji w Oracle SET TRANSACTION ISOLATION LEVEL POZIOM IZOLACJI
Ex. SET (RC, S) SELECT SELECT INSERT UPDATE COMMIT SELECT SELECT Porównanie dwóch dostępnych poziomów izolacji)
READ ONLY SET TRANSACTION ISOLATION LEVEL READONLY; Pozwala tylko na odczyt danych
SELECT... FOR UPDATE Czasami jest potrzeba zablokowania wierszy podczas czytania Baza danych przy składni SELECT FOR UPDATE nakłada exclusive lock na wiersz Odblokowanie następuje poprzez zawołanie ROLLBACK albo COMMIT Możliwość zawężenie SELECT FOR UPDATE OF
CURSOR kursor1 IS SELECT * FROM tabela1 WHERE (warunek) FOR UPDATE; CURSOR kursor2 IS SELECT pole1, pole2 FROM winterize WHERE (warunek) FOR UPDATE OF pole1;
Ex. TODO (np. z NOWAIT etc.) WHERE CURRENT OF (z przykładem jakby to było ze zwykłym UPDATE i błędem) w kursorze
LOCK TABLE LOCK TABLE table [opcje] IN typ_blokowania MODE [NOWAIT] http://download.oracle.com/docs/cd/b28359_01/server.111/b28286/statements_9015.htm
Dostępne są następujące typy blokowania: EXCLUSIVE (tylko SELECT) SHARE (zabrania konkurencji, zezwala na update) SHARE ROW EXCLUSIVE (zabrania SHARE oraz update) ROW SHARE albo SHARE UPDATE (zabrania na exclusive lock) ROW EXCLUSIVE (jak SHARE ale też zabrania dostać SHARE)
Blokady domyślne SELECT brak blokad INSERT/UPDATE/DELETE - ROW EXCLUSIVE SELECT...FROM...FOR UPDATE NOWAIT ROW EXCLUSIVE
SET TRANSACTION Oracle Database SQL Reference 10g Release 1 (10.1) albo 11g http://download.oracle.com/docs/cd/b28359_01/server.111/b28286/statements_10005.htm
Sesje (TODO) Transakcja SET TRANSACTION ISOLATION LEVEL READ COMMITTED; Sesja ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;
Wykrywanie zakleszczeń (deadlock) Oracle potrafi wykrywać automatycznie zakleszczenia
Ex. INSERT A, B COMMIT Sesja 1 Sesja 2 DELETE A DELETE B DELETE A DELETE B Obie sesje czekają na siebie, Oracle przewidział w to miejsce błąd: ORA-00060: deadlock detected while waiting for resource
Oracle Lock Management services Odwołania/interfejs znajdują się w pakiecie DBMS_LOCK Pozwala sterować dostępem do terminala Synchronizować Nakładać blokady (na poziomie aplikacji)
Poza częścią opisaną znajduje się też w pakiecie funkcja DBMS_LOCK.SLEEP (seconds IN NUMBER); mogąca przydać się przy symulacjach.
Dostępne blokady
i ich wspólne występowanie
Ex. (synchronizacja między sesjami) Tabela z opisem (na pewno coś co pozwoli rozróżnić kiedy został wstawiony wiersz!) 3 sesje Pierwsza nakładająca/zdejmująca blokadę Dwie sesje
Plan zapytania explain plan Plan zapytania dotyczy planu jaki stosuje optymalizator Oracle (można odrobinę generalizować) Tyczy się: SELECT, INSERT, UPDATE, DELETE Plan zapytania można odpytywać pod względem różnych statystyk
Plan zapytania zawiera informacje o: Kolejność odwołań do tabel Rodzaj dostępu (np. indeksy) Rodzaje złączeń (JOIN) Filtry, agregacje,...
W szczegółach informacji mogą znaleźć się informacje o czasie wykonania poszczególnych bloków, czy były wykonane równolegle.
Przeglądanie planu zapytania Tabela planu zapytania Tworzenie tabeli Generowanie planu zapytania
Tabela planu zapytania Powinniśmy sprawdzić czy znajduje się w bazie danych. np. DESCRIBE plan_table;
Tworzenie tabeli planu zapytania W przypadku gdy jej nie ma należy uruchomić skrypt znajdujący się $ORACLE_HOME/RDBMS/ADMIN/UTLXPLA N.SQL W przypadku np. 11g jest to:
create table PLAN_TABLE ( statement_id varchar2(30), plan_id number, timestamp date, remarks varchar2(4000), operation varchar2(30), options varchar2(255), object_node varchar2(128), object_owner varchar2(30), object_name varchar2(30), object_alias varchar2(65), object_instance numeric, object_type varchar2(30), optimizer varchar2(255), search_columns number, id numeric, parent_id numeric, depth numeric, position numeric, cost numeric, cardinality numeric, bytes numeric, other_tag varchar2(255), partition_start varchar2(255), partition_stop varchar2(255), partition_id numeric, other long, distribution varchar2(30), cpu_cost numeric, io_cost numeric, temp_space numeric, access_predicates varchar2(4000), filter_predicates varchar2(4000), projection varchar2(4000), time numeric, qblock_name varchar2(30), other_xml clob );
Ważniejsze komórki planu zapytania statement_id Operation Options object_name object_type id parent_id position cost
Uruchomienie planu zapytania Ogólna składnia EXPLAIN PLAN FOR SQL_Statement Example:
Korzystanie z takiego podejścia było by raczej uciążliwe, mamy w tym przypadku tylko jedno zapytanie. Możemy oznaczyć statement_id EXPLAIN PLAN SET STATEMENT_ID = SID FOR SQL_STAT Możliwa jest też zmiana tabeli planu zapytania poprzez składnie INTO
Wyświetlanie c.d. Mimo wszystko nadal plan zapytania nie jest zbyt czytelny istnieją dwa podejścia: Skrypty Oracle Tworzenie własnych skryptów
Skrypty oracle UTLXPLS.SQL - UTiLity explain Serial plans UTLXPLP.SQL - UTiLity explain Parallel plans Wyświetlają ostatni plan >>> Pokazać pliki (są w notkach)
Tworzenie własnych skryptów Demo Oracle
Uogólnienie formatowanie i automat DBMS_XPLAN.DISPLAY np. SELECT plan_table_output FROM TABLE(DBMS_XPLAN.DISPLAY( 'plan_table', NULL, 'basic'));
Istnieje jeszcze możliwość wyświetlania planu zapytania, które jest przechowywane w kursorze SELECT plan_table_output FROM FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR (NULL, NULL, 'basic'));
Typy formatowania BASIC TYPICAL BASIC + (patrz: dwa typy dostępu ACCESS i FILTER) All Możliwość sterowania/dodawania kolumn np. 'basic +cost'; 'All -cost' Informacje dodatkowe +note
SQL Developer
Ustawienia dodatkowe Możliwość odpalenia planów zapytania od razu SET AUTOTRACE TRACEONLY SET TIMING ON SET AUTOTRACE ON
Testowa baza danych Jedna z dostępnych w Oracle jako przykłady Ułatwiają wykorzystanie do celów testowych.
CREATE TABLE EMP (EMPNO NUMERIC(4) NOT NULL, ENAME VARCHAR(10), JOB VARCHAR(9), MGR NUMERIC(4), HIREDATE DATETIME, SAL NUMERIC(7, 2), COMM NUMERIC(7, 2), DEPTNO NUMERIC(2)); INSERT INTO EMP VALUES (7369, 'SMITH', 'CLERK', 7902, '17-DEC-1980', 800, NULL, 20); INSERT INTO EMP VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '20-FEB-1981', 1600, 300, 30); INSERT INTO EMP VALUES (7521, 'WARD', 'SALESMAN', 7698, '22-FEB-1981', 1250, 500, 30); INSERT INTO EMP VALUES (7566, 'JONES', 'MANAGER', 7839, '2-APR-1981', 2975, NULL, 20); INSERT INTO EMP VALUES (7654, 'MARTIN', 'SALESMAN', 7698, '28-SEP-1981', 1250, 1400, 30); INSERT INTO EMP VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1-MAY-1981', 2850, NULL, 30); INSERT INTO EMP VALUES (7782, 'CLARK', 'MANAGER', 7839, '9-JUN-1981', 2450, NULL, 10); INSERT INTO EMP VALUES (7788, 'SCOTT', 'ANALYST', 7566, '09-DEC-1982', 3000, NULL, 20); INSERT INTO EMP VALUES (7839, 'KING', 'PRESIDENT', NULL, '17-NOV-1981', 5000, NULL, 10); INSERT INTO EMP VALUES (7844, 'TURNER', 'SALESMAN', 7698, '8-SEP-1981', 1500, 0, 30); INSERT INTO EMP VALUES (7876, 'ADAMS', 'CLERK', 7788, '12-JAN-1983', 1100, NULL, 20); INSERT INTO EMP VALUES (7900, 'JAMES', 'CLERK', 7698, '3-DEC-1981', 950, NULL, 30); INSERT INTO EMP VALUES (7902, 'FORD', 'ANALYST', 7566, '3-DEC-1981', 3000, NULL, 20); INSERT INTO EMP VALUES (7934, 'MILLER', 'CLERK', 7782, '23-JAN-1982', 1300, NULL, 10);
CREATE TABLE DEPT (DEPTNO NUMERIC(2), DNAME VARCHAR(14), LOC VARCHAR(13) ); INSERT INTO DEPT VALUES (10, 'ACCOUNTING', 'NEW YORK'); INSERT INTO DEPT VALUES (20, 'RESEARCH', 'DALLAS'); INSERT INTO DEPT VALUES (30, 'SALES', 'CHICAGO'); INSERT INTO DEPT VALUES (40, 'OPERATIONS', 'BOSTON');
CREATE TABLE BONUS (ENAME VARCHAR(10), JOB VARCHAR(9), SAL NUMERIC, COMM NUMERIC); CREATE TABLE SALGRADE (GRADE NUMERIC, LOSAL NUMERIC, HISAL NUMERIC); INSERT INTO SALGRADE VALUES (1, 700, 1200); INSERT INTO SALGRADE VALUES (2, 1201, 1400); INSERT INTO SALGRADE VALUES (3, 1401, 2000); INSERT INTO SALGRADE VALUES (4, 2001, 3000); INSERT INTO SALGRADE VALUES (5, 3001, 9999);
Daty i takie tam... ALTER SESSION SET NLS_DATE_LANGUAGE= 'AMERICAN'; select sysdate, TO_DATE('17-DEC-1980', 'DD-MON-YYYY') from dual; INSERT INTO EMP VALUES (7369, 'SMITH', 'CLERK', 7902, TO_DATE('17-DEC-1980','DD-MON-YYYY'), 800, NULL, 20); - - Lub ustawiając w pełni jeszcze NLS_DATE_FORMAT= 'DD-MON-RR'
Przykłady planów zapytania
Iloczyn kartezjański
Czytanie planu zapytań Można sobie wyobrazić plan zapytań w postaci drzewa MERGE JOIN (1) BUFFER (3) TABLE ACCESS (2) TABLE ACCESS (4)
Tworzenie odbywa się zgodnie z kluczami ID, PARENT_ID Następnie czytamy idąc od najbardziej lewego, wykonane operacje
MERGE JOIN (1) BUFFER (3) TABLE ACCESS (2) TABLE ACCESS (4) Co oznacza, że najpierw została wykonana operacja TA (2), następnie TA(4) po czym została zbuforowana (3) finalnie zostały złączone (4)
Czyli okazuje się (to czego się spodziewaliśmy), że zapytanie w postaci iloczynu kartezjańskiego przeczyta nam w pełni obie tabele i dokona złączenia każdego wiersza z każdym.
Iloczyn kartezjański warunek Pozbyliśmy się buforowania i mamy złączenie HASH JOIN jednak nadal pełen dostęp do tabel
Z JOIN
Wygląda na to, że wszystkie zapytania wyglądają tak samo?!!!!!!!! Czego brakuje? KLUCZE, INDEKSY
OPTYMALIZATOR ZADZIAŁAŁ!!
BEZ OPTYMALIZATORA
Optymalizator Pamiętajmy, że optymalizator nie zawsze musi być obecny! Niektóre bazy mają bardzo prosty optymalizator. Optymalizator nie zawsze musi zadziałać po naszej myśli
Porównanie z MySQL
Polecenie EXPLAIN w MYSQL
* GWIAZDKA!!
TODO Możliwość oceny dodatkowej analizy liczności wierszy
c.d. Plan zapytania optymalizator Przykład analizy bardziej złożonego przykładu Możliwości wpływu na wykonywane zapytanie nie tylko od strony SQL ale i optymalizatora
Przykład Struktura: Tematy Posty Rodzaje postów (np. przylepiony)
Zapytanie do postów Iloczyn kartezjański OUTER JOIN LEFT/RIGHT OUTER JOIN... ON
Możliwe drogi zapytania
Pętle zagnieżdżone SELECT * FROM emp, dept WHERE emp.deptno = dept.deptno;
Złączenie z odwróconym sortowaniem (Sort-merge join) SELECT * FROM emp, dept WHERE emp.deptno = dept.deptno;
Cluster Join SELECT * FROM emp, dept WHERE emp.deptno = dept.deptno;
Hash Join SELECT * FROM emp, dept WHERE emp.deptno = dept.deptno;
Trace Jedna z metod
Przykłady Podpowiedzi/ hintów dla optymalizatora W przykładach LIVE
Błędy optymalizatora Mała zbiór wartości o dużej liczebności w dużym zbiorze wartości o małej liczebności Złączenia tabel o małej liczebności z tabelami o dużej liczebności (raczej nie dotyczy Oracle) Błędy z dystrybucją (>histogram)...
Podsumowanie To mikroskopijny wycinek wiedzy Programy do analizy zapytań (najczęściej komercyjne) Książki z serii SQL Tuning Dodatkowo Tuning na poziomie samego serwera DB
Wyjątki Zasięg Przechwytywanie Deklaracja Rzucanie Deklaracja dodatkowych parametrów (nazwa, numer)
Zasięg wyjątków Błędy kompilacji Te wyjątki pojawiają się w czasie kompilacji, zatem są wychwycone już w czasie tworzenia aplikacji. (Najczęściej brak średnika) Błędy czasu wykonania Wyjątki tego typu powstają podczas wykonania i mogą zależeć od wielu czynników, mogą też wystąpić w wielu sekcji PL/SQL. Zostaną omówione dalej.
Możliwość przechwycenia wyjątku w zależności od jego wystąpienia DECLARE -- Sekcja deklaracji. BEGIN......... -- Sekcja wykonawcza... EXCEPTION -- Sekcja obsługi wyjątków END:
Sekcja deklaracji Przechwycenie możliwe na zewnątrz Sekcja wykonawcza Przekazana do lokalnej sekcji obsługi wyjątków Możliwość obsługi w sekcji obsługi wyjątków Jeśli nie są obsłużone przekazywane są dalej Sekcja obsługi wyjątku Przechwycenie możliwe na zewnątrz
Konstrukcja sekcji przechwycenia i wywołania wyjątku DECLARE. E EXCEPTION; BEGIN. RAISE E; EXCEPTION WHEN (nazwa_wyjatku) THEN. END;
Nazwy wyjątków SQLCODE wyjątki zdefiniowane przez Oracle, zwraca opis wyjątku SQLERRM zwraca opis w zależności od parametru, może zwracać opis spoza definicji Oracle Możliwość definicji wyjątków własnych
Kilka wyjątków predefiniowanych ACCESS_INTO_NULL CURSOR_ALREADY_OPEN VALUE_ERROR ZERO_DIVIDE Więcej w dokumentacji
Przykłady
Błąd w sekcji wykonania DECLARE L1 INTEGER := 2; L2 VARCHAR(2) := 0; BEGIN L1 := L1/L2; EXCEPTION WHEN ZERO_DIVIDE THEN DBMS_OUTPUT.PUT_LINE('Blad dzielenia' SQLCODE); END; /
Funkcje błędów DECLARE code NUMBER; errm VARCHAR2(200); BEGIN NULL; code := SQLCODE; errm := SQLERRM; dbms_output.put_line(code ' - ' errm); END; /
Wywołanie wyjątku bez obsługi w bloku BEGIN RAISE ACCESS_INTO_NULL; END; /
BEGIN RAISE ACCESS_INTO_NULL; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie dowolnego wyjatku'); END; /
BEGIN RAISE ACCESS_INTO_NULL; EXCEPTION WHEN ACCESS_INTO_NULL THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku ACCESS_INTO_NULL'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie dowolnego wyjatku'); END; /
Wyjątek przechwycony w bloku zewnętrznym BEGIN DECLARE V INTEGER; BEGIN SELECT 1 INTO V FROM DUAL WHERE 1 <> 1; EXCEPTION WHEN ACCESS_INTO_NULL THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku ACCESS_INTO_NULL'); END; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie dowolnego wyjatku'); END; /
Błąd w sekcji obsługi wyjątku BEGIN DECLARE V INTEGER; E EXCEPTION; BEGIN RAISE E; EXCEPTION WHEN ACCESS_INTO_NULL THEN SELECT 1 INTO V FROM DUAL WHERE 1 <> 1; DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku ACCESS_INTO_NULL'); END; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie dowolnego wyjatku'); END; /
cd BEGIN DECLARE V INTEGER; E EXCEPTION; BEGIN RAISE E; EXCEPTION WHEN ACCESS_INTO_NULL THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku ACCESS_INTO_NULL'); SELECT 1 INTO V FROM DUAL WHERE 1 <> 1; - - zamienione miejscami! END; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie dowolnego wyjatku'); END; /
Wyjątek w sekcji deklaracji BEGIN DECLARE V VARCHAR(1) := 'AB'; BEGIN NULL; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku wewnatrz'); END; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku na zewnatrz'); END; /
Własne wyjątki Mamy możliwość deklarowania poprzez EXCEPTION (w pewien sposób w obrębie deklaracji), ograniczone możliwości komentarzy... PRAGMA EXCEPTION_INIT pozwala o komentować poprzedni wyjątek i nadać mu numer RAISE_APPLICATION_ERROR dynamiczny wyjątek
DECLARE moj EXCEPTION; BEGIN RAISE moj; EXCEPTION WHEN moj THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku moj'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku innego'); END; /
EXCEPTION_INIT Konstrukcja PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number); np. dla bledu ORA-06502 numeric or value error będzie to -6502 ale może być to błąd np. 60 (dedlock detect) nie majacy odpowiednika Pozwala to zdefiniować błąd który istnieje w oracle a nie ma predefinowanego typu
DECLARE moj EXCEPTION; PRAGMA EXCEPTION_INIT(moj, -60); BEGIN RAISE moj; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku: ' SQLERRM); END; /
RAISE_APPLICATION_ERROR Konstrukcja raise_application_error(error_number, message[, {TRUE FALSE}]); error_number - wartość z przedziału -20000.. -20999 Komunikat może mieć 2048 bajtów Opcjonalny parametr pozwala albo na umieszczanie albo nie błędów na stosie poprzednich wywołań
BEGIN RAISE_APPLICATION_ERROR(-20000, 'Jakis blad'); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku: ' SQLERRM); END; /
DECLARE jakis EXCEPTION; PRAGMA EXCEPTION_INIT(jakis, -20000); BEGIN RAISE_APPLICATION_ERROR(-20000, 'Jakis blad'); EXCEPTION WHEN jakis THEN DBMS_OUTPUT.PUT_LINE('Zlapanie jakiegos: ' SQLERRM); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Zlapanie wyjatku: ' SQLERRM); END; /
Ponowne wymuszenie DECLARE e EXCEPTION; BEGIN... BEGIN... RAISE e; EXCEPTION WHEN e THEN RAISE; -- tu nastąpi ponowne wywolanie watku (sprawdzic linijki kodu, komentarz) END; EXCEPTION WHEN e THEN... END;
Nie ma opcji wyskoczenia z wyjątku!! ( i dobrze) DECLARE E EXCEPTION; BEGIN RAISE E; <<etykieta_goto>> DBMS_OUTPUT.PUT_LINE('Za etykieta'); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Wyjatek'); GOTO etykieta_goto; END;
Formatowanie błędów Możliwość formatowania wyjątków DBMS_UTILITY.FORMAT_ERROR_STACK DBMS_UTILITY.FORMAT_CALL_STACK
DECLARE E EXCEPTION; BEGIN RAISE E; EXCEPTION WHEN OTHERS THEN -- UWAGA, funkcja PUT_LINE ma ograniczenia, stack moze zwrocic wiecej znakow! DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK); END;
Pola LOB, etc. Large Objects LOB BLOB CLOB NCLOB Zabezpieczenia (od 11g)
LOB znakowe Maksymalny rozmiar (128 Tb), związany z wielkością bloku (tak więc domyślnie może być mniejszy) Typ CLOB jest typem obiektowym, a zatem wymaga operacji standardowych dla takich typów w Oracle (istnieje funkcja empty_clob() - a dokładniej jest to konstruktor)
Możliwe stany obiektu clob_null CLOB; clob_pusty CLOB := empty_clob(); clob_dane CLOB := 'TEKST';
Ograniczenia na rozmiar Mimo możliwości przechowywania bardzo dużych danych w polach CLOB(itp.) narzucone są ograniczenia ze strony funkcji konwertujących i tak w SQL nie można przekonwertować więcej niż 4000 znaków a w PL/SQL 32767 znaków. Aby móc przechowywać większe ilości danych należy używać lokalizatora
Tworzenie i zarządzanie dużymi obiektami INSERT INTO tabela (pole_clob) VALUES (empty_clob()) RETURNING pole_clob INTO zmienna_clob Następnie można, mając lokalizator w zmienna_clob, dodać dane to wybranego pola. Podobnie realizuje się to w przypadku UPDATE
LOB w przypadku PL/SQL W tej sytuacji powinniśmy mieć utworzoną strukturę na poziomie bazy danych ORACLE Można tego dokonać za pomocą CREATE DIRECTORY
Tablica z danymi
Pakiet DBMS_LOB Obsługa pól LOB, plików,...
Przy takim podejściu mamy duże ograniczenia wynikające z wielkości zapytania SQL'owego Należy zastosować rozwiązania bazujące na pobraniu identyfikatora danych, któe chcemy wstawić.