Hlavní navigace

Embedded databáze - Gadfly

31. 5. 2004
Doba čtení: 6 minut

Sdílet

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.

Cloud 24 - tip 1

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

Byl pro vás článek přínosný?