http://postgres.cz/api.php?action=feedcontributions&user=82.119.243.73&feedformat=atomPostgreSQL - Příspěvky [cs]2024-03-28T08:49:45ZPříspěvkyMediaWiki 1.36.0http://postgres.cz/index.php?title=Skoleni&diff=208Skoleni2006-08-03T10:20:41Z<p>82.119.243.73: </p>
<hr />
<div>Školení<br />
<br />
Toto denní školení je určeno budoucím uživatelům PostgreSQL, kteří chtějí získat základní představu o vlastnostech této databáze a získat nutné minimum znalostí pro optimální používání PostgreSQL. Toto školení je zaměřeno na používání PostgreSQL v prostředí o.s. Linux. Od účastníků školení se předpokládá minimální znalost SQL a minimální znalost operačního systému Linux. <br />
<br />
Osnova kurzu:<br />
1. Administrace PostgreSQL (cca 4. hod.)<br />
* Členění souborů, struktura databáze<br />
* Instalace, inicializace databázového clusteru, poinstalační nastavení<br />
* Zálohování databáze, obnova databáze ze zálohy, export a import dat<br />
* Správa uživatelů<br />
* Nastavení procesu pg_autovacuum<br />
* Ukázka SQL klientů phpPgAdmin a Emacs<br />
* Orientace v systémovém katalogu<br />
<br />
2. Popis interních mechanismů PostgreSQL (cca 1. hod.)<br />
* Multigenerační architektura (MVCC) - izolace procesů<br />
* TOAST <br />
* Partitioning<br />
<br />
3. Optimalizace SQL dotazů (cca 1. hod.)<br />
* Variace SQL příkazů, čtení výpisu příkazu EXPLAIN<br />
* Složený, jednoduchý, podmíněný a funkcionální index<br />
<br />
4. Programování uložených procedur (cca 2. hod.)<br />
* Instalace procedurálního jazyka a nastavení přístupových práv<br />
* Představení jazyka PL/pgSQL<br />
* Návrh jednoduché funkce finanční matematiky<br />
* Návrh SRF funkce<br />
<br />
Z trojice nejrozšířenějších open source databází Firebird, MySQL a PostgreSQL patří PostgreSQL oprávněně na vrchol, co se týká stability, podpory ANSI SQL, výkonu v enterprise aplikacích. Snadno se používá, snadno se rozšiřuje o další funkce. Na internetu je volně dostupná řada vynikajících doplňků (tsearch2, OpenGIS) včetně kvalitní dokumentace.<br />
<br />
Školení povede Pavel Stěhule. Pavel pravidelně píše o PostgreSQL na www.root.cz a je podepsán pod většinou článků, které v posledních pěti letech vyšly o PostgreSQL v češtině. Pro PostgreSQL napsal několik doplňků umožňujících snadnější portaci Oracle aplikací do PostgreSQL. Je zodpovědný za weby postgresql.ok.cz a postgresql.interweb.cz.</div>82.119.243.73http://postgres.cz/index.php?title=Napi%C5%A1te_si_debugger_PL/pgSQL_aneb_pokro%C4%8Dil%C3%A9_techniky_programov%C3%A1n%C3%AD_v_PostgreSQL&diff=203Napište si debugger PL/pgSQL aneb pokročilé techniky programování v PostgreSQL2006-07-17T07:07:13Z<p>82.119.243.73: </p>
<hr />
<div>[[Category:Články]]<br />
Napište si debugger PL/pgSQL aneb pokročilé techniky programování v PostgreSQL <br />
<br />
Zkuste si napsat vlastní debugger uložených procedur. Brzo zjistíte, že to není žádná legrace. Proč? Jednak debugger je typicky interaktivní aplikace, a prostředí uložených procedur se ani náhodou nedá označit jako interaktivní. Navíc se snažíte ladit kód, který je prováděn vzdáleně. Řeknu to rovnou, bez úpravy zdrojových kódů a rozšíření komunikačního protokolu nemáte šanci (jeden skoro skutečný debugger PL/pgSQL jsem už napsal). Když se ale smíříte s určitými omezeními a pokud použijete knihovnu orafce, je tu jistá naděje.<br />
<br />
Pro tuto chvíli zůžím funkcionalitu debuggerů na krokování kódu. Pak je funkcí debuggeru zastavit v určitém bodě provádění kódu, informovat obsluhu o dosažení bodu přerušení a čekat na pokyny obsluhy. Je na uživateli, zda-li ukončí laděnou aplikaci, nebo si nechá vypsat obsah proměnných, nebo bude pokračovat dál v ladění. Opět je tu menší zádrhel. Vzhledem k implementaci PL/pgSQL neexistuje způsob, jak se dostat k proměnným. To zamrzí. Pracujeme ale s databází, takže můžeme v kódu obsah proměnných uložit do tabulky a tu si přečíst. Tuto tabulku musíme ale číst z session laděné aplikace. PL/pgSQL funkce se spouští v transakci, a do ukončení (a potvrzení transakce) nejsou jakékoliv provedené změny v tabulkách zvenčí viditelné. Takže tu máme dva hlavní problémy: a) pozastavení kódu, b) obousměrná komunikace v prostředí klient/server. Pokud znáte programovací jazyk PL/pgSQL, tak víte, že řešení těchto problémů je nad možnosti tohoto jazyka. Takže jak? Relativně krátce je k dispozici pro PostgreSQL doplněk [http://pgfoundry.org/projects/orafce/ Orafce], který, kromě jiného, obsahuje implementaci balíčku [http://www.utexas.edu/its/unix/reference/oracledocs/v92/B10501_01/appdev.920/a96612/d_pipe.htm dbms_pipe RDBMS Oracle]. Funkce z tohoto balíčku umožňují asynchronní multisession komunikaci, což je přesně to, co potřebujeme. Z hlediska uživatele umožňují zakládat pojmenované roury a jejich prostřednictvím realizovat komunikaci mezi dvěma sessions. Roury v RDBMS se chovají stejně jako systémové sestřičky. Proces, který se snaží číst z prázné roury je zastaven a čeká až se do roury jiný proces zapíše. A to je způsob, jak dokážeme řízenně zastavit provádění PL/pgSQL funkce.<br />
<br />
Ještě si dovolím stručně popsat knihovnu [[Oracle functionality#DBMS_PIPE|dbms_pipe]]. Roura je datová abstrakce (něco jako soubor) umožňující komunikaci mezi klienty databáze. V podstatě se jedná o sdílenou pamět, do které jeden klient zapisuje a druhý z ní čte. Data, která se prostřednictvím roury přenášejí, jsou strukturovaná, tj. každá zpráva, která se do roury uloží může mít víc položek různých typů. Celý proces přenosu probíhá v několika krocích:<br />
* v lokální paměti sestavujeme zprávu přidáváním jednotlivých položek,<br />
* obsah lokální paměti přesuneme do sdílené paměti. Od toho okamžiku má libovolný PostgreSQL klient přístup ke zprávě,<br />
* obsah sdílené paměti přesuneme do lokální paměti klienta a zprávu odstraníme ze sdílené paměti<br />
* z lokální paměti postupně načítáme položku zprávy<br />
Jak na rouru, tak na zprávu se můžeme dívat jako na FIFO fronty. Každá roura může být sdílená několika klienty. Každá zpráva je ale přečtena pouze jednou,- získá ji a z sdílené paměti odstraní klient, který se k ní dostane jako první.<br />
<br />
Nerad bych tu přepisoval dokumentaci k dbms_pipe, kterou si můžete bezproblémově vygooglovat na netu. Pro začátek si vystačíme s funkcemi:<br />
<br />
{|<br />
|-<br />
| dbms_pipe.pack_message(hodnota) || uloží hodnotu do bufferu sestavované zprávy.<br />
|-<br />
| dbms_pipe.send_message(nazev_fronty) || přesune zprávu do pojmenované fronty zpráv.<br />
|-<br />
| dbms_pipe.receive_message(název_fronty) || z pojmenované fronty zpráv přesune první zprávu do bufferu čtené zprávy.<br />
|-<br />
|dbms_pipe.unpack_message_typ() || vrací hodnotu daného typu, která je první v bufferu čtené zprávy.<br />
|-<br />
|}<br />
Například přesun čísla a textu mezi dvěma přihlášenými klienty provede následující posloupnost volání funkcí:<br />
<pre><br />
SELECT dbms_pipe.pack_message(0);<br />
SELECT dbms_pipe.pack_message('Ahoj');<br />
SELECT dbms_pipe.send_message('moje roura');<br />
<br />
SELECT dbms_pipe.receive_message('moje roura');<br />
SELECT dbms_pipe.unpack_message_number();<br />
SELECT dbms_pipe.unpack_message_text(); <br />
</pre><br />
Teď už máme dostatek znalostí, abychom napsali funkci trace(...), která pošle své argumenty ladícímu klientu a čeká před svým dokončením na vnější signál. Laděnou funkci musíme ručně doplnit o volání trace, např:<br />
<pre><br />
CREATE OR REPLACE FUNCTION test_loop() <br />
RETURNS void AS $$<br />
BEGIN<br />
FOR i IN 1..10 LOOP<br />
trace('test_loop', 3, i::text);<br />
END LOOP;<br />
END;<br />
$$ LANGUAGE plpgsql;<br />
</pre><br />
Potřebuji dvě funkce. Zmíněnou funkci trace() a funkci cont, která zobrazí ladící data a popostrčí funkci trace (signalizuje jí požadavek na její ukončení).<br />
<pre><br />
CREATE OR REPLACE FUNCTION trace(_name varchar, _ln integer, _value varchar)<br />
RETURNS void AS $$<br />
BEGIN<br />
PERFORM dbms_pipe.pack_message(_name);<br />
PERFORM dbms_pipe.pack_message(_ln);<br />
PERFORM dbms_pipe.pack_message(_va);<br />
PERFORM dbms_pipe.send_message(dbms_pipe.unique_session_name()||'$DBG'); -- posli data<br />
PERFORM dbms_pipe.receive_message(dbms_pipe.unique_session_name()||'$DBG$CONT'); -- cekej na signal<br />
END;<br />
$$ LANGUAGE plpgsql;<br />
<br />
CREATE OR REPLACE FUNCTION cont(_pipe varchar, OUT _fn varchar, OUT _ln integer, OUT _value varchar)<br />
RETURNS record AS $$<br />
BEGIN<br />
-- jsou k dispozici data?<br />
PERFORM 1 FROM dbms_pipe.db_pipes WHERE name = _name AND items > 0;<br />
IF FOUND THEN<br />
PERFORM dbms_pipe.receive_message(_pipe||'$DBG');<br />
_fn := dbms_pipe.unpack_message_text();<br />
_ln := dbms_pipe.unpack_message_number();<br />
_value := dbms_pipe.unpack_message_text();<br />
RETURN;<br />
ELSE<br />
-- ceka nekdo na signal continue?<br />
PERFORM 1 FROM dbms_pipe.db_pipes WHERE name = _name || '$DBG$CONT' AND items = 0;<br />
IF FOUND THEN<br />
PERFORM dbms_pipe.send_message(_name||'$DBG$CONT');<br />
END IF;<br />
-- opet cekej na data<br />
PERFORM dbms_pipe.receive_message(_name);<br />
_fn := dbms_pipe.unpack_message_text();<br />
_ln := dbms_pipe.unpack_message_number();<br />
_value := dbms_pipe.unpack_message_text();<br />
RETURN;<br />
END IF;<br />
END;<br />
$$ LANGUAGE plpgsql;<br />
</pre><br />
Samotné krokování může probíhat tak, že v jednom okně si spustíme laděnou funkci, a v druhém okně výpisem z tabulky db_pipes získáme identifikátor session, a opakujeme volání funkce cont. Tato verze má tu nevýhodu, že nejsme schopni detekovat ukončení provádění laděné funkce a a funkci cont musíme po posledním cyklu ručně přerušit.<br />
<pre><br />
postgres=# select test_loop();<br />
<br />
postgres=# select * from dbms_pipe.db_pipes;<br />
name | items | size | limit | private | owner<br />
-------------------------+-------+------+-------+---------+-------<br />
PG$PIPE$1$4652$DBG | 1 | 32 | | f |<br />
PG$PIPE$1$4652$DBG$CONT | 0 | 0 | | f |<br />
(2 rows)<br />
<br />
postgres=# select cont('PG$PIPE$1$4652');<br />
cont<br />
------------------<br />
(test_loop,40,1)<br />
(1 row)<br />
<br />
postgres=# select cont('PG$PIPE$1$4652');<br />
cont<br />
------------------<br />
(test_loop,40,2)<br />
(1 row)<br />
<br />
...<br />
<br />
postgres=# select cont('PG$PIPE$1$4652');<br />
Cancel request sent<br />
ERROR: canceling statement due to user request<br />
CONTEXT: SQL function "receive_message" statement 1<br />
SQL statement "SELECT dbms_pipe.receive_message( $1 ||'$DBG')"<br />
PL/pgSQL function "cont" line 3 at perform<br />
</pre><br />
S bezestavovým komunikačním protokolem si nevystačíme. Jakékoliv další funkce se implementují dost komplikovaně. Dvou-stavový protokol sám o sobě řeší synchronizaci komunikace. V prvním stavu laděný klient oznamuje, že se dostal do stavu přerušení a očekává příkaz. V druhém stavu laděný klient odesílá výsledek zpracovaného příkazu. Vzájemnou komunikaci mohu popsat schématem:<br />
<pre><br />
A, Dostal jsem se k bodu B, Počkej až si klient řekne<br />
přerušení, čekám na o příkaz, pak mu jej pošli.<br />
příkaz Čekej na výsledek<br />
<br />
A, Zpracoval jsem příkaz, B, Zobraz výsledek a skonči<br />
posílám výsledek a <br />
skonči<br />
</pre><br />
Proces A - laděný klient, Proces B - ladící klient. Pokud bych nezkoušel napsat debugger v PL/pgSQL, pak bych proces B implementoval jako smyčku obsahující zobrazení ladících informací, získání reakce od uživatele a zpracování vstupu. Jelikož uložené procedury z principu nenabízejí žádný prostředek, jak zajistit interakci s uživatelem (Nedávno jsem narazil v konferenci na dotaz, jak v uložených procedurách implementovat MessageBox a InputBox. Odpověď: Principiálně to není možné.), nelze toto schéma použít. Veškerá data od uživatele musím mít už v době volání funkce. Proto jsem napsal funkce cont, exec a stop.<br />
<pre><br />
CREATE OR REPLACE FUNCTION trace(_desc varchar, _ln integer, _value varchar)<br />
RETURNS void AS $$<br />
DECLARE<br />
_request integer;<br />
_r record;<br />
_v varchar;<br />
BEGIN<br />
PERFORM dbms_pipe.pack_message(0);<br />
-- posli info dosazeni bodu preruseni a cekej na prikaz<br />
PERFORM dbms_pipe.send_message(dbms_pipe.unique_session_name()||'$DBG');<br />
PERFORM dbms_pipe.receive_message(dbms_pipe.unique_session_name()||'$DBG$CONT');<br />
_request := dbms_pipe.unpack_message_number();<br />
PERFORM dbms_pipe.pack_message(1);<br />
PERFORM dbms_pipe.pack_message(_desc);<br />
PERFORM dbms_pipe.pack_message(_ln);<br />
IF _request = 1 THEN -- vrat parametry<br />
PERFORM dbms_pipe.pack_message(_value);<br />
ELSIF _request = 2 THEN -- proved dotaz<br />
-- pro pretypovani record->varchar je nutne pouzit PL/pgSQL konverzi<br />
EXECUTE dbms_pipe.unpack_message_text() INTO _r;<br />
_v := _r; PERFORM dbms_pipe.pack_message(_v);<br />
ELSIF _request = 3 THEN -- ukonceni ladeni<br />
PERFORM dbms_pipe.pack_message('Stop debuging');<br />
PERFORM dbms_pipe.send_message(dbms_pipe.unique_session_name()||'$DBG');<br />
RAISE EXCEPTION 'Stop debuging';<br />
END IF;<br />
-- posli data<br />
PERFORM dbms_pipe.send_message(dbms_pipe.unique_session_name()||'$DBG');<br />
END;<br />
$$ LANGUAGE plpgsql;<br />
<br />
CREATE OR REPLACE FUNCTION cont(_pipe varchar, OUT _desc varchar, OUT _ln integer, OUT _value varchar)<br />
RETURNS record AS $$<br />
declare i integer;<br />
BEGIN<br />
PERFORM dbms_pipe.receive_message(_pipe||'$DBG');<br />
IF 0 <> dbms_pipe.unpack_message_number() THEN<br />
RAISE EXCEPTION 'Synchronisation error';<br />
END IF;<br />
PERFORM dbms_pipe.pack_message(1);<br />
PERFORM dbms_pipe.send_message(_pipe||'$DBG$CONT');<br />
PERFORM dbms_pipe.receive_message(_pipe||'$DBG');<br />
IF 1 <> dbms_pipe.unpack_message_number() THEN<br />
RAISE EXCEPTION 'Synchronisation error';<br />
END IF;<br />
_desc := dbms_pipe.unpack_message_text();<br />
_ln := dbms_pipe.unpack_message_number();<br />
_value := dbms_pipe.unpack_message_text();<br />
END;<br />
$$ LANGUAGE plpgsql;<br />
<br />
CREATE OR REPLACE FUNCTION stop(_pipe varchar, OUT _desc varchar, OUT _ln integer, OUT _value varchar)<br />
RETURNS record AS $$<br />
declare i integer;<br />
BEGIN<br />
PERFORM dbms_pipe.receive_message(_pipe||'$DBG');<br />
IF 0 <> dbms_pipe.unpack_message_number() THEN<br />
RAISE EXCEPTION 'Synchronisation error';<br />
END IF;<br />
PERFORM dbms_pipe.pack_message(2);<br />
PERFORM dbms_pipe.send_message(_pipe||'$DBG$CONT');<br />
PERFORM dbms_pipe.receive_message(_pipe||'$DBG');<br />
IF 1 <> dbms_pipe.unpack_message_number() THEN<br />
RAISE EXCEPTION 'Synchronisation error';<br />
END IF;<br />
_desc := dbms_pipe.unpack_message_text();<br />
_ln := dbms_pipe.unpack_message_number();<br />
_value := dbms_pipe.unpack_message_text();<br />
END;<br />
$$ LANGUAGE plpgsql;<br />
<br />
CREATE OR REPLACE FUNCTION exec(_pipe varchar, _query varchar, OUT _desc varchar, OUT _ln integer, OUT _value varchar)<br />
RETURNS record AS $$<br />
declare i integer;<br />
BEGIN<br />
PERFORM dbms_pipe.receive_message(_pipe||'$DBG');<br />
IF 0 <> dbms_pipe.unpack_message_number() THEN<br />
RAISE EXCEPTION 'Synchronisation error';<br />
END IF;<br />
PERFORM dbms_pipe.pack_message(5);<br />
PERFORM dbms_pipe.pack_message(_query);<br />
PERFORM dbms_pipe.send_message(_pipe||'$DBG$CONT');<br />
PERFORM dbms_pipe.receive_message(_pipe||'$DBG');<br />
IF 1 <> dbms_pipe.unpack_message_number() THEN<br />
RAISE EXCEPTION 'Synchronisation error';<br />
END IF;<br />
_desc := dbms_pipe.unpack_message_text();<br />
_ln := dbms_pipe.unpack_message_number();<br />
_value := dbms_pipe.unpack_message_text();<br />
END;<br />
$$ LANGUAGE plpgsql;<br />
</pre><br />
Ladění uložených procedur není jedinou oblastí, kde můžeme intersession komunikaci použít. Často se používá k vzájemné synchronizaci procedur nebo k realizaci architektury klient-server (Bohužel PostgreSQL nepodporuje autonomní transakce, takže si v praxi nedovedu představit klient-server aplikaci nad PL/pgSQL. Zatím.). <br />
<br />
Nedělám si iluze, že bych napsal použitelný debugger. Komunikační protokol je primitivní bez možnosti resynchronizace, množina příkazů je minimální. Jenomže sofistikovanější protokol znamená více kódu a tak i menší přehlednost a zřetelnost kódu. Pravdou je, že mi šlo víc o ukázku možností nové knihovny orafce než o vytvoření vlastního debuggeru. Čímž ovšem nevylučuji, že někdo můj prototypový debugger použije. Já sám jsem se ale za těch pár let naučil žít bez debuggeru a vystačit si s RAISE NOTICE.</div>82.119.243.73http://postgres.cz/index.php?title=Diskuse:SQL_Triky&diff=206Diskuse:SQL Triky2006-05-18T05:49:17Z<p>82.119.243.73: </p>
<hr />
<div></div>82.119.243.73http://postgres.cz/index.php?title=Kategorie:FAQ&diff=89Kategorie:FAQ2006-05-17T06:16:46Z<p>82.119.243.73: </p>
<hr />
<div>Často kladené dotazy do PostgreSQL</div>82.119.243.73http://postgres.cz/index.php?title=3.8_Nelze_otev%C5%99%C3%ADt_instala%C4%8Dn%C3%AD_bal%C3%AD%C4%8Dek&diff=1183.8 Nelze otevřít instalační balíček2006-04-11T04:43:43Z<p>82.119.243.73: </p>
<hr />
<div>Tato chyba může mít dvě příčiny. Nejčastější je double-click na MSI soubor v ZIP archivu. Instalace vyžaduje rozbalení ZIP archivu do dočasného adesáře a teprve poté spuštění. Druhým možným důvodem je poškozený stažený soubor. Zkuste jej stáhnout ještě jednou nebo jej zkuste najít někde jinde na internetu.<br />
[[Category: 3. Časté chyby při instalaci]]</div>82.119.243.73http://postgres.cz/index.php?title=3.7_P%C5%99i_upgrade_mi_instal%C3%A1tor_hl%C3%A1s%C3%AD_nedostate%C4%8Dn%C3%A1_pr%C3%A1va,_ale_jsem_zalogov%C3%A1n_jako_administr%C3%A1tor&diff=1173.7 Při upgrade mi instalátor hlásí nedostatečná práva, ale jsem zalogován jako administrátor2006-04-11T04:40:09Z<p>82.119.243.73: </p>
<hr />
<div>Tento problém vyřešíte tak, že napřed odinstalujete předchozí verzi. Poznámka: odinstalací PostgreSQL neodstraníte svoje data. Poté nainstalujte novou verzi. Ujistěte se, že ji instalujete do stejných adresářů. To by mělo pomoci. Tato chyba může nastat při minoritních změnách verzí (např. mezi 8.0.1 na 8.0.2), které nevyžadují dump/reload.<br />
[[Category: 3. Časté chyby při instalaci]]</div>82.119.243.73http://postgres.cz/index.php?title=Kategorie:4._Spole%C4%8Dn%C3%A9_provozn%C3%AD_chyby&diff=202Kategorie:4. Společné provozní chyby2006-04-07T05:41:34Z<p>82.119.243.73: </p>
<hr />
<div>[[Category:MicrosoftFAQ]]</div>82.119.243.73http://postgres.cz/index.php?title=4.1_Instalace_procedur%C3%A1ln%C3%ADho_jazyka_kon%C4%8D%C3%AD_chybou_%22dynamic_load_error%22&diff=2004.1 Instalace procedurálního jazyka končí chybou "dynamic load error"2006-04-07T05:41:23Z<p>82.119.243.73: </p>
<hr />
<div>Častou příčinnou bývá chybějící DLL pro požadovaný procedurální jazyk. DLL, která jsou dodávány s PostgreSQL pouze zpřístupňují procedurální jazyk, a potřebují DLL jazyka dohledatelné z systémové proměnné PATH. Seznam požadovaných DLL pro jednotlivé procedurální jazyky naleznete v instrukcích k instalaci. <br />
<br />
K zjištěbí chybějících knihoven můžete použít "depends tool" fy. Microsoft, který je dostupný v Windows Support Tools, které jsou sice na instalačním CD Windows, ale instalují se samostatně. Pak jednoduše spusťte "depends plpython.dll (pro PL/Python) a dostanete výpis chybějících knihoven.<br />
<br />
<br />
[[Category: 4. Společné provozní chyby]]</div>82.119.243.73http://postgres.cz/index.php?title=Kategorie:2._Dotazy_na_klientsk%C3%A1_rozhran%C3%AD&diff=145Kategorie:2. Dotazy na klientská rozhraní2006-04-06T05:12:03Z<p>82.119.243.73: </p>
<hr />
<div>[[Category:FAQ]]</div>82.119.243.73http://postgres.cz/index.php?title=Kategorie:3._Administrativn%C3%AD_dotazy&diff=152Kategorie:3. Administrativní dotazy2006-04-06T05:11:20Z<p>82.119.243.73: </p>
<hr />
<div>[[Category:FAQ]]</div>82.119.243.73