POSTGRESQL (Postgres) http://www.postgresql.org/docs/9.0/static/index.html http://www.postgresql.org/docs/9.1/static/index.html PostgreSQL obiektowo-relacyjny SZBD oparty na Postgresie rozwijanym w University of California at Berkeley, Computer Science Department. POSTGRES pierwszy wprowadził wiele konstrukcji, które potem zostały wprowadzone do innych komercyjnych systemów. PostgreSQL jest potomkiem oryginalnego, otwartego kodu opracowanego w Uniwersytecie w Berkeley. W wielu miejscach podobny do Oracle z PL/SQL. Uważany za wzorcowy system. W dokumentacji częste porównania ze Standardem SQL. psql standardowy interaktywny program kliencki PostgreSQL: $ psql mydb \q - wyjście z psql 1
Rozszerzenia proceduralne SQL Standard SQL/PSM (SQL/Persistent Stored Modules) Microsoft, Sybase TransactSQL Oracle PL/SQL DB2 SQL/PL PostgreSQL PL/pgSQL, PL/PSM MySQL MySQL SQL/PSM 2
Warto zwrócić uwagę w PostgreSQL v Open Source v Reguły v Typy złożone: enum, array, wierszowy, rekordowy (tworzony przy użyciu CREATE TYPE) v Wzorce przy tworzeniu bazy danych v Definiowanie zdarzeń v Składowanie danych metodą TOAST 3
Klaster, baza danych, schemat Klaster zbiór baz danych zarządzany przez pojedynczą instancję serwera PostgreSQL. Baza danych (w standardzie katalog) składa się ze schematów. CREATE SCHEMA myschema; database.schema.table DROP SCHEMA myschema [CASCADE]; CREATE SCHEMA schemaname AUTHORIZATION username; -- utworzenie schematu i ustalenie właściciela schematu Dla każdej bd automatycznie tworzony jest domyślny schemat public SET search_path TO myschema; -- bieżący schemat 4
SQL SELECT version(); SELECT current_date; SELECT random(); SELECT * FROM Osoby ORDER BY nazwisko LIMIT 5; -- wyświetlone 5 wierszy SELECT * FROM Osoby ORDER BY nazwisko LIMIT 3 OFFSET 3; -- wyświetlone 3 wiersze poczynając od 4 Kolejność ewaluacji podwyrażeń nie jest zdefiniowana (optymalizator może sam sobie wybrać kolejność). 5
Tworzenie tabeli CREATE TABLE Cities ( name varchar(80) PRIMARY KEY, location point); CREATE TABLE Weather ( city varchar(80) REFERENCES Cities(name), temp_lo int, temp_hi int, prcp real, date date); Point typ danych specyficzny dla PostgreSQL. 6
SERIAL, DEFAULT CREATE TABLE Products ( product_no SERIAL PRIMARY KEY, name text, price numeric DEFAULT 9.99, data timestamp DEFAULT now() ); SERIAL - generowanie jednoznacznego numeru (realizowane wewnętrznie przez sekwencję) Text = Varchar = Character Varying (do ok. 1GB) 7
Sekwencje CREATE SEQUENCE numer START 101; SELECT nextval('numer'); nextval --------- 101 currval('numer') W Oracle podobnie ale jest używana notacja obiektowa numer.nextval, numer.currval. 8
Funkcje warunkowe CASE WHEN condition THEN result [WHEN...] [ELSE result] END COALESCE(value [,...]) NULLIF(value1, value2) - if value1=value2 then null GREATEST(value [,...]) LEAST(value [,...]) 9
Określanie (konwersja) typu Specyfikacja typu wartości: SELECT text 'Origin' AS "label", point '(0,0)' AS "value"; label value ------------------- Origin (0,0) (1 row) lub CAST('2.2' AS REAL); 10
Systemowe kolumny tabeli v v v v OID identyfikator obiektowy wiersza dla tabel (obiektowych) tworzonych z opcją WITH OIDS tableoid identyfikator tabeli; użyteczne przy hierarchiach tabel xmin id transakcji wstawiającej/aktualizującej wiersz cmin id modyfikującej instrukcji w ramach transakcji v xmax - id transakcji usuwającej wiersz lub 0 v cmax id instrukcji usuwającej lub 0 v ctid fizyczne miejsce wiersza (aktualne dopóki wiersz nie zmieni położenia w pliku). 11
ALTER TABLE ALTER TABLE products ADD COLUMN description text CHECK (description <> ''); ALTER TABLE products DROP COLUMN description; ALTER TABLE products DROP COLUMN description CASCADE; -- usunięcie kolumny razem z więzami klucza obcego ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups; ALTER TABLE products ALTER COLUMN product_no SET NOT NULL; -- dodanie więzów NOT NULL ALTER TABLE products ALTER COLUMN price SET DEFAULT 7; ALTER TABLE products DROP CONSTRAINT some_name; ALTER TABLE prods ALTER COLUMN price TYPE numeric(10,2); ALTER TABLE prods RENAME COLUMN prod_no TO prod_numb; ALTER TABLE products RENAME TO items; 12
Instrukcje SQL INSERT INTO Weather VALUES ('San Francisco', 46, 50, 0.25, '1994-11-27'); INSERT INTO Cities VALUES ('San Francisco', '(-194.0, 53.0)'); COPY Weather FROM '/home/user/weather.txt'; SELECT city, (temp_hi+temp_lo)/2 AS temp_avg, date FROM Weather; SELECT * FROM Weather INNER JOIN Cities ON (Weather.city = Cities.name); INSERT INTO Products (product_no, name, price) VALUES (1, 'Cheese', 9.99), (2, 'Bread', 1.99), (3, 'Milk', 2.99); 13
DISTINCT ON SELECT DISTINCT ON(deptno) deptno, ename FROM Emp; Wszystkie wiersze z tą samą wartością deptno są uważane jako duplikaty. Z tego zbioru jest wybierany jeden reprezentant. Nie występuje w Standardzie. SELECT DISTINCT ON (expression [, expression...]) 14
Operatory zbiorowe query1 UNION [ALL] query2 query1 INTERSECT [ALL] query2 query1 EXCEPT [ALL] query2 ALL bez eliminacji duplikatów 15
Akcje referencyjne RESTRICT, NO ACTION zapobiega usunięciu wiersza powiązanego więzami klucza obcego. - NO ACTION sprawdzanie więzów przełożone na koniec transakcji, - RESTRICT sprawdzanie natychmiast. CASCADE usuń również powiązane wiersze. SET NULL, SET DEFAULT (ale jeśli wartość domyślna nie spełnia warunku klucza obcego, cała operacja usunięcia nie powiedzie się). 16
Rozszerzalność SQL v v v v Typy danych Funkcje Reguły Wyzwalacze 17
Typy danych v v v v bazowe w SQL (w tym boolean) dziedziny - typ bazowy z więzami spójności, tworzone przez CREATE DOMAIN złożone w tym CREATE TYPE pseudo-typy - nie mogą być typami danych kolumn w tabeli ani atrybutów typów złożonych; możliwe jako typy argumentów i wyników funkcji np. any - dowolny typ danych, record - dowolny typ wierszowy polimorficzne - pseudotypy: anyelement, anyarray, anyenum. Funkcje, które je używają, nazywają się polimorficzne. 18
Typy enumeracyjne CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy'); CREATE TABLE Person ( name text, current_mood mood ); INSERT INTO Person VALUES ('Moe', 'happy'); SELECT * FROM Person WHERE current_mood = 'happy'; name current_mood ------+-------------- Moe happy (1 row) Uporządkowanie wartości zgodne z kolejnością w definicji typu 19
Typy tablicowe (array) CREATE TABLE Sal_emp ( Name text, Pay_by_quarter integer[], Schedule text[][] ); Również składnia ze Standardu (długości wektorów nie są sprawdzane): Pay_by_quarter integer ARRAY[4], 20
Typy rekordowe CREATE TYPE inventory_item AS ( name text, supplier_id integer, price numeric ); CREATE TABLE on_hand ( item inventory_item, count integer ); INSERT INTO on_hand VALUES (ROW('fuzzy dice', 42, 1.9), 100); Inny zapis konstruktora ROW: ' (''fuzzy dice'', 42, 1.99) ' W typie rekordowym nie ma więzów spójności (na razie). 21
Konstruktor rekordu - ROW SELECT ROW(1,2.5,'this is a test'); SELECT ROW(T.f1,T.f2, 42) FROM T; 22
Typ wierszowy dla tabeli CREATE TABLE Inventory_item ( name text, supplier_id integer REFERENCES suppliers, price numeric CHECK (price > 0) ); Automatycznie jest tworzony typ rekordowy odpowiadający wierszom tej tabeli o tej samej nazwie Inventory_item W typie rekordowym nie są brane pod uwagę więzy spójności. 23
CREATE DOMAIN CREATE DOMAIN US_postal_code AS TEXT CHECK( VALUE ~ '^\\d{5}$' OR VALUE ~ '^\\d{5}-\\d{4}$' ); CREATE TABLE US_snail_addy ( address_id SERIAL PRIMARY KEY, street1 TEXT NOT NULL, street2 TEXT, street3 TEXT, city TEXT NOT NULL, postal US_postal_code NOT NULL); 24
Funkcje SQL -- Ciąg instrukcji SQL. -- Ostatnia instrukcja zwraca rezultat funkcji - musi być SELECT, chyba, że typ funkcji jest określony jako void (wtedy jest procedurą). -- Ciało funkcji w postaci napisu (string) z separatorami albo ' albo $<znacznik>$ -- Nie można używać instrukcji dotyczących transakcji. CREATE FUNCTION clean_emp() RETURNS void AS 'DELETE FROM emp WHERE salary < 0; ' LANGUAGE SQL; SELECT clean_emp(); clean_emp ------------- (1 row) 25
Przykłady funkcji CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$ UPDATE Bank SET balance = balance - $2 WHERE accountno = $1; SELECT balance FROM Bank WHERE accountno = $1; $$ LANGUAGE SQL; Parametry funkcji: $1, $2, - mogą być typu wierszowego CREATE FUNCTION double_salary (Emp) RETURNS numeric AS $$ SELECT $1.salary * 2 AS salary; $$ LANGUAGE SQL; SELECT ename, double_salary(emp.*) FROM Emp; 26
Przykład Funkcja typu wierszowego: CREATE FUNCTION new_emp(text) RETURNS Emp AS $$ SELECT $1 AS name, 1000.0 AS salary; $$ LANGUAGE SQL; SELECT (new_emp('kowalski')).name; -- konieczne nawiasy name ------------ Kowalski 27
Kategorie stabilności funkcji informacja dla optymalizatora v v v v Zmienna (volatile) każde wywołanie może zwracać inną wartość, funkcja może zmienić stan bazy danych. Nie poddaje się optymalizacji. Stabilna (stable) - każde wywołanie dla tych samych argumentów zwraca tę samą wartość w ramach wykonania aktualnej instrukcji SQL, funkcja nie zmienia stanu bazy danych. Niezmienna (immutable) - każde wywołanie dla tych samych argumentów zwraca zawsze tę samą wartość, funkcja nie zmienia stanu bazy danych. W CREATE FUNCTION określone przez słowa kluczowe: IMMUTABLE STABLE VOLATILE 28
Reguły Query rewrite rule system reguły przekształcania zapytań działają po zbudowaniu drzewa zapytania przez parser przed skierowaniem drzewa zapytania do optymalizatora. Podobne do wyzwalaczy. Np. typ SERIAL jest realizowany przy pomocy sekwencji. Użycie perspektywy jest realizowane wewnętrznie za pomocą tabeli i reguły np. CREATE VIEW Myview AS SELECT * FROM Mytab; Realizowane jako: CREATE TABLE Myview (te same kolumny jak w mytab); CREATE RULE "_RETURN" AS ON SELECT TO Myview DO INSTEAD SELECT * FROM Mytab; 29
Składnia reguły CREATE RULE name AS ON event TO object DO [ ALSO INSTEAD ] { NOTHING command (command;... ) } - w przypadku event=select tylko jedno command Przykład CREATE RULE MyTab_ins_protect AS ON INSERT TO MyTab DO INSTEAD NOTHING; Aby zrealizować modyfikację danych poprzez perspektywę, trzeba dla niej napisać odpowiednia regułę. 30
PL/pgSQL Proceduralny język do zapisu funkcji, wyzwalaczy. Kod składowany i wykonywany po stronie serwera bazy danych zmniejsza ruch w sieci między klientem a serwerem. Funkcje mogą być typu void oraz mieć parametry wyjściowe (czyli mieć charakter procedur). Blok: [ <<label>> ] [ DECLARE deklaracje ] BEGIN instrukcje EXCEPTION WHEN warunek THEN instrukcje_obsługi_wyjątków END [label] 31
Przykład funkcji w PL/pgSQL CREATE FUNCTION somefunc() RETURNS integer AS $$ << outerblock >> DECLARE quantity integer := 30; BEGIN RAISE NOTICE 'Quantity here is %', quantity; -- Prints 30 quantity := 50; DECLARE quantity integer := 80; BEGIN RAISE NOTICE 'Quantity here is', quantity; -- Prints 80 RAISE NOTICE 'Outer quantity is', outerblock.quantity; -- Prints 50 END; RAISE NOTICE 'Quantity here is %', quantity; -- Prints 50 RETURN quantity; END outerblock; $$ LANGUAGE plpgsql; 32
Aliasy dla parametrów funkcji CREATE FUNCTION sales_tax(subtotal real) RETURNS real AS $$ BEGIN RETURN subtotal * 0.06; END; $$ LANGUAGE plpgsql; CREATE FUNCTION sum_n_product( x int, y int, OUT sum int, OUT prod int) $$ BEGIN sum := x + y; prod := x * y; END;$$ LANGUAGE plpgsql; AS 33
Klauzula INTO SELECT select_expressions INTO [STRICT] target FROM...; INSERT... RETURNING expressions INTO [STRICT] target; UPDATE... RETURNING expressions INTO [STRICT] target; DELETE... RETURNING expressions INTO [STRICT] target; STRICT: zgłaszane są wyjątki NO_DATA_FOUND i TOO_MANY_ROWS; bez STRICT: wynikiem pierwszy wiersz lub NULLe. BEGIN SELECT * INTO STRICT myrec FROM Emp WHERE ename = x; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE EXCEPTION 'employee % not found', x; WHEN TOO_MANY_ROWS THEN RAISE EXCEPTION 'employee % not unique', x; END; 34
PERFORM Gdy funkcja wywoływana w kodzie ma nie zwracać wartości: PERFORM create_mv('cs_session_page_requests_mv', my_query); 35
Dynamiczny SQL EXECUTE command-string [ INTO [STRICT] target ]; command-string napis instrukcji do wykonania dynamicznie target zmienna rekordowa, wierszowa lub lista zmiennych 36
Diagnostyka 1. Liczba wierszy zwróconych przez ostatnią instrukcję: GET DIAGNOSTICS integer_var = ROW_COUNT; 2. Zmienna FOUND czy ostania instrukcja (w tym PERFORM) zwróciła co najmniej jeden wiersz: SELECT * INTO myrec FROM Emp WHERE empname = myname; IF NOT FOUND THEN RAISE EXCEPTION 'employee % not found', myname; END IF; Instrukcja NULL i podnoszenie wyjątku: BEGIN y := x / 0; EXCEPTION WHEN division_by_zero THEN NULL; -- nic nie rób END; 37
Zmienne SQLSTATE i SQLERRM Wewnątrz sekcji wyjątków są dostępne informacje o zaistniałym błędzie: SQLSTATE numer błędu, SQLERRM komunikat o błędzie. 38
Instrukcja RAISE RAISE level 'format' [, expression [,...]]; level = DEBUG, LOG, INFO, NOTICE, WARNING, EXCEPTION RAISE NOTICE 'Calling cs_create_job(%)', v_job_id; 39
Gdy typem wyniku funkcji jest SETOF sometype Budowa zbioru wyników dla funkcji za pomocą RETURN NEXT expression,.., expression; -- zwraca wiersz RETURN QUERY query; -- zwraca zbiór wierszy Zakończenie za pomocą RETURN bez podawania wartości. Początek przykładu: CREATE TABLE Foo ( fooid INT, foosubid INT, fooname TEXT); INSERT INTO Foo VALUES (1, 2, 'three'); INSERT INTO Foo VALUES (4, 5, 'six'); 40
CREATE OR REPLACE FUNCTION get() RETURNS SETOF Foo AS $BODY$ DECLARE r Foo%rowtype; BEGIN FOR r IN SELECT * FROM Foo WHERE fooid > 0 LOOP RETURN NEXT r; -- przekaż aktualny wiersz END LOOP; RETURN; -- koniec wykonywania funkcji END $BODY$ LANGUAGE 'plpgsql'; SELECT * FROM get(); 41
Wyzwalacze Definiowane przez bezparametrową funkcję typu trigger (w nagłówku RETURNS trigger). Rodzaje: [wierszowe dla instrukcji] [BEFORE AFTER] [INSERT DELETE UPDATE]. Funkcje wyzwalaczy dla instrukcji powinny zwracać (przez RETURN) NULL. Funkcje wyzwalaczy wierszowych BEFORE zwracają: NULL oznacza nie wykonywać operacji; przekazywany przez funkcję wiersz (przy INSERT, UPDATE) - zostaje wstawiony do tabeli a przy DELETE - usunięty. Jeśli kilka wyzwalaczy: wyjście z poprzedniego jest przekazywane na wejście następnego (w kolejności alfabetycznej nazw). 42
Funkcje wyzwalaczy w PL/pgSQL NEW, OLD - dane typu RECORD Przykład: CREATE TABLE Emp ( empname text, salary integer, last_date timestamp, last_user text); CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON Emp FOR EACH ROW EXECUTE PROCEDURE emp_stamp(); 43
CREATE FUNCTION emp_stamp() RETURNS trigger AS $$ BEGIN -- Sprawdzenie czy podano nazwisko i zarobki IF NEW.empname IS NULL THEN RAISE EXCEPTION 'empname cannot be null'; END IF; IF NEW.salary IS NULL THEN RAISE EXCEPTION '% cannot have null salary', NEW.empname; END IF; IF NEW.salary < 0 THEN RAISE EXCEPTION '% has negative salary', NEW.empname; END IF; -- Zapisz kto ustalił zarobki pracownika i kiedy NEW.last_date := current_timestamp; NEW.last_user := current_user; RETURN NEW; END; $$ LANGUAGE plpgsql ; 44
Dziedziczenie na poziomie tabel CREATE TABLE Cities( name text, population real, altitude int); (nie typów danych) CREATE TABLE Capitals(state char(2)) INHERITS (Cities); SELECT name, altitude FROM Cities WHERE altitude > 500; SELECT name, altitude FROM ONLY Capitals WHERE altitude > 500; ONLY może być użyte w instrukcjach SELECT, UPDATE i DELETE 45
Partycjonowanie przez dziedziczenie 1. Utwórz tabelę nadrzędną, z której partycje będą dziedziczyć. Ta tabela zwykle nie ma danych. 2. Utwórz tabele podrzędne do przechowywania partycji. 3. Utwórz warunki CHECK określające, jakie dane mają należeć do danej partycji w oparciu o wartości w kolumnie klucza partycji (rozłączne). 4. Utwórz indeksy na partycjach w tym ewentualnie na kolumnach klucza w każdej partycji (ewentualnie UNIQUE). 5. Napisz wyzwalacz dla tabeli nadrzędnej wstawiania danych do odpowiedniej partycji. 6. Ustaw parametr konfiguracyjny constraint_exclusion na on aby optymalizator skorzystał z warunków rozłączności. 46
Przykład CREATE TABLE Klienci( Id_klienta int, Nazwisko Text, Adres Text, Region Text); CREATE TABLE KliencizMazowsza( CHECK (Region = Mazowsze )) INHERITS (Klienci); CREATE INDEX Nazw_Index ON KliencizMazowsza(Nazwisko)... CREATE TRIGGER insert_klienci_trigger BEFORE INSERT ON Klienci FOR EACH ROW <funkcja wstawiająca klienta do odpowiedniej partycji> 47
Geometryczne typy danych 48
Tworzenie obiektów typu XML Zgodnie ze standardem: XMLPARSE (DOCUMENT '<?xml version="1.0"?> <book><title>manual</title><chapter>...</chapter></book>') XMLPARSE (CONTENT 'abc<foo>bar</foo><bar>foo</bar>') W drugim przypadku może być więcej niż jeden element główny. Dodatkowo (tak jak dla innych typów) określenie typu: xml '<foo>bar</foo>' lub '<foo>bar</foo>'::xml Nie ma walidacji względem DTD lub XML Schema. W drugą stronę konstrukcja standardu: XMLSERIALIZE ( { DOCUMENT CONTENT } value AS type ) Dodatkowo: cast 49
Funkcja xmlelement SELECT xmlelement(name foo, xmlattributes('xyz' as bar), xmlelement(name abc), xmlcomment('test'), xmlelement(name xyz)); xmlelement ---------------------------------------------------------- <foo bar="xyz"><abc/><!--test--><xyz/></foo> 50
Wyszukiwanie w dokumencie XML xpath(xpath, xml) -- wynikiem tablica wartości XML wskazywanych przez ścieżkę xpath 51
Mapowanie tabel na XML tabletoxml(tablename) <tablename> <row> <columnname1>data</columnname1> <columnname2>data</columnname2> </row> <row>... </row>... </tablename> Podobnie querytoxml, cursortoxml. 52
Funkcje tabelowe CREATE TABLE Foo (fooid int, foosubid int, fooname text); CREATE FUNCTION getfoo(int) RETURNS SETOF Foo AS $$ SELECT * FROM Foo WHERE fooid = $1; $$ LANGUAGE SQL; SELECT * FROM getfoo(1) AS t1; SELECT * FROM Foo WHERE foosubid IN(SELECT foosubid FROM getfoo(foo.fooid) z WHERE z.fooid = Foo.fooid); CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1); SELECT * FROM vw_getfoo; 53
Tablice wielowymiarowe ARRAY SELECT ARRAY[1,2,3+4]; array --------- {1,2,7} (1 row) Wielowymiarowa tablica: SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]]; array ----------------- {{1,2},{3,4}} (1 row) Wewnętrzne słowa ARRAY można opuszczać. 54
ARRAY CREATE TABLE Arr(f1 integer[], f2 integer[]); INSERT INTO Arr VALUES (ARRAY[1,2], ARRAY[3,4]); SELECT ARRAY[f1, f2, '{5,6}'::integer[]] FROM Arr; array -------------------------------- {{1,2},{3,4},{5,6}} (1 row) 55
ARRAY od podzapytania SELECT ARRAY(SELECT oid FROM Pg_proc WHERE proname LIKE 'bytea%') AS Zbior; Zbior ------------------------------------------------------------------------------- {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006} (1 row) Podzapytanie musi zwracać pojedyncza kolumnę! * 56
Typy złożone ARRAY CREATE TABLE Sal_emp ( name text, pay_by_quarter integer[], schedule text[][] ); Nieokreślony rozmiar tablic. Ograniczone tablice nie są jeszcze obsługiwane w wersji 8.3. Użycie z konstruktorem lub bez. INSERT INTO Sal_emp VALUES ('Bill', '{10000, 10000, 10000, 10000}', '{{"meeting", "lunch"}, {"training", "presentation"}}'); -- lub INSERT INTO Sal_emp VALUES ('Bill', ARRAY[10000, 10000, 10000, 10000], ARRAY[['meeting', 'lunch'], ['training', 'presentation']]); 57
Dostęp do tablic SELECT name FROM Sal_emp WHERE pay_by_quarter[1] <> pay_by_quarter[2]; SELECT pay_by_quarter[3] FROM Sal_emp; SELECT schedule[1:2][1:1] FROM Sal_emp -- wycinek tablicy WHERE name = 'Bill'; schedule ------------------------ {{meeting},{training}} (1 row) * 58
Aktualizacja tablic UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}' WHERE name = 'Carol'; UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}' WHERE name = 'Carol'; * 59
Typy złożone (rekordowe) CREATE TYPE inventory_item AS ( name text, supplier_id integer, price numeric); CREATE TABLE On_hand ( item inventory_item, count integer); INSERT INTO On_hand VALUES (ROW('fuzzy dice', 42, 1.99), 1000); -- ROW można opuścić, gdy co najmniej dwa elementy na liście CREATE FUNCTION price_extension(inventory_item, integer) RETURNS numeric AS 'SELECT $1.price * $2' LANGUAGE SQL; SELECT price_extension(item, 10) FROM On_hand; 60
SELECT (item).name FROM On_hand WHERE (item).price > 9.99; -- wymagane ujęcie item w nawiasy! CREATE TYPE complex AS (r double precision, i double precision); CREATE TABLE Mytab(complex_col complex); INSERT INTO Mytab (complex_col) VALUES((1.1,2.2)); UPDATE Mytab SET complex_col = ROW(1.1,2.2) WHERE...; UPDATE Mytab SET complex_col.r = (complex_col).r + 1 WHERE...; INSERT INTO Mytab (complex_col.r, complex_col.i) VALUES(1.1, 2.2); 61
Indeksy B-drzewo, Hash oraz opracowane w Uniwersytecie w Berkley: GiST (Generalized Search Tree) i GIN (Generalized Inverted Index) W B drzewach NULLe idą na koniec. CREATE INDEX name ON table(column); -- B-drzewo CREATE INDEX name ON table USING hash(column); -- Hasz CREATE INDEX ind_nam ON People ((first_name ' ' last_name)); 62
Realizacja złożonej selekcji Użycie indeksów może być łączone przez optymalizator np. gdy klauzula: WHERE (A OR B) AND (C OR D) i są indeksy pozwalające wyznaczyć WHERE A, WHERE B, WHERE C, WHERE D każde wyszukiwanie produkuje wektor bitów, które następnie są razem łączony w wynik jak przy indeksach bitmapowych. Sel(R, (A OR B) AND (C OR D)) = (SEL(R,A) OR SEL(R,B)) AND (SEL(R,C) OR SEL(R,D)) 63
Indeksy częściowe Określone na podzbiorze zbioru wierszy określonym przez predykat indeksu. Można w ten sposób uniknąć indeksowania wartości, które często występują i dla których użycie indeksu jest niewskazane. CREATE TABLE Access_log (url varchar, client_ip inet,... ); CREATE INDEX access_log_client_ip_ix ON Access_log (client_ip) WHERE NOT (client_ip > inet '192.168.100.0' AND client_ip < inet '192.168.100.255'); Indeks zostanie np. użyty dla: SELECT * FROM Access_log WHERE client_ip = inet '192.168.100.23'; CREATE INDEX orders_unbilled_index ON Orders (order_nr) WHERE billed IS NOT true; 64
Operator CLUSTER na tabeli grupujący rekordy tabeli (1) CLUSTER tablename USING indexname; Indeks musi być wcześniej utworzony. System sortuje plik danych zgodnie z porządkiem określonym przez indeks. Aby optymalizator wziął dokonane pogrupowanie pod uwagę trzeba wykonać instrukcję ANALYZE. Kolejne UPDATEy mogą zaburzyć porządek klastra. Dokonywać częstych powtórzeń CLUSTER np. CLUSTER; -- dokonuje reklastrowania wszystkich pogrupowanych tabel. Operacja poniższa może być szybsza niż (1): CREATE TABLE newtable AS SELECT * FROM table ORDER BY columnlist; 65
Transakcja BEGIN; -- początek transakcji UPDATE Accounts SET balance = balance - 100.00 WHERE name = 'Alice'; -- etc etc COMMIT/ROLLBACK/ROLLBACK TO savepoint; Gdy nie ma BEGIN - każda instrukcja jest osobną transakcją. 66
Współbieżność: model MVCS (Multiversion Concurrency Control) Przy odczycie nie ma blokad wykorzystywana jest jednolita wersja danych tak jak w Oracle. Oprócz tego są blokady zakładane explicite zarówno na poziomie wierszy jak i tabel. Są tylko dwa różne poziomy izolacji (tak jak w Oracle) o nazwach: READ COMMITTED i SERIALIZABLE. 67
READ COMMITTED Read Committed jest domyślny. Zapytanie korzysta ze stanu bazy danych, jaki był w chwili rozpoczynania się zapytania uwzględniający tylko zmiany zatwierdzone. Przy UPDATE, DELETE, SELECT z FOR UPDATE i SELECT z FOR SHARE wyszukiwanie wierszy odbywa się tak samo jak przy SELECT i dotyczy wierszy także gdy zostały w trakcie zmienione wyszukiwanie czeka na zakończenie transakcji, która je zmienia - (gdy uzyskane zostaną blokady do update u sprawdzane jest ponownie czy spełniają one warunek wyszukiwania). (*) SELECT Ename FROM Emp WHERE Deptno=123 FOR SHARE; - założenie blokad S na spełniające wiersze 68
SERIALIZABLE Zapytanie korzysta ze stanu bazy danych, jaki był w chwili rozpoczynania się transakcji uwzględniający tylko zmiany zatwierdzone. Przy UPDATE, DELETE, SELECT FOR UPDATE i SELECT FOR SHARE wyszukiwanie wierszy odbywa się tak samo jak przy SELECT i dotyczy tych wierszy także gdy zostały w trakcie zmienione wyszukiwanie czeka na zakończenie transakcji, która je zmienia. Gdy wiersz nie uległ zmianie od chwili rozpoczęcia się transakcji, transakcja zakłada blokady i wykonuje zmiany. Gdy wiersz uległ zmianie, transakcja zostaje wycofana i aplikacja musi ją ponowić. Jest gwarancja, że transakcja działa na spójnych danych nie zmienianych przez inne transakcje, ale nie zapobiega fantomom, czyli nie gwarantuje szeregowalności (wymagane jest założenie explicite odpowiednich blokad). 69
Rodzaje blokad na tabeli ACCESS SHARE do wykonania zwykłego SELECT; ROW SHARE (IS) do SELECT FOR UPDATE i SELECT FOR SHARE; ROW EXCLUSIVE (IX) do INSERT, DELETE, UPDATE; SHARE UPDATE EXCLUSIVE do VACUUM, ANALYZE, CREATE INDEX CONCURRENTLY; SHARE (S) do CREATE INDEX (bez CONCURRENTLY); SHARE ROW EXCLUSIVE SHARE i ROW ECLUSIVE; EXCLUSIVE (X) przy pewnych operacjach na katalogu systemowym; ACCESS EXCLUSIVE do ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX, CLUSTER, VACUUM FULL 70
Blokady explicite na tabelę LOCK TABLE Nazwa IN MODE; 71
Blokady wierszowe Tylko dwa typy: SHARE i EXCLUSIVE. Informacja o blokadzie na wierszu nie jest trzymana w RAM, tylko razem z wierszem danych na dysku (tak jak w Oracle). Blokada na wierszu nie blokuje jego odczytu tylko jego zapis. Gdy wiersz jest zmieniany blokada EXCLUSIVE. Przy SELECT FOR UPDATE jest zakładana blokada EXCLUSIVE nie ma osobnego typu blokady UPDATE. Blokada SHARE jest zakładana przy SELECT FOR SHARE. Samo SELECT nie zakłada blokady SHARE na wierszach. 72
Uprawnienia obiektowe SELECT, INSERT, UPDATE, DELETE, REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORARY, EXECUTE, USAGE. GRANT UPDATE ON accounts TO joe; 73
Aby móc używać czyjegoś schematu użytkownik musi uzyskać uprawnienie USAGE od właściciela (podobnie, aby tworzyć obiekty, uprawnienie CREATE do schematu). Każdy użytkownik mający uprawnienie logowania się do bazy danych, ma uprawnienia CREATE i USAGE w schemacie public. Właściciel bazy danych może odwołać te domyślne uprawnienia: REVOKE CREATE ON SCHEMA public FROM PUBLIC; 74
Wzorce użycia schematów v v v Jeden schemat public tak jakby nie było schematów domyślnie wybierany jest public. Każdy użytkownik ma zakładany schemat identyczny ze swoją nazwą użytkownika. Wtedy system jako domyślny schemat bierze właśnie ten schemat. Można usunąć schemat public. Wiele schematów dedykowanych do obsługi specyficznych funkcji/użytkowników. 75
Katalog systemowy Każda baza danych zawiera schemat pg_catalog, w którym znajdują się systemowe tabele/perspektywy. Nazwy obiektów w tym schemacie zaczynają się od pg, np.pg_class katalog obiektów jak tabele, perspektywy, indeksy; pg_attribute kolumny tabel; pg_database bazy danych (jeden katalog na klaster). SELECT p.relname, c.name, c.altitude FROM Cities c, PG_class p WHERE c.altitude > 500 and c.tableoid = p.oid; Relname name altitude ----------+------------+---------- cities Las Vegas 2174 cities Mariposa 1953 capitals Madison 845 76
Tworzenie bazy danych CREATE TABLESPACE sample_ts OWNER <db_owner> LOCATION 'c:/pgdata/sampledb/system'; CREATE DATABASE sample_db OWNER <db_owner> TEMPLATE <template> TABLESPACE sample_ts; Template0 oryginalna, systemowa pusta baza danych Template1 systemowa dopasowana baza danych możliwe dodawanie obiektów i cech (domyślnie) Ewentualnie inna bd nieaktywna. 77
EXPLAIN EXPLAIN SELECT * FROM tenk1; QUERY PLAN --------------------------------------------------------------------------- Seq Scan on tenk1 (cost=0.00..458.00 rows=10000 width=244) 1. Szacowany koszt wstępny przed rozpoczęciem przekazywania wyników np. sortowanie (domyślnie l. operacji We/Wy) 2. Szacowany koszt całkowity (domyślnie l. operacji We/Wy) 3. Szacowana liczba wynikowych wierszy. 4. Szacowany oczekiwany rozmiar wiersza (w bajtach). 78
Statystyki używane przez optymalizator SELECT relname, relkind, reltuples, relpages FROM pg_class WHERE relname LIKE 'tenk1%'; Relname relkind reltuples relpages ----------------------+---------+-----------+---------- tenk1 r 10000 358 tenk1_hundred i 10000 30 tenk1_thous_tenthous i 10000 30 tenk1_unique1 i 10000 30 tenk1_unique2 i 10000 30 (5 rows) r tabela, i - indeks Liczba wierszy, Liczba stron 79
Statystyki obliczane przez ANALYZE Domyślnie ANALYZE jest realizowane przez proces drugoplanowany działający w tle. Oszacowanie selektywności wyszukiwania przez indeks założony na danej kolumnie. Dla każdej tabeli i kolumny np. Liczba różnych wartości w kolumnie Jaki procent wartości w kolumnie stanowią NULL Lista wartości, które wielokrotnie się powtarzają 80
Instrukcje administracyjne VACUUM odśmiecanie (garbage-collection) miejsca na dysku i opcjonalnie, przy okazji ANALYZE. REINDEX przebudowa indeksów. 81
Powiadamianie o zajściu zdarzenia W ramach jednej bazy danych: LISTEN nazwa_zdarzenia; (na czas aktualnej sesji) NOTIFY nazwa_zdarzenia; UNLISTEN nazwa_zdarzenia; Np. Nowy_klient_dodany_do_bazy, Klient_nie_wypłacalny. Projektant bazy danych ustala nazwy zdarzeń. Dodatkowe informacje są przekazywane poprzez tabele w indywidualny sposób. Zwykle instrukcja NOTIFY występuje w regule automatycznie odpalanej. Jeśli występuje w transakcji, akcja powiadamiania zachodzi po wykonaniu COMMIT. Powiadomienie zależy od języka aplikacji np. w C funkcja PQnotifies sprawdza, czy otrzymano powiadomienie. 82
Przykład ujawnienie wierszy w tabeli przez perspektywę CREATE VIEW phone_num AS SELECT name, phone FROM phone_data WHERE phone NOT LIKE '412%'; CREATE FUNCTION tricky(text, text) RETURNS bool AS $$ BEGIN RAISE NOTICE '% => %', $1, $2; RETURN true; END $$ LANGUAGE plpgsql COST 0.0000000000000000000001; SELECT * FROM phone_num WHERE tricky(name, phone); -- COST wskazówka dla optymalizatora - oczekiwany koszt realizacji funkcji 83
Przestrzeń tabel CREATE TABLESPACE space1 LOCATION '/mnt/sda1/postgresql/data'; CREATE TABLE foo(i int) TABLESPACE space1; Również baza danych może zostać utworzona w określonej przestrzeni tabel. 84
TOAST (The Oversized-Attribute Storage Technique). Stały rozmiar strony - 8kB Każdy wiersz tylko na jednej stronie. Gdy są kolumny dopuszczające większe rozmiary niż domyślnie 2000B, danej tabeli jest przyporządkowywana druga tabela do zapisywania dużych wartości w kolumnach. Duże obiekty są kompresowane albo składowane jako zbiór wierszy w tej dodatkowej tabeli. 85