Autor: Martin Kumst – www.kumst.net – martin.kumst@seznam.cz
Sám jsem se s projektem SQLite seznámil poměrně nedávno a musím říci, že se mi velice zalíbil. Také lituji toho, že jsem jej neobjevil již dříve, protože bych si jeho použitím pro některá nasazení usnadnil život a ušetřil nemalé množství práce. Doufám, že vám následující text tento šikovný projekt přiblíží a třeba bude inspirací k tomu, že sami SQLite zkusíte a třeba i někde nasadíte.
SQLite je relativně malá knihovna, která implementuje kompletní relační databázový systém. Nejedná se však o klasickou klient – server databázi tak, jak ji známe z projektů MySQL a PostgreSQL, ale naopak je zde databáze uložena v souboru a předpokládá se tedy, že k datům přistupuje software, který běží na stejném počítači či serveru, na kterém jsou uložena data.
Základní myšlenkou projektu SQLite je jednoduchost. Jak již bylo řečeno, samotná databáze s daty je uložena v klasickém souboru na disku. Dále je třeba zmínit to, že SQLite prakticky vůbec nepotřebuje žádnou konfiguraci. Databázový software je absolutně spokojen, pokud mu sdělíte, s jakým databázovým souborem hodláte pracovat. Samozřejmě je nutné, aby uživatel, pod kterým poběží váš software přistupující k datům, měl k databázovému souboru náležitá práva. Neznamená to však, že SQLite nelze vůbec konfigurovat. Pokud si budete přát, můžete chování své instance SQLite upravit pomocí příkazu PRAGMA.
Autorem tohoto projektu je programátor D. Richard Hipp, který se rozhodl své dílo šířit pod public domain licencí, což může být považováno za jednu z výhod tohoto databázového systému, jelikož se v případě sporného použití tohoto projektu nemusíte licenčními podmínkami zabývat vůbec. SQLite je údajně použit na příklad v následujících aplikacích: Google Chrome, Safari, Opera, Android Browser, Mozilla Firefox a Thunderbird, Skype a Adobe Reader. SQLite je podporován následujícími organizacemi: Facebook, Expensify, Mozilla, Navagiation Data Standard, Bentley a Bloomberg. SQLite lze použít na všech GNU/Linuxových distribucích, Windows i OS X. Z uvedeného jasně vyplývá, že možnosti použití SQLite jsou velmi rozmanité a multiplatformní.
Výhodami SQLite jsou tedy: velká jednoduchost použití, malá velikost, databáze v souboru, většinou nulová potřeba jakékoli konfigurace, nulová cena a jistě i public domain licence.
Jako další výhodu je také nutno uvést i jistou míru paralelního přístupu, kterou, na rozdíl od konkurenčních projektů, SQLite nabízí. SQLite umožňuje, aby z jedné databáze četlo najednou více instancí. Toto však neplatí pro zápis, ale o tom až dále.
Jako další výhodu vnímám i fakt, že vzhledem k velice malé velikosti SQLite je až obdivuhodné, že podporuje skoro celý standard SQL-92. SQLite podporuje dokonce i cizí klíče, jejichž vynucení je však potřeba aktivovat použitím příkazu PRAGMA.
Další výhodu také můžeme spatřovat také v tom, že vzhledem k tomu, že je databáze uložena v jednom jediném souboru, je její zálohování a případně i distribuce opravdu snadným úkolem.
Jako hlavní nevýhodu bych viděl nízký výkon, který se projeví hlavně při zápisu většího množství dat. SQLite chápe každý insert jako vlastní transakci a podle dokumentace transakci dokončí opravdu až tehdy, kdy jsou data bezpečně fyzicky uložena na disku. Na jednu stranu je dobré, že se můžete v podstatě spolehnout na bezpečné uložení dat, ale na stranu druhou je nízký výkon silně obtěžující a hlavně omezující faktor. Tuto neblahou situaci můžete vyřešit tím, že uzavřete více insertů do vlastní transakce (begin transaction a commit). Tím docílíte velmi výrazného zrychlení v případě, že na databázi pouštíte větší množství insertů.
Nevýhodou je také již zmíněné uzavření celé databáze v případě probíhajícího zápisu. To znamená, že v podstatě nelze realizovat paralelní zápis do databáze. Také nelze z databáze číst, pokud je do ní zrovna zapisováno.
Ve výše uvedených odstavcích jsem se pokusil nastínit hlavní výhody a nevýhody projektu SQLite. Jistě by se o těchto tématech dalo napsat daleko více textu, ale obávám se, že je to mimo rozsah tohoto článku.
SQLite se hodí pro malá nasazení, kdy k datům přistupuje pouze jeden fyzický stroj a to nejlépe pouze z jedné instance či vlákna. Typickým příkladem tedy může být jednoduché osobní účetnictví, malý pokladní terminál, správce osobních financí či aplikace pro finanční analýzu.
SQLite se také hodí jako databáze pro malý až střední web. Zde můžete těžit z faktu, že databáze je uložena v souboru na disku, takže můžete případně ušetřit nějaké finance vybráním hostingu bez relační databáze. To samozřejmě předpokládá, že programovací jazyk použitý v rámci hostingu (např. PHP) bude mít nainstalovány potřebné extenze a moduly.
Na webu SQLite se také můžeme dočíst, že SQLite bývá používán jako cache dat nad některým větším databázovým systémem (Postgresql, Oracle, atd.). To znamená, že vlastní data jsou uložena ve větším databázovém systému a SQLite obsahuje jen jejich jakýsi obraz, který může být i nějakým způsobem agregovaný. Při změně vlastních dat je samozřejmě nutné data v SQLite, který slouží jako cache, obnovit. Těží se zde hlavně z rychlosti čtení, který SQLite nabízí, a také z faktu, že nasazením cache SQLite, který bude z pravidla běžet na jiném stroji než vlastní velká databáze, dojde ke snížení zátěže hlavního databázového serveru.
Zdrojové kódy i binárky je možné stáhnout z webu samotného projektu, který sídli na adrese www.sqlite.org. Já osobně však preferuji balíčky, které mi nabízí má distribuce. Myslím, že v dnešní době již s podporou SQLite v žádné hlavní GNU/Linuxové distribuci není problém. Osobně používám Debian, takže si ukážeme instalaci právě na něm:
aptitude install sqlite3
Uvedeným příkazem jsme si nainstalovali samotnou knihovnu SQLite a také řádkového klienta sqlite3, který použijeme pro demonstraci použití této databáze.
Novou databázi a tím i soubor, kde bude uložena, vytvoříme opravdu velice snadno zadáním následujícího příkazu:
sqlite3 ourdb.db
Pokud soubor s uvedeným jménem neexistuje, bude vytvořen. Pokud existuje, dojde k připojení k databázi, která je v něm uložena.
Samotná nová databáze je poněkud samoúčelná a je proto potřeba v ní vytvořit několik tabulek, do kterých budeme následně ukládat záznamy.
K tomu, abychom úspěšně vytvořili tabulku v SQLite, ale potřebujeme znát datové typy, které nám SQLite nabízí. Podporované datové typy jsou:
NULL – Hodnota null
INTEGER – celočíselná hodnota
REAL – číslo s plovoucí desetinnou čárkou
TEXT – textový řetězec
BLOB – binární data
Je nutno uvést, že v SQLite je v podstatě jedno, s jakým datovým typem sloupec v tabulce vytvoříte. Do jakéhokoli sloupce mohou být uložena jakákoli data a to bez ohledu na to, jaký typ sloupce byl uveden při vytvoření tabulky. Existuje zde však jedna výjimka a tou je celočíselný primární klíč (INTEGER PRIMARY KEY). V dokumentaci SQLite se dočteme, že toto není chyba a že typ dat definovaný pro sloupec při vytvoření tabulky má být vnímán jako jakési doporučení typu dat, která mají být v daném sloupci obsažena. Osobně toto jako chybu či nedostatek nevnímám. S ohledem na typické nasazení SQLite a jeho důraz na jednoduchost toto lze brát opravdu spíše jako pozitivní věc, která by nás však u vyspělé databáze právem pohoršila. SQLite sám s touto situací opravdu počítá. Pokud budete mít na příklad ve sloupci s typem INTEGER i nějaká textová data a zavoláte na tomto sloupci funkci SUM, dojde opravdu ke korektnímu sečtení číselných hodnot a textová data zůstanou nedotknuta.
Každá tabulka v SQLite obsahuje speciální sloupec nazvaný rowid, který roste od jedničky a slouží k jednoznačné identifikaci řádku v tabulce. Tento sloupec je použit interně samotným databázovým systémem, ale nic nebrání tomu, abychom používali sloupec rowid ve svých dotazech jako ekvivalent pro auto-inkrementální číselný klíč. Speciální sloupec rowid nám může v některých případech ušetřit trochu práce s psaním dotazů, ale bohužel není všemocný. Také je nutno podotknout, že hodnoty rowid ze smazaných záznamů mohou být v budoucnu použity pro nové záznamy.
Jak již bylo napsáno, SQLite podporuje i cizí klíče. Nejdříve je však potřeba vynucení cizích klíčů zapnout. Je to tak údajně z důvodu zpětné kompatibility. Každopádně provedení následujícího příkazu silně doporučuji vždy před začátkem manipulace s daty, čímž můžete předejít nekonzistencím ve své databázi. Aktivaci cizích klíčů provedete tímto příkazem:
PRAGMA foreign_keys = ON;
Cizí klíč z jedné tabulky však nemůže mířit na speciální sloupec rowid do tabulky jiné, takže proto musíme primární klíč zpravidla vytvořit sami. SQLite samozřejmě podporuje i vícesloupcové klíče, ale příklady jejich použití leží podle mého mimo rámec tohoto textu.
Dlužno říci, že k využívání primárních a cizích klíčů nás opravdu nikdo nenutí. Jejich podporu v SQLite vnímám osobně jako úžasné plus, a proto jejich použití silně doporučuji. Myslím, že ve 21. století by referenční integrita i v jednoduché databází měla být samozřejmostí.
Výše jsme zlehka probrali problematiku datových typů a problematiku cizích a primárních klíčů. Myslím, že nám tedy už snad nic nebrání k tomu, abychom si vytvořili několik pokusných tabulek. Na tomto místě již předpokládám, že má uživatel vytvořenu novou databázi a nachází se v sqlite3 konzoli.
Jako příklad pro vyzkoušení si vybereme jednoduchou evidenci majetku. Naší databázovou strukturou budeme chtít popsat kdo vlastní jakou věc. Každá věc má své jméno, vlastníka a unikátní identifikátor. Vlastníkem může být jakákoli osoba. Osoba má své jméno, příjmení a unikátní identifikátor. Nemůže existovat věc, která má neexistujícího vlastníka. Tato struktura vám zní možná až příliš primitivně, ale osobně se domnívám, že dobře demonstruje nabyté znalosti a pro účel tohoto textu se hodí velmi dobře.
Z uvedeného tedy vyplývá, že budeme potřebovat dvě tabulky. První bude tabulka vlastníků, kterou pojmenujeme persons a ne owners, protože můžeme předpokládat, že v budoucnu budeme na tuto tabulku vázat další. Druhá tabulka se bude jmenovat things.
Nejdříve si zapneme podporu cizích klíčů:
PRAGMA foreign_keys = ON;
Následně již můžeme vytvořit první tabulku se jménem persons:
CREATE TABLE persons(id integer primary key autoincrement, name text, surname text);
Dále si můžeme vytvořit druhou tabulku. Bude to tabulka things, která bude navázána na první tabulku persons:
CREATE TABLE things(id integer primary key autoincrement, name text, owner_id integer, FOREIGN KEY(owner_id) REFERENCES persons(id));
Nyní bychom měli mít zapnuté vynucení cizích klíčů a vytvořeny dvě tabulky. Nic nám tedy nebrání v tom, abychom pokročili k naplnění tabulek daty.
Využijeme faktu, že naše tabulky neobsahují žádné záznamy, a otestujeme podporu cizích klíčů v SQLite. Pokusíme se vložit záznam do tabulky things s nějakým fiktivním vlastníkem, který samozřejmě v tabulce persons ještě nemůže existovat.
Pokus o vložení nového záznamu do tabulky things provedeme třeba takto:
insert into things(id, name, owner_id) values(null, 'Zidle', 4);
Tímto příkazem se snažíme o vložení nového záznamu do tabulky things s tím, že nová věc se bude jmenovat Zidle a její vlastník bude osoba s id 4. Kvůli faktu, že v tabulce persons není žádný záznam, naše snaha selže a SQLite nám zobrazí tuto chybovou zprávu:
Error: FOREIGN KEY constraint failed
Není to úžasné? I tak malý databázový systém, jaký je SQLite, nám ohlídá referenční integritu našich dat.
Posuňme se od neúspěšného snažení k pokusu, který by měl skončit úspěchem. Následujícím příkazem vložíme novou osobu do tabulky persons:
insert into persons(id, name, surname) values(null, 'Martin', 'Kumst');
Uvedeným příkazem jsme vložili autora textu do tabulky osob a potenciálních vlastníků. Následujícím příkazem tam vložíme ještě jednoho:
insert into persons(id, name, surname) values(null, 'Theo', 'Kumst');
Uvedeným příkazem jsme vložili do tabulky osob fiktivního nežijícího člověka. Pojďme se nyní podívat na stav dat v tabulce persons:
sqlite> select * from persons;
1|Martin|Kumst
2|Theo|Kumst
Uvedeným příkladem jsme si vypsali data, která jsou uložena v tabulce persons. Také můžeme vidět, že i když jsme do sloupce id ukládali hodnotu null, použila se pro jeho hodnotu číselná řada rostoucí od jedničky. Tento sloupec je primárním klíčem v tabulce persons.
Nyní již můžeme do tabulky things vkládat věci, které bude někdo vlastnit. Vložme jich tam několik:
insert into things(id, name, owner_id) values(null, 'Zidle', 1);
insert into things(id, name, owner_id) values(null, 'Zidle', 1);
insert into things(id, name, owner_id) values(null, 'Zidle', 2);
insert into things(id, name, owner_id) values(null, 'Stul', 2);
Uvedenými příkazy jsme autorovi textu přiřadili dvě židle a fiktivní osobě židli a stůl. Podívejme se tedy nyní na stav dat v tabulce things:
sqlite> select * from things;
1|Zidle|1
2|Zidle|1
3|Zidle|2
4|Stul|2
Vidíme, že data odpovídají tomu, jak jsme je vložili, což je potěšující. Pojďme si však zkusit vypsat k evidovaným věcem rovnou jméno vlastníka:
select things.id, things.name, persons.name as owner_name, persons.surname as owner_surname from things join persons on things.owner_id = persons.id;
1|Zidle|Martin|Kumst
2|Zidle|Martin|Kumst
3|Zidle|Theo|Kumst
4|Stul|Theo|Kumst
V uvedeném výstupu vidíme seznam evidovaných věci i se jménem a příjmením vlastníka. Docílili jsme tak spojením (join) obou tabulek.
Na závěr si ještě znovu otestujeme podporu pro cizí klíče. V prvním testu jsme v tabulce persons nikoho neměli. Nyní tam však máme dva potenciální vlastníky. Pokusíme se však vložit záznam s neexistujícím vlastníkem:
sqlite> insert into things(id, name, owner_id) values(null, 'Rotoped', 200);
Error: FOREIGN KEY constraint failed
Vidíme, že kontrola dodržování referenční integrity opět zafungovala. Díky tomu budou naše data vždy v pořádku.
Popsali jsme si stučně to, co SQLite vlastně je. Následně jsme si nastínili výhody, nevýhody a případné možnosti vhodného nasazení. Potom jsme se podívali, jak se SQLite nainstaluje a jak je v něm možné vytvořit a naplnit daty jednoduchou databázi.
Děkuji všem, kteří dočetli až sem. Doufám, že byl tento text někomu přínosný.
V příštím díle se pokusím probrat příkazy řádkového klienta SQLite a představit některé složitější SQL dotazy, abychom si ukázali, co SQLite umí. Dále bych se chtěl zaměřit na ukázky použití v hlavních programovacích jazycích: Java, PHP a C.
Děkuji za případné dotazy a připomínky.
... ale uvítal bych lepší formátování článku... části sql dotazů a jejich výstupů zanikají v okolním textu... blbě se to "rychlo"čte.
SQLite nemusí být jen soubor na disku, ale je schopna běžet i čistě in-memory. Ano, po jejím zavření se všechna data zničí, ale pokud stavíte aplikaci, kde některá data stačí uchovat jen po dobu běhu a zároveň byste využili SQL dotazy nad nimi, koukněte na tuhle možnost.
Vyvoj Sqlite je celkom aktivny a vdaka tomu distribucne balicky su casto dost zastarale(hlavne prave v Debiane).
Nove verzie casto prinasaju citelny narast vykonu alebo zaujimave optimalizacie. Napriklad verzia 3.8.11 priniesla citleny narast vykonu.
Odporucam sledovat changelog http://www.sqlite.org/changes.html
Sqlite pouzivam dlhe roky a je to vyborna vec. Spomeniem este vyborneho grafickeho spravcu/manazera sqlite databaz zo susedneho polska sqlitestudio.pl
Tesim sa na dalsi diel.
SQLiteStudio je fajn. Pro OSX pak existuje třeba taky jednoduchý a taky free SQLight (aruvan.com).
Když už jsme u toho… Osobně používám pro všechny databáze (včetně sqlite) program Adminer.
Adminer je fajn na zakladne operacie. Ak potrebujes nieco viacej, tak to na specializovany program nema.
S sqlite robim denne(casto jednorazove servisne veci) a do objavenia sqlitestudia(na linuxe som nic schopne nepoznal) mi niektore veci zabrali kopu casu. Z podobnych dovodov chlapik napisal sqlitestudio. Za co mu vdacny(a nielen to). Skoda, ze trochu prestal pracovat na jeho vyvoji. Sqlitestudio prepisal do C++ a niektore nove veci a veci fungujuce v starej verzii ostali otvorene.
Dekuji za reakci. Na nove verze SQLite se urcite podivam. Bylo by zajimave udelat vykonnostni test distribucni a aktualni verze. Podivam se na to v dalsim dilu.
Dobrý den, reším problém, že mám v DB uloženo poměrně velké množství celociselnych 32bit čísel ale SQLite si je i přesto, že je sloupec označen jako INTGER, ukládá jako znaky. Coz je samozrejme hrozne neusporne na misto.Lze nějak vynutit konverzi ? Děkuji za odpověď.
SQLite uses dynamic run-time typing. So just because a column is declared to contain a particular type does not mean that the data stored in that column is of the declared type. SQLite is strongly typed, but the typing is dynamic not static. Type is associated with individual values, not with the containers used to hold those values.
-- Source: https://www.sqlite.org/c3ref/column_decltype.html
Nejspis si ta data ukladate jako retezce, ne jako inty.
Moc pak nechápu, jak to jde dohromady s tímto
INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value.
Omlouvám se špatně jsem si přečetl vaši odpověď. Každopádně, udělal jsem několik testu, ale pokaždé ať jsem se snažil sebevíc se mě to uložilo v tom textovém formátu.
Např. když provedu následující příkazy skrze sqlite browser: create table test (id INTEGER); insert into test VALUES (5); tak ta hodnota 5 je uložena jako řetězec.
Pekny uvod do SQLite. Taky se priklanim k jinemu formatovani prikazu, ale jinak supr. Jen tak dal. Dekuji!
Dobrý den,
je SQLite vhodný i pro přepis informací z matričních knih????
Rekl bych, ze technicky pro to neni zadna prekazka. Mozne duvody proc ne, jsou jine a, rekl bych, i dobre zminene v clanku.
Kolik lidi bude s tim systemem pracovat? Budou pracovat paralelne? Pokud odpovedi na predchozi otazky jsou "hodne" a "ano", tak zkuste urcite neco jineho nez SQLite.
Bez kontextu nedava vase otazka smysl. Je to stejny, jako zeptat se, staci mi vrtacka za 2000?
Pro Vás a Vaši rodinu ano, pro službu v rozsahu MyHeritage ne
Taky může být místo v souboru jen v paměti https://www.sqlite.org/inmemorydb.html :)
Ja ted sqlite nasadil na jednom malem diskusnim webu á narazil na problem, ze dnes hostingy behaji na virtualnich file systemech, ktere nepodporuji zamykani souboru. Sqlite pri konkurencnim pristupu pak kolabuje s chybou disk i/o error.
Ja se tedy v tom jake "virtualni filesystemy ktere nepodporuji zamykani souboru" webhostingy pouzivaji nevyznam, ale zkuste si overit ze databazi mate v adresari kteremu se nezmenila prava tak ze je pro vas read-only - zda se mi ze jsem kdysi narazil na podobny problem.
SQLite je fajn, ale na väčší projekt by som hľadal spôsoby ako použiť Firebird Embed. SQLite v štandarde nepodporuje triedenie podľa národných zvyklostí, takže písmená s diakritikou sú na konci. Je možnosť skompilovať SQLite s ICU, osobne sa mi túto verziu podarilo po dlhom čase na internete nájsť a fungovalo to. Problém ale nastáva v tom, že dodnes som nezistil, že ak použijem index na stĺpec s národnými znakmi, či tento index bude mať štruktúru upravenú pomocou ICU a teda pri použití štandardných SQLite GUI by mohol byť poškodený. Takže nakoniec som od ICU upustil a SQLite používam bez neho. Navyše SQLite nedodáva predkompilovanú verziu s ICU vôbec a pokiaľ si to používateľ sám neprekompiluje musí sa spoľahnúť na kompiláciu niekoho iného. To znamená, že ak použil taký a taký nástroj, možno bude nutné pridať knižnice daného kompilátora atď. Škoda vysokého potenciálu tejto databázy, keď bežnú vec akou je triedenie nezvláda v základe.
Sqlite je viac ako fajn. Na vecsi projekt Sqlite nieje z principu vhodna(spominany chybajuci mulituzivatelsky pristup pri zapise).
To, ze neexistuje predkompilovana verzia s ICU nevidim problem. Asi nieje dopyt a kompilacia je uplne jednoducha. Tiez mi sqlite nedodava predkompilovane verzie pre moje potreby a kompilujem si ich sam.
Tiez neviem preco si dodnes nezistil ci tie GUI aplikacie neposkodia index s ICU. Nevidim v tom problem. Mas takto sancu prispiet do celeho projektu. Sqlite ma urcite mailing list. Zapoj sa donho a pytaj sa. Este som nezazil situaciu aby mi niekto neodpovedal a nemal snahu pomoct. Vyborna vec na zvysenie poznania je len pasivne sledovat takyto mailig list. Clovek ziska vecsi prehlad.
Myslim si, ze potencial sqlite sa vyuziva dostatocne. Je to ina db s inym zameranim a tak je potrebne na to pozerat.
Mam pocit, ze places na nespravnom hrobe.
Takto, ten index funguje, ale či je vždy pri použití v inom type SQLite prepočítaný, to netuším.
Za zminku stoji, a nenasel jsem to zde expl. uvedeno, ze z uvedenych duvodu je SQLite pouzivan jako aplikacni format. Napr. email klient Evolution ho tak pouziva. Osobne ho tak take pouzivam ve spojeni s knihovnou Qt. Vice viz
https://www.sqlite.org/appfileformat.html
Jinak diky za clanek.