Embedded databáze - Gadfly

Radim Kolář 31. 5. 2004

Pokračování seriálu o embedded databázových enginech. V dnešním dílu nebude předem ohlášená SQLite, ale pythonská databáze Gadfly.

Gadfy

Databáze Gadfly byla vybrána pro pokračování seriálu z těchto důvodů:

  1. Byla zmíněna v diskusi k prvnímu dílu.
  2. Od napsání prvního dílu jsem se s ní setkal i v komerčních aplikacích.
  3. Je obsažena v Zope.

Databáze Gadfly je malá, relační embedded databáze pro Python, podporující dotazovací jazyk SQL. Databáze je šířena pod příznivou BSD licencí, a je proto velmi vhodná pro začlenění do komerčních produktů naprogramovaných v tomtéž jazyce.

Zvláštní na této databázi je to, že je jako jedna z mála kompletně naprogramována v interpretovaném jazyce Python. Pro Python je totiž nabídka embedded databází mnohem menší než pro Javu, o C ani nemluvě. Gadfly používá pro zrychlení datových operací platformově závislou knihovnu kjbuckets. V případě, že tato knihovna není k dispozici, použije se přenositelná pure-Python verze, která je funkčně ekvivalentní. Gadfly v Zope je naneštěstí dodávána v pomalé variantě.

Instalace

GadFly 1.0 je ke stažení na sourceforge.net. Ačkoliv je tato verze datována 10 Jul 2002, na jejím vývoji se stále pracuje, soudě podle aktivity v CVS. Pro Python 2.3 budete potřebovat ještě dva oneline fixy pro utility gfplus a gfserver.

Python 2.2 jsem nezkoušel, ale protože vyšel v prosinci 2001, měl by fungovat bez problémů. Instalace se provádí klasicky: tj. python setup.py install. Pokud chceme zrychlenou verzi (což chceme), provedeme stejný příkaz i v podadresáři kjbuckets.

Spuštění

Gadfly obsahuje kromě vlastní knihovny implementující databázi ještě dva pomocné programy: gfplus a gfserver. gfplus je interaktivní SQL interpretr a gfserver je server pro víceuživatelský přístup.

(hsn@sanatana):% gfplus

gfplus $Revision: 1.6 $ -- Interactive gadfly shell  [readline]

Friday April 23, 2004 07:53 PM
Using:
DB Name: netmag
DB Location: /tmp
Unable to locate database "netmag" at location "/tmp".
Create? (Yy/Nn) y
GF> create table clanky(id integer, cteno integer, text varchar);
OK
GF> insert into clanky values(1,0,'Nas prvni clanek...');
OK
GF> create unique index clanky1 on clanky(id);
OK
GF> insert into clanky values(1,0,'Nas druhy clanek...');
StorageError: uniqueness violation: 1 UNIQUE index CLANKY1 on ('ID',)
GF> desc clanky

COLUMN_NAME
===========
ID
CTENO
TEXT

GF> select * from  __table_names__;
TABLE_NAME      | IS_VIEW
=========================
__INDEXCOLS__   | 1
__COLUMNS__     | 1
__TABLE_NAMES__ | 1
CLANKY          | 0
DUAL            | 1
__INDICES__     | 1
__DATADEFS__    | 1
GF> select *  from __indices__;
TABLE_NAME | IS_UNIQUE | INDEX_NAME
===================================
CLANKY     | 1         | CLANKY1
GF> 

Omezení Gadfly

  • vůbec nepodporuje hodnotu NULL
  • nedporuje žádné operace s datumy
  • nepodporuje Outer join
  • Typeless databaze, při operacích jsou akceptována data libovolného podporovaného typu bez ohledu na typ sloupce.
  • nepodporuje operator LIKE
  • nepodporuje přístupová práva k db objektům
  • nepodporuje DELETE, UPDATE přes cursory (podobně jako postgresql)
  • neškálovatelná databáze. Celý obsah databáze je při startu nahrán z disku do operační paměti

Nejvíce nemilá jsou první dvě omezení. Datumy je možné ještě oželet s výmluvou na typeless databázi, ale nepodporování hodnoty NULL je vážným omezením. V praxi to znamená, že pokud chcete používat Gadfly jako alternativní db stroj, musíte aplikaci předělat, aby je nepoužívala, což se nemusí vždy podařit.

Podporované vlastnosti

Na druhé straně Gadfly podporuje u embedded databází méně běžné vlastnosti, jako jsou subselecty, agregační funkce včetně nadstandardního MEDIAN, operátor DISTINCT, a to i v agregačních funkcích, prepared statementy, pohledy – včetně user defined v Pythonu (!!), operátory BETWEEN, EXISTS, ANY, ALL a IN. Transakce jsou podporovány včetně crash recovery. Roll forward (nazývané též media) recovery podporováno není.

Použití

Databáze Gadfly má interface pouze do jednoho jazyka, a to do Pythonu. S databází se pracuje standardně pomocí Python Database API.

Příklad použití

Python 2.3.2 (#1, Dec  5 2003, 03:04:50)
[GCC 3.3.3 [FreeBSD] 20031106] on freebsd5
Type "help", "copyright", "credits" or "license" for more information.
>>> import gadfly
>>> c=gadfly.gadfly("netmag","/tmp")
>>> rs=c.cursor()
>>> rs.execute("select * from clanky")
>>> rs.fetchone()
('Nas prvni clanek...', 0, 1) 

Maličkosti

Bystří čtenáři si jistě povšimli, že pořadí vrácených sloupců není při použití operátoru * shodné s pořadím, v jakém byly původně sloupce definovány. Toto chování je odlišné od chování většiny databází a je třeba na něj při programování myslet. Dalším nedostatkem je, že pokud vytvoříte dvě databáze v jednom adresáři, což je možné, přepíší se vám navzájem tabulky se stejným jménem.

Callback view

Jak již bylo psáno, Gadfly umí použít pro definici pohledu místo SQL statementu pythonskou třídu. To nám sice plně user defined funkce a stored procedury v databázi nenahradí, ale pro embedded databáze je to zcela postačující.

Vložíme si do tabulky pár dalších záznamů:

GF> select * from clanky;
TEXT                                 | CTENO | ID
=================================================
Nas prvni clanek...                  | 300   | 1
Novy design!                         | 500   | 2
Vratili jsem tam radsi ten stary.... | 800   | 3
Co takhle zkusit oba dva?            | 321   | 4
Radsi najmeme webdesignera           | 456   | 5

Vytvoříme si pohled, který nám zobrazí jen články s čteností nad 400.

import gadfly
import gadfly.introspection

class hodnectene(gadfly.introspection.RemoteView):
  def __init__(self,db):
    self.column_names=['id']
    self.db=db
  def listing(self):
    rs=self.db.cursor()
    rs.execute("SELECT id FROM clanky WHERE cteno>400")
    return map(lambda x:x[0],rs.fetchall())

c=gadfly.gadfly("netmag","/tmp")
c.add_remote_view("nejlepsi", hodnectene(c))

rs=c.cursor()
rs.execute("SELECT * FROM nejlepsi");
print rs.fetchall() 

Víceuživatelský přístup

Databáze gadfly obsahuje server gfserver, který umožnuje víceuživatelský, vzdálený přístup k databázi. Spíše než databázový server je to jednoduchý multiplexer jednotlivých databázových operací. Umožňuje však vytvářet rozdílné security policy, a jednoduchým způsobem tak omezovat příkazy, které je možné v databázi provádět.

Malá ukázka:

(hsn@sanatana):% gfserver 2222 netmag /tmp tajneheslo
gfserve: starting the server
main loop on <socket._socketobject object at 0x8309a2c> <gadfly.database.gadfly instance at 0x81d21ac>
server: waiting for connection(s)

Přístup k serveru. /admin/ je jméno policy.
Python 2.3.3 (#2, Apr 18 2004, 08:35:27)
[GCC 3.3.3 [FreeBSD] 20031106] on freebsd5
Type "help", "copyright", "credits" or "license" for more information.
>>> import gadfly.client
>>> conn = gadfly.client.gfclient("admin", "tajneheslo", "localhost",2222)
>>> c=conn.cursor()
>>> c.execute("SELECT * from clanky")
>>> c.fetchall()
[('Nas prvni clanek...', 300, 1), ('Novy design!', 500, 2), ('Vratili jsem tam radsi ten stary....', 800, 3), ('Co takhle zkusit oba dva?', 321, 4), ('Radsi najmeme webdesignera', 456, 5)] 

Rychlost

Realnému otestování rychlosti bránil fakt, že Gadfly nepodporuje hodnoty NULL. Nemohl jsem tak pouhou změnou db driveru provést test v reálné aplikaci.

Pro hrubou ilustraci jsem změřil inserty za sekundu na Pentiu 200 Mhz. U databáze PostgreSQL jsem prepared statementy netestoval, protože každý driver používá odlišnou syntaxi a mapování na server-side prepared statementy není podporováno. V našem případě by server-side prepared statementpřidal 15 % Prepared statementy se vyplácejí jen u krátkých dotazů, u déletrvajících dotazů je jejich vliv prakticky nulový. Z tabulky je vidět, že výkon Gadfly je pro běžné použití rozhodně dostačující.

Tabulka č. 569
postgresql 7.4 psycopg driver 750
postgresql 7.4 PyGreSQL driver 614
postgresql 7.4 pyPgSQL driver 462
gadfly – immediate 98
gadfly – prepared statement 229

Závěr

Proč použít Gadfly databázi? Odpověd jsem získal od jednoho výrobce komerčního software, který ji používá.

  • Nemusí se nic instalovat
  • Rychlost je přijatelná
  • Běží na všech platformách podporovaných Pythonem
  • Moje aplikace tak není závislá na SQL serveru
  • Umí SQL
DigiZone.cz: Mňam TV chystá vstup na Slovensko

Mňam TV chystá vstup na Slovensko

Vitalia.cz: 7 nemocí očí, které musíte léčit včas

7 nemocí očí, které musíte léčit včas

120na80.cz: Velký přehled: 7 očkování proti exotickým nemocem

Velký přehled: 7 očkování proti exotickým nemocem

Lupa.cz: Jak EET vidí ajťák aneb Drahá vražda UX

Jak EET vidí ajťák aneb Drahá vražda UX

Podnikatel.cz: Šizený guláš na pultě. Jako Lidl to nedělejte

Šizený guláš na pultě. Jako Lidl to nedělejte

Vitalia.cz: Před, nebo po snídani? Kdy je lepší čistit si zuby

Před, nebo po snídani? Kdy je lepší čistit si zuby

DigiZone.cz: DAB+ versus FM, ČRo a ČRa proti APSV

DAB+ versus FM, ČRo a ČRa proti APSV

Vitalia.cz: Dnešní patolog o mrtvolu téměř nezavadí

Dnešní patolog o mrtvolu téměř nezavadí

Vitalia.cz: Martin Kasa o byznysu s léky

Martin Kasa o byznysu s léky

Vitalia.cz: Proč máme prasklý chléb nejraději?

Proč máme prasklý chléb nejraději?

DigiZone.cz: Šlágr TV dostala pokutu 100 000 Kč

Šlágr TV dostala pokutu 100 000 Kč

DigiZone.cz: Programatický nákup i pro rozhlas

Programatický nákup i pro rozhlas

Lupa.cz: Babiš: nevím o návodu, jak obejít blokování webů

Babiš: nevím o návodu, jak obejít blokování webů

Vitalia.cz: Sója a rakovina

Sója a rakovina

Vitalia.cz: Syndrom PC vidění: stačí dvě hodiny denně

Syndrom PC vidění: stačí dvě hodiny denně

120na80.cz: Zjistěte, zda je vaše klíště infikované

Zjistěte, zda je vaše klíště infikované

120na80.cz: 5 triků, jak zastavit krvácení po holení

5 triků, jak zastavit krvácení po holení

120na80.cz: Co jí dělá? Sklerotizaci

Co jí dělá? Sklerotizaci

Lupa.cz: Zaplatíme ti, když ti seženeme práci

Zaplatíme ti, když ti seženeme práci

Vitalia.cz: Taky ji kupujete? Je šizená

Taky ji kupujete? Je šizená