UNICORN COLLEGE BAKALÁŘSKÁ PRÁCE Efektivní datové
Transkript
UNICORN COLLEGE Katedra informačních technologií BAKALÁŘSKÁ PRÁCE Efektivní datové struktury pro implementaci aplikace typu Personal Finance Manager Autor BP: Jan Šinkmajer Vedoucí BP: Mgr. Pavel Zeman 2015 Praha Čestné prohlášení Prohlašuji, že jsem svou bakalářskou práci na téma Efektivní datové struktury pro aplikace typu Personal Finance manager vypracoval samostatně pod vedením vedoucího bakalářské práce a s použitím výhradně odborné literatury a dalších informačních zdrojů, které jsou v práci citovány a jsou také uvedeny v seznamu literatury a použitých zdrojů. Jako autor této bakalářské práce dále prohlašuji, že v souvislosti s jejím vytvořením jsem neporušil autorská práva třetích osob a jsem si plně vědom následků porušení ustanovení § 11 a následujících autorského zákona č. 121/2000 Sb. V……………………. dne ……….. …….…………………………… (Jan Šinkmajer) Poděkování Děkuji vedoucímu bakalářské práce Mgr. Pavlu Zemanovi za účinnou metodickou, pedagogickou a odbornou pomoc a další cenné rady při zpracování mé bakalářské práce. Efektivní datové struktury pro aplikaci typu Personal Finance Manager Efficient data structures for the implementation Personal Finance Manager applications 6 Abstrakt Práce si klade za cíl navrhnout a popsat možný způsob ukládání dat, která jsou předmětem aplikací typu Personal Finance Manager (PFM). Návrh je tvořen s ohledem na klíčový předpoklad, že aplikace bude provozována, jako online internetová služba čítající až stovky tisíc klientů a až stovky miliónů transakcí. Předmětem práce je návrh datového modelu, generování reprezentativního vzorku dat a měření vytěžování těchto dat. Tento postup je proveden v relační databázi Oracle a objektové databázi MongoDB, přičemž jsou popsány rozdíly obou přístupů. Klíčová slova: databáze, datové modelování, relační databáze, objektová databáze, finance, účet, osobní výdaje Abstract This work aims to design and describe a possible way of storing data of applications such as Personal Finance Manager (PFM) applications. Design is made with respect to the key precondition that the application will run as an online service (via Internet), counting hundreds of thousands of clients and hundreds of milions transactions. The goal is to design a data model, generate representative sample data and measure extraction of data. This procedure is performed in a relational database Oracle and object database MongoDB, while the differences are described for both approaches. Keywords: database, data modeling, relational database, object database, finance, account, personal costs 7 Obsah Úvod 10 1. 10 Co představují systémy PFM 1.1. Základní popis PFM a historie 10 1.2. Požadavky na systém PFM 11 1.2.1. 2. Funkční požadavky 11 1.2.1.1. Osoby a uživatelské účty 11 1.2.1.2. Účty a transakce 12 1.2.1.3. Osobní nastavení kategorií 13 1.2.1.4. Investice, úvěry, cashflow 13 1.2.1.5. Finanční cíle a rozpočtová omezení 13 1.2.2. Nefunkční požadavky 14 1.3. Neřešené funkčnosti 14 Datový model 15 2.1. Entita 15 2.2. Atribut 16 2.3. Doména 16 2.4. Vztah 16 2.5. Metoda modelování a notace 17 3. Volba vhodného typu databáze 19 4. Předpoklady, generování testovacích dat a metoda měření 20 5. 4.1. Zajištění reprezentativního vzorku dat 20 4.2. Metody měření 23 Návrh a implementace v relačním modelu 24 5.1. Základní popis entit 25 5.2. Účty a pohyb financí 26 5.3. Sumární účty a „memo“ účty 28 5.4. Alternativa jednoduchého záznamu o výdajích a příjmech 29 5.5. Transformace modelu do tabulek a relací 30 5.6. Účetní období 31 5.7. Konstrukce dotazů a nastavení indexů 32 5.8. Partitioning 39 8 5.9. Využití materializovaných pohledů 5.10. Organizace diskového prostoru 6. 42 45 5.10.1. Tablespace 45 5.10.2. Optimalizace využití prostoru pomocí PCTFREE 47 Návrh implementace v MongoDB 47 6.1. Návrh objektů (dokumentů) 48 6.2. Konstrukce dotazů a zavedení indexů 49 6.1. Organizace diskového prostoru 52 7. Závěr 54 8. Seznam použitých zdrojů 56 9. Seznam obrázků 57 10. Seznam tabulek 58 9 Úvod V dnešní době zaznamenáváme výrazný rozmach internetových portálů a projektů, orientujících se na nějakou úzce specifickou problematiku. Řada z těchto internetových technologií poskytuje služby, ke kterým bychom jinak měli obtížný přístup. Svůj rozmach zažívají různé systémy pro vedení poznámek, kalendářů, nástroje pro pořizování, sdílení dokumentů a mnohé další. Kromě samotného technického řešení nám tyto nástroje velmi často poskytují i konkrétní metodiku, jak dané informace spravovat, zálohovat a jak s nimi nakládat. Mezi tyto systémy lze řadit i tzv. manažery osobních financí, neboli PFM aplikace, což je zkratka z anglického Personal Finance Manager. Tato práce se zabývá popisem a návrhem datového úložiště pro aplikace typu PFM a to zejména s ohledem na efektivitu vytěžování těchto dat, snadnou udržovatelnost a rozšiřitelnost. 1. Co představují systémy PFM 1.1. Základní popis PFM a historie Systémy pro správu osobních financí mají významnou roli v každodenním osobním životě nespočtu jejich uživatelů. Jejich cílem je pomoci s plánováním a správou osobních financí, poskytnout přehled o příjmové a výdajové stránce rozpočtu jednotlivce či skupiny osob (typicky domácností). Veškeré osobní či rodinné finanční operace jsou kategorizovány do předem definovaných skupin, čímž poskytují přehled o struktuře výdajů a příjmů domácnosti. Umožňují vytyčení finančních cílů a sledování jejich naplnění. Pomáhají v rozhodování při investicích a sledování jejich výnosnosti v čase. Poskytují nástroje, které pomáhají rozhodovat o nutnosti zadlužení, či splácení úvěrů. Jmenovaných funkčností je celá řada. Pro inspiraci je vhodné nahlédnout na existující řešení a rozsah jejich funkčnosti. Historie systémů se začíná psát již v roce 1983, kdy Scott Cook a Tom Proulx založili společnost Intuit a v tehdejší prudce se rozrůstající obci vlastníků osobních počítačů vycítili příležitost uvést aplikaci pro správu osobních financí. Jejich produkt se jmenoval Quicken a na několik dalších let se stal etalonem ve světě PFM. V roce 1990 vydává Microsoft svou vlastní PFM platformu nazvanou Microsoft Money, kterou staví právě na spolupráci s firmou Intuit. 10 Tato práce se zabývá především online aplikací, tedy řešením, kde stejnou aplikaci obsluhují řady uživatelů a data jednotlivých uživatelů musí být izolována, přestože jsou ukládána ve stejné databází. Takto pracující online PFM vznikají kolem roku 2006 a jsou jimi systémy Wesabe a Mint. Nakonec ale původní firma Intuit skupuje jak Mint, tak Wesabe, který posléze silně prosazujícímu se Mintu ustupuje. 1.2. Požadavky na systém PFM V následující kapitole je shrnuto, jaké vlastnosti a funkčnosti lze od PFM systému očekávat, tedy konkrétně jaké vlastnosti a funkčnosti budeme uvažovat ve fázi tvorby datového modelu. Výčet nemá ambice rozkrýt kompletní sadu případů užití (use cases) nebo zahltit tuto práci nespočtem elementárních funkčních a nefunkčních požadavků. Jakkoliv jsou tyto výstupy běžně vnímány jako nedílná součást analýzy a návrhu systémů, zde se text omezuje na shrnutí nejdůležitějších oblastí, které by měl systém pokrývat. Jednotlivé oblasti tedy představují: 1.2.1. Funkční požadavky 1.2.1.1. Osoby a uživatelské účty Jelikož je v této práci pojednáváno o online PFM systému, je třeba zavést principy autentizace a autorizace. Je třeba evidovat identitu klienta, informace o něm a zajistit správu jeho osobního nastavení. Klient se do systému prvotně registruje pomocí svého emailu. Email by tak měl mít schopnost jednoznačně identifikovat klienta. Stejně tak je nezbytné evidovat osoby, které mají přístup ke správě systému, zajistit oblasti a operace, ke kterým má uživatel přístup. K této funkčnosti lze vhodně využít uživatelských rolí, které se skládají z elementárních oprávnění. Jednotliví uživatelé jsou pak přiřazování právě těmto rolím. Je třeba brát v úvahu i tu možnost, že osoba správce může být současně i klientem a to tak, že je v systému vedena pod jednou identitou (osobou). Potřeba sledovat výdaje domácností představuje nutnost zavést vazby mezi osobami, či určitá uskupení, kde zapsané výdaje a příjmy jednotlivců dávají možnost sestavit celkový pohled na finanční situaci domácnosti. 11 1.2.1.2. Účty a transakce Aplikace pro správu osobních financí poskytuje především přehled nad všemi finančními operacemi. K tomu je zapotřebí zachytit jednak účty, na kterých finanční operace probíhají a dále samotný pohyb financí. Účty nepředstavují pouze účty bankovní, ale jakýkoliv jednotný zdroj určitého množství peněz v určité měně. Lze je také vnímat jako saldo finančních operací (příjmových a výdajových) nad určitým zdrojem financí. Účet tak může být hotovost v peněžence, investice, účet v bance, poskytnutá půjčka jiné osobě. Úvěr je v podstatě také účtem se záporným saldem. Každopádně je nezbytné rozlišovat mezi sebou typy účtů, tedy co je účtem v bance, co hotovostí v peněžence, co úvěrem atp. Klíčové je ovšem rozlišit bilanční účty a příjmové účty 1. Bilanční účet, jak již název napovídá, představuje účet, jehož bilanci sledujeme. Chceme tedy znát stav účtu. Oproti tomu příjmový účet je účtem cizím, jehož stav není třeba znát. Transakce z něj přicházejí, nebo na něj odcházejí, ale neznáme jejich celkové saldo. Transakce představuje událost, ke které dochází na účtu a souvisí s uskutečněním pohybu financí. Je nutné rozlišit dva základní směry pohybu, tedy příjem a výdej z účtu. Zvláštním případem je pohyb z jednoho účtu na jiný účet. Tedy např. reálně situaci, kdy dojde k vyzvednutí hotovosti z banky (a jejímu přesunu do peněženky). Je možné vnímat takovou transakci jakou jediný pohyb se svým zdrojem a cílem, či jako dva samostatné protisměrné účetní záznamy – příjmový a výdajový, což představuje uvažování a zápis podobný účetní praxi. V tomto pojetí má každá transakce dva účty. Účet, ze kterého jsou finance odčerpány a účet, na který jsou připsány. V neposlední řadě bude třeba samotnou transakci klasifikovat, tedy určit o jaký pohyb se jedná. Jistě je třeba vnímat jinak transakci, která vzniká z důvodů výdaje financí, a jinak například transakci, která narovnává stav účtu z důvodů zjištění rozdílného stavu na skutečném účtu v bance. 1 FOWLER, Martin: Analysis Patterns – Reusable Object Models. ,Addison Wesley, 1998, s. 123 12 Vedle tohoto typu transakce bude chtít sám klient své výdaje i příjmy kategorizovat. Tedy zařadit, zda se jedná o výdaje za kulturu, potraviny atp. Stejně tak u příjmů lze sledovat jejich strukturu, zda se jedná o příjmy ze závislé činnosti, z pronájmu, úroky z úspor atp. 1.2.1.3. Osobní nastavení kategorií V předchozím odstavci je zmíněna kategorizace transakcí, na kterou je třeba klást také určité nároky. V první řadě si každý klient vytváří vlastní kategorizaci, tedy vlastní strukturu příjmů a výdajů, kterou chce sledovat. Dále pak bude třeba zachytit hierarchii ve výdajové struktuře. Je jistě zajímavé sledovat odděleně výdaje za palivo, servis automobilu a jeho pořízení, stejně tak jako může být významné sledovat celkové náklady za automobil. Je tedy vhodné, aby systém umožnil začlenit dílčí kategorie pod jednu souhrnnou. 1.2.1.4. Investice, úvěry, cashflow Investice, stejně tak jako úvěr, představují specifickou variantu účtu, ke kterému jsou zaznamenávány období, úroková míra, či předpokládaná výnosnost investice a další. Takto definované parametry pak umožňují zobrazit projekci předpokládaných výnosů, či splátek v budoucnosti. Aby bylo možné získat ucelenou představu a predikci vývoje stavu účtů, umožní systém zadávat i pravidelné opakující se příjmy a výdaje. K tomu je v systému třeba pořídit pouze předpis těchto pravidelných transakcí, zahrnující časové období, periodicitu a částku. Investice, úvěry i předpis pravidelných transakcí posléze vygenerují transakce specifického prediktivního typu, které pak napomáhají k reportingu osobního, či domácího cash-flow a umožňují náhled na stav financí v jakémkoliv bodě časové osy. 1.2.1.5. Finanční cíle a rozpočtová omezení Zde se jedná o jednoduché vytyčení časových milníků, které mohou být pravidelné (např. měsíční), či ojedinělé. Cíl je možné, ale ne nezbytně nutné, definovat k jedné, nebo více kategoriím. Stejně tak je možné cíl provázat s konkrétními 13 účty. Cíle jsou pak dvojího typu. Tím prvním chceme dosáhnout určitého stavu na účtu, nebo naopak nechceme překročit stanovenou částku v součtu všech transakcí. Taková konstrukce by měla být schopná modelovat případy, kdy např. chceme dosáhnout určitých celkových úspor, popř. úspor na konkrétním účtu, nebo v druhém případě nechceme, aby např. výdaje v restauracích měsíčně překročily zvolenou částku. 1.2.2. Nefunkční požadavky Při zopakování klíčového atributu tohoto systému, tedy že se jedná o online systém dostupný velkému množství uživatelů, vyvstávají další požadavky, na které je třeba myslet v rámci návrhu databázové struktury. Tím prvním je skutečnost, že data mnoha uživatelů, která spolu nesouvisí, jsou ukládána v jedné databázi. To samo o sobě představuje nutnost zajistit a správně určit vlastníka jakýchkoliv dat. Dalším požadavkem bude zcela nesporně požadavek na výkonnost systému. Systém, který je díky fenoménu internetu celosvětově dostupný, může předpokládat řádově stovky tisíc, až miliony uživatelů (jako je tomu ve skutečnosti v případě aplikace Mint) a potažmo miliardy transakcí. Vyhledávání, zpracovávání a agregace dat tak operují se skutečně velkým množstvím záznamů a nároky na efektivní strukturu jsou tak zřejmé. Významným požadavkem z hlediska návrhu je i počet evidovaných finančních transakcí na jednoho uživatele. Většina dotazů do databáze se totiž týká právě jednoho uživatele a tak je tento předpoklad významný z hlediska dotazů na agregovaná data. Protože se jedná o aplikaci pro správu osobních financí, není předpokládán počet operací za měsíc větší než v řádu několika desítek, či stovek. 1.3. Neřešené funkčnosti Tato práce se věnuje jádru problematiky správy osobních financí. Celé řešení by mělo obsahovat i spoustu návazností. Řada obdobných služeb může být klientům úplně, či částečně zpoplatněna. To do celkového řešení vnáší potřebu zachytit poskytované služby, jejich objednávky, vyúčtování, platby a mnohé další. Životaschopnost takového řešení může být spjata s příjmy z reklamního prostoru a obchodních sdělení. Tyto budou pravděpodobně kontextově provázány se sledovanou aktivitou uživatelů, jejich výdaji v určitých oblastech a jejich zájmy o finanční 14 produkty. Protože obchodní model takového řešení může být skutečně různorodý, není součástí řešení obsaženého v této práci. Práce neřeší ani technické otázky, jakými jsou např. úložiště sessions a mnohé další otázky související se samotným nasazením na provozní infrastrukturu. 2. Datový model Stěžejní disciplínou, která je nezbytná při návrhu úložiště dat, je datové modelování a jedním ze základních výstupů práce je právě datový model. Tato kapitola popisuje, co lze vnímat jako datový model, včetně podrobného popisu jeho součástí. Datový model je abstraktní částí výsledné databáze. Ve své podstatě zachycuje myšlenkový model problémové domény, její elementární prvky a definici vztahů mezi těmito prvky. Jinými slovy je složen z entit, atributů, domén a vztahů. Tyto prvky jsou popsány v dalším textu této kapitoly. 2.1. Entita Je v celku nesnadné vymezit pojem entity pomocí přesné definice. Entita může být prakticky čímkoliv, tedy jakýmkoliv konkrétním či abstraktním prvkem, o kterém potřebujeme uchovávat nějaké informace. Podle toho hovoříme o konkrétních, či abstraktních entitách. Pokud tedy uvažujeme problémovou doménu aplikací PIM, pak entitou budou zcela jistě prvky jako účet, vlastník účtu, rozpočet, tedy podstatná jména z oblasti osobních financí, které chceme datově podchytit. Entitami budou ale i některá slovesa problémové domény, o kterých chceme uchovávat informace. Příkladem může být např. slovo nakupovat, tedy entita nákup. U těchto entit je třeba dávat pozor na jejich význam, tedy ke komu se vztahují. Např. prodej je různým pohybem financí z pohledu dodavatele a odběratele a slova prodej a nákup mohou mít stejný význam. V oblasti osobních financí může být takovou problematickou entitou příjem na účet, který je současně výdajem z jiného účtu. Velmi důležitou entitou jsou vztahy mezi jinými entitami. Příkladem může být vztah faktury k objednávce. Takový vztah může nést pouhou informaci o vztahu, popř. ji rozšiřuje o další atributy. 15 2.2. Atribut Atributy přestavují jednotlivé nositele elementární informace o entitě. Je to například jméno osoby, datum narození, či adresa. Konkrétně na atributu adresy lze dobře ukázat, jakou dělitelnost informace v systému chceme udržet. Adresa sama může být jedním atributem, ve kterém je uložen ucelený několikařádkový text adresy včetně ulice, čísla popisného, města, PSČ atd. Pokud ovšem v systému chceme pracovat samostatně např. s PSČ, je třeba mít tento atribut veden samostatně. Pokud ovšem chceme např. sledovat historii adres, dojdeme v čase k přesvědčení, že adresa nemusí být nezbytně atributem, ale můře být samotnou entitou o čemž se přesvědčíme později. 2.3. Doména Pojem doména se vztahuje k atributu a představuje obor hodnot atributu, kterých může nabývat. Někdy je tento pojem mylně zaměňován s datovým typem atributu. Obor hodnot má totiž širší význam. Pokud v našem návrhu systému budeme např. uchovávat titul před jménem osoby, pak typem atributu bude pravděpodobně řetězec o délce čtyřech znaků. Přípustný obor hodnot může být ale mnohem užší a může se omezovat na konkrétní existující tituly (MUDr, RNDr, Ing.) 2.4. Vztah Vztahy se definují mezi různými entitami. Jedná se o jakési asociace, které lze mnohdy jednoduše vyjádřit větou jako „klient vlastní účet“, která definuje vztah mezi klientem a účtem, tedy mezi dvěma účastníky vztahu. Vztah, ve kterém vystupují právě dva účastnící, je nejběžnější a hovoříme o něm jako o binárním vztahu. Známe ale i vztahy se třemi účastníky a ze světa financí tu lze uvést například transakci z pokladny na bankovní účet, kde vystupují tři entity: bankovní účet, pokladna a transakce (jako nositel informace o pohybu peněz). Vztah se třemi účastníky nazýváme ternárním vztahem. Počtu účastníků ve vztahu pak říkáme stupeň vztahu. 16 Entita může být ve vztahu se sebou sama, což představuje zvláštní případ binárního vztahu, který je užíván tam, kde chceme docílit jakési hierarchie. V našem případě tak např. budeme chtít rozdělit osobní výdaje do nějakých kategorií tak, aby bylo možné sledovat osobní výdaje v určité oblasti. Pokud připravíme kategorie „servis automobilu“ a „palivo“, budeme možná v čase chtít sledovat i celkové výdaje za automobil. V hierarchii kategorií tak zavedeme další kategorii „automobil“, která je nadřízená kategoriím „servis automobilu“ a „palivo“. Dalším parametrem vztahů, který je třeba vzít v úvahu, je násobnost vztahu neboli multiplicita. Hovoříme o vztahu jedna k jedné (1:1), jedna k více (1:N) a více k více (M:N). Někdy se tento termín mylně zaměňuje s termínem kardinalita. Kardinalita ovšem představuje konkrétní výskyt počtu vztahů. Vztah jedna ku jedné bude v našem případě představovat vztah entit uživatel a klient, pokud předpokládáme, že klient nemůže mít více uživatelských účtů. Za vztah jedna k více můžeme dosadit vztah entity výdaje (účetní záznam) k entitě účet. Tedy finanční pohyb, který představuje, že jsme z peněženky vynaložili na nákup určitou částku, je přiřazen právě jednomu účtu. Naopak na tomto účtu registrujeme více výdajů (1:N). V aplikaci pro správu osobních financí budeme pracovat s entitou rozpočtového omezení, které představuje nějaký finanční limit výdajů v určitých výdajových kategoriích. V tomto případě lze demonstrovat vztah více k více, kdy rozpočtové omezení a výdajová kategorie jsou právě v tomto vztahu M:N. Je zcela zřejmé, že k výdajové kategorii pořizujeme v čase několik rozpočtových omezení. Naopak jsme konstatovali, že pro rozpočtové omezení můžeme vyčlenit několik výdajových kategorií. Vlastností vztahu, kterou je třeba také zmínit, je účast entit, která může být úplná, nebo částečná. Úplná účast entity je tehdy, pokud entita nemůže existovat sama o sobě bez účasti ve vztahu. 2.5. Metoda modelování a notace Z řady existujících metod datového modelování je v této práci zvolen velmi rozšířený Entity Relationship Diagram (ERD), který se v softwarovém inženýrství využívá pro abstraktní a konceptuální znázornění dat. Znázornění pomocí ERD tak slouží především k popisu informační potřeby nebo k popisu typu informace uložené v databázi. Další etapy v tvorbě databázového modelu představují mapování konceptuálního modelu do jeho logické a následně fyzické podoby. 17 Existuje mnoho konvencí pro tvorbu ER diagramů, počínaje notací Chenovou z roku 1976 až po UML. Poměrně rozšířenou notací, která je použita dále v této práci, je tzv. notace „Crow’s foot“. Ta znázorňuje entity pomocí boxů. Ty jsou dále propojovány čarami, které reprezentují vztahy. Symboly na obou koncích těchto spojnicových čar vyjadřují multiplicitu. Příkladem na obrázku 2-1 je binární vztah klienta k bankovnímu účtu, který má v tomto případě multiplicitu 1:N. Obrázek 2-1 Vztah dvou entit znázorněný v ER diagramu. Relace je modelována tím, že vztah rozšíříme o primární relaci (Klient) a cizí relaci (BankovniUcet). Maximální počet instancí jedné entity, které můžeme asociovat s jednou instancí jiné entity, nazýváme kardinalitou vztahu 1. Pojmy stupeň a kardinalita mají odlišný význam u vztahů a relací. V záhlaví boxů je patrný název entity, pod ním jsou jednotlivé atributy a spojnice definuje vztah mezi entitami a jeho kardinalitu pomocí symbolů. Výčet symbolů, které určují kardinalitu, jsou zachyceny na obrázku 2-2. 1 RIORDAN, M, Rebecca: Vytváříme relační databázové aplikace, Computer Press, Praha 2000, str. 45 18 Obrázek 2-2 notace kardinality vztahů Symboly vyjadřují jaký je maximální počet instancí jedné entity asociovaných s entitou druhou. První symbol označuje, že na této straně je očekáván právě jeden objekt. Další symbol představuje více možných objektů. Třetí v řadě představuje kombinaci, tedy žádný nebo jeden objekt (nepovinnost). V posledním případě jde opět o kombinaci – očekáváme jeden, či více objektů. V této kapitole jsme stručně shrnuli pojmy a notaci, která bude využívána v dalších kapitolách. 3. Volba vhodného typu databáze Při volbě vhodného úložiště dat se naskýtá celá řada možností, počínaje systémem souborů, přes relační po objektové databáze. Nalézt vhodné řešení může pomoci matice databázových systémů 1. Ta vychází z ohodnocení složitosti dat a potřeby dotazovat se na data (vyhledávat). Na obrázku 3-1 jsou zachyceny jednotlivé kvadranty odpovídající kombinacím požadavků na systém. 1 STONEBRAKER, Michael, BROWN Paul: Objektově relační SŘBD, analýza příští velké vlny, BEN – technická literatura, Praha 2000, ISBN 80-86056-94-5,str. 19 19 s dotazy bez dotazů Jednoduchá data Složitá data Relační DB Objektově-relační DB Systém souborů Perzistentní jazyk Obrázek 3-1 matice DB systémů Z tohoto rozdělení je zřejmé, že aplikace pro správu osobních financí bude potřebovat silné nástroje pro vyhledávání a dotazování do databáze. Ve volbě vhodného databázového nástroje lze hledat mezi relačními a objektovými systémy řízení báze dat (SŘBD). Relační model je naprosto rozdílný od objektového. Relační databáze interpretují data ve formě jednoduchých dvourozměrných tabulek. Jejich mapování do složitějších struktur objektové aplikace však bývá obtížné. Přesto se jedná o nejčastější a nejvíce podporované implementace databází. Oproti tomu mladší objektové databáze přinášejí přímé ukládání struktur objektů a jejich vazeb a vlastnosti známé z objektově orientovaných programovacích jazyků (dědičnost, polymorfismus, zapouzdření). Nenajdeme zde ale jednotný směr vývoje a společný standard. 4. Předpoklady, generování testovacích dat a metoda měření 4.1. Zajištění reprezentativního vzorku dat Aby bylo možné objektivně posoudit efektivitu navržených struktur, je třeba tyto struktury naplnit relevantními daty. Objem dat přitom vychází z dříve stanovených předpokladů, tedy předpokládaného počtu uživatelů a počtu měsíčních transakcí. 20 Způsob generování v databázi Oracle je postaven na jazyce PL/SQL (Procedural Language/Structured Query Language). Tento jazyk rozšiřuje standardní jazyk SQL o konstrukce procedurálního programování. Zejména díky možnosti iterativních operací a generátoru náhodných čísel lze docílit vygenerování požadovaného reprezentativního vzorku dat. V jednotlivých přiložených procedurách (v přiloženém souboru 04_functions_gen.sql) jsou zachyceny bloky kódu PL/SQL generující data a musí být spuštěny v následujícím pořadí: funkce GENERATEPERSONS – generuje data 100 000 klientů, jméno a příjmení jsou náhodně generované řetězce. Datum narození je náhodně generováno v rozsahu 1.1.1930 - 1.1.2005 funkce GENERATEACCOUNTS – pro každého klienta generuje náhodně jeho vlastní účty v počtu 1 až 10. Dále generuje nákladové kategorie v počtu 7 až 35 a příjmové kategorie v počtu 1 až 5. Všechny účty jsou uvažovány v jedné měně. funkce GENERATETRANSACTION – pro každého klienta generuje náhodně transakce z účtu na účet v rozpětí cca dvou let (1.1.2013 - 31.12.2014). Transakce jsou v počtu 500 až 2400, což představuje různou aktivitu klientů v systému. Hodnota 2400 vychází z teoretického předpokladu: až 100 transakcí měsíčně po dobu 24 měsíců. Každá desátá transakce je příjmem v hodnotě 5 000 až 150 000 na náhodný účet. Ostatní transakce jsou výdajem z náhodného účtu na náhodnou nákladovou kategorii v hodnotě 10 až 2000. Tímto způsobem může dojít k nesmyslným záporným zůstatkům na účtech, což je ale z hlediska sledování efektivity struktur nepodstatné. Způsob generování dat po jednotlivých klientech nemusí ovšem nutně odpovídat struktuře reálné produkční databáze. V praxi budou data ukládána postupně v čase a nikoliv po jednotlivých klientech. Proto je nakonec v práci použita následující metoda GENERATETRANSACTIONS2 funkce GENERATETRANSACTIONS2 –tato funkce postupně v čase generuje 100 miliónů transakcí a to tak, že nejprve náhodně vybere klienta a poté zvolí náhodně 2 jeho účty, mezi kterými provede transakci. V průběhu iterace se zvyšuje datum transakce tak, aby bylo dosaženo simulace postupného ukládání dat v čase. funkce GETRANDOMDATE – je pomocnou funkcí, kterou využívají další funkce pro generování dat. Generuje náhodné datum v určeném rozsahu. 21 Jakkoliv není předmětem práce docílit efektivního importu, či generování dat, je velmi vhodné odstranit patřičné indexy u tabulek, do kterých se právě provádí generování s masivním zápisem. To platí zejména v případě generování transakcí. Tvorba struktur indexů v době masivního zápisu generovaných dat velmi prodlužuje celkovou dobu operace. Protože součástí této práce je i porovnání relační databáze Oracle s objektovou databází MongoDB, je vhodné zajistit v obou systémech identický vzorek dat. Využijeme tedy data vygenerovaná v databázi Oracle. Přestože na trhu existují systémy, které umožňují snadnou migraci dat z Oracle do MongoDB, zde se v jednoduchých konstrukcích nabízí poměrně triviální způsob přenosu. Protože databáze MongoDB pracuje s daty ve formátu JSON, budeme se snažit zajistit na straně Oraclu zformovat výstup do této struktury. Zdrojem bude specifický select odpovídající struktuře dat v MongoDB. Exportní soubor pro MongoDB je vytvořen pomocí přesměrování výstupu příkazové konzole v Oracle (sqlplus) do textového souboru. Spolu s dalšími příkazy zajišťujícími formátování, vypnutí odezvy atp. je dosaženo kýženého výstupu. Takto např. vypadá příkaz pro export transakcí a účetních záznamů: set echo off set pagesize 0 set term off set heading off col DPdz format a50 spool D:\clients.json; select '{ "_id" : ' || idclient || ', "name" : "' || name || '", "validfrom" : {"$date" : "' || to_char(validfrom,'yyyy-mm-dd') ||'T00:00:00.000+0100"}, "validto" : {"$date" : "' || to_char(validto,'yyyy-mm-dd') ||'T00:00:00.000+0100"}}' from client; cle col spool out set pagesize 100 set term on Další skripty jsou obsaženy v příloze (export_to_mongodb.sql), Výstupem je struktura ve formátu JSON (je potřeba pouze z konce textu odmazat informaci o počtu dotazovaných záznamů, která je automaticky přidána na konec výstupu). Takový formát je pak možné importovat do MongoDB pomocí nativního nástroje MongoImport a to tímto způsobem: mongoimport --db pfmtest --collection clients --file d:\clients.json 22 4.2. Metody měření Efektivitu struktur lze vnímat z mnoha pohledů. Tou nejsledovanější bude pravděpodobně rychlost budoucího systému, tedy rychlost operací a zejména rychlost, s jakou mohou být vykonány složitější dotazy na agregovaná data. Podstatná může být i efektivita související s objemem uložených dat. V neposlední řadě lze srovnávat i náročnost na implementaci zvoleného řešení. Co se týká rychlosti a prostoru, jde o měřitelné ukazatele a lze je tak dále objektivně srovnávat. Pro měření rychlosti vybereme některé typické funkčnosti systému, které dostatečně reprezentují způsob, jakým se budeme dotazovat na data. Z pohledu systému pro osobní správu financí lze jako typické vnímat tyto případy užití, související s konkrétním požadavkem na data: A. Přehled nákladů v jednotlivých nákladových kategoriích za určité období. V tomto případě se jedná o nejběžnější a stěžejní výstup PFM aplikací. Dotazovaným obdobím bývá zpravidla kalendářní měsíc, či rok. Data jsou v tomto období agregována na základě výdajových kategorií. B. Celková finanční bilance klienta. Představuje kumulovaný stav všech účtů vztažený k aktuálnímu času (či k jinému času v minulosti). C. Přehled transakcí za určité období - s filtrací dle účtu a rozmezí částky. Tyto funkčnosti reprezentované dotazem do databáze jsou předmětem měření. Měření probíhá na stejném PC s omezením paralelně běžících procesů a aplikací. Specifikace testovacího PC Procesor: Intel® Core(TM) i7-4710HQ 2,5 GHz – 4 jádra Pamět: 16GB OS: Windows 8.1 64Bit Disk 1TB – pro testování vyhrazen a zformátován prostor 512 GB MongoDB 3.0 Standard Oracle database 11g 11.2.0.1.0 Enterprise Edition Nastavení databáze Oracle: Automatic memory management – enabled Memory target – 6 528 MB Systém global area (SGA) – 4 256 MB (aktuálně automaticky přidělená) Program global area – 2 272 MB (aktuálně automaticky přidělená) 23 Měření je provedeno vždy více (minimálně 5) tak, aby byla vyloučena chyba dlouhotrvajícího selectu z důvodů intervence jiného procesu, či aktivity disku. Výsledná časová hodnota uvedená v práci je pak mediánem ze všech provedených měření. Protože dotazovaná data jsou v databázi cachována, je třeba v rámci jednotlivých měření cache paměť vyprázdnit. Další významnou hodnotou, kterou lze sledovat v souvislosti s výkonností systému, je objem diskových operací. Hodnoty, jakými jsou počet přečtených bytů, či logických bloků disku mohou napovědět, nakolik může výsledné trvání dotazu ovlivnit rychlost disku. 5. Návrh a implementace v relačním modelu V této kapitole je popsáno konkrétní řešení systému PFM v databázi Oracle spolu s popisem jednotlivých rozhodnutí a naznačením některých možných variant řešení. V jednotlivých funkčních oblastech jsou nejprve nalezeny klíčové entity, určují se vztahy mezi nimi. Mezi nalezenými entitami jsou v práci vybrány takové, které jsou klíčové v otázce efektivity budoucího systému. Je např. zřejmé, že PFM systém by měl obsahovat část týkající se uživatelů, jejich uživatelských účtů a oprávnění, nicméně pokud se zabýváme otázkou efektivity u velkého objemu dat, pak je to oblast nezajímavá. Na úrovni návrhu tabulek je pak řešena klíčová část celého systému a to oblast účtů a finančních transakci. Pro tuto oblast jsou pak vyjmenovány atributy, určeny kandidátní, primární a cizí klíče. Výsledkem je konkrétní podoba datového modelu a DDL skript pro vytvoření struktury v databázi Oracle. Na obrázku 5-1 je zachycen celkový doménový model aplikace. 24 class Domain Model UserAuthority RoleAuthority UserRole UserRoleUser UserProfile Family hotovost banka uver Person AccountCategory IsFormer :bool Account - AccountT ype :string IdAccount :long Inv estment AccountType, bilancni transakcni Proj ection Loan Cashflow AccEntry LimitAccountCategory LimitAccount - IdAccount :long Amount :decimal AmountInNativeCurrency :decimal Transaction Proj ectedTransaction TransactionType Limit - Validfrom :DateTime ValidT o :DateTime Currency Vyber, prevod, narovnani uctu, vydeh Obrázek 5-1 entity PFM systému 5.1. Základní popis entit Person – entita nesoucí údaje o osobě Client / Family – entita zastřešující skupinu osob, která manipuluje se stejnými účty (např. rodinu). Account – účet, ať už se jedná o depozit v bance, hotovost, či např. úvěr. Rovněž ale přestavuje protiúčet finanční transakce, tedy nákladový účet, či příjmový účet. AccountCategory – typ účtu, tedy např. hotovost, bankovní účet, úvěr, investice. Současně obsahuje příznak, zda se jedná o bilanční účet (vlastní 25 účet, kde sledujeme stav), či „statement“ účty, tedy protiúčty, kde nesledujeme stav (nákladové a příjmové účty). AccEntry – položka účetního záznamu. Odepisuje, či připisuje částku na účet (což je dáno znaménkem operace) k určitému datu. Transaction – zapouzdřuje celou finanční operaci pohybu peněz, tedy většinou dva účetní záznamy (peníze odchází z fyzického účtu na nákladový účet). Lze realizovat transakce i na více účetních záznamech. TransactionType – typ transakce může být standardní, vyrovnávací transakce účetního období (viz kapitola 5.6. Účetní období). Currency – slouží pro zavedení účtů v různých měnách. Projection – předpis pro projekci financí do budoucna. U investic a půjček obsahuje úrokovou sazbu, délku období atp. Specializací je také entita CashFlow, která obsahuje předpis pro částky, které se pravidelně platí v čase, či pravidelně odcházejí z účtu. Limit – slouží pro rozpočtová omezení jednotlivých nákladových účtů, či jiná upozornění při překročení částky na účtu. UserProfile – entita udržující informace o přihlašovacích údajích osoby. UserRole – uživatelská role v systému, která zahrnuje výčet oprávnění. UserAuthority – elementární oprávnění, ze kterých se skládají uživatelské role. 5.2. Účty a pohyb financí Zachycení finančních toků, stavů jednotlivých účtů a přehledu vynaložených prostředků v různých výdajových kategoriích tvoří jádro osobních finančních systémů. Účet udržuje stav věcí, které mají nějakou hodnotu vyjádřenou v penězích. Snížit, či navýšit stav účtu lze pomocí jednotlivých operací na účtu. Tyto operace pak zajišťují kompletní historii účtu. Velmi jednoduchý model účtů je zachycen na obrázku 5-2. Představuje entitu účtu, na které jsou zachyceny jednotlivé účetní záznamy. Množství, či finanční částku nese atribut amount, přičemž skutečnost, zda se jedná o příchozí, či odchozí operaci je dána kladným, nebo záporným znaménkem množství. Další dva atributy jsou časové. V informačních systémech často rozlišujeme dvě časové značky pro událost. Jednou je okamžik, kdy k daná událost reálně nastala, druhou pak 26 okamžik, kdy byla tato událost zaznamenána do systému. Zachycení obou časů je velmi důležité například u zpětně zaznamenaných operací. class ucet-zaznam Entry Account - amount :quantity timeChanged :timepoint timeBooked :timepoint Obrázek 5-2 účet a účetní záznam Tento zjednodušený pohled má svá úskalí. Převod z jednoho účtu na jiný účet bychom museli zachytit jako dva separátní účetní záznamy na dvou účtech. Z jednoho účtu částku odebíráme a na jiný účet stejnou částku přičítáme. Snadno si lze přestavit, že každá finanční transakce má ve skutečnosti dvě strany, tedy v dříve používané sémantice dva účty: zdroj a cíl. Položky odečtené z jednoho účtu musí být načteny na jiný účet. Položky nemohou samovolně vzniknout, ani zaniknout. Pro tento účel je zavedena entita transakce. Transakce zapouzdřuje účetní záznamy obou účtů: zdrojového a cílového. Vztahy entit jsou zachyceny na obrázku 5-3. class transakce Entry Account Transaction 2 - amount :quantity timeChanged :timepoint timeBooked :timepoint Obrázek 5-3 transakce Součet účetních záznamů v jedné transakci je vždy roven nule. Z jednoho účtu částka odchází, na jiný účet je připisována. Tento systém zachycení finančních pohybů vychází z běžné účetní praxe a pomáhá udržet konzistentní informaci o pohybu financí. Lze namítnout, že jeden ze dvou účtů v transakci nám nemusí být znám. Pokud např. pořizujeme lístky do divadla, odchází peníze z reálného účtu (peněženka) na účet obchodníka. Ten v systému zachycen není. Jako účet může být ale vnímána i nákladová kategorie, za kterou chceme své výdaje sledovat. 27 V tomto případě jsou to tedy „výdaje za kulturu“, které představují samostatný nákladový účet. 5.3. Sumární účty a „memo“ účty Pokud je využíván systém účtů a transakcí a zajímá nás bilance účtu, dojdeme velmi často k potřebě sledovat bilanci souhrnně za skupinu účtů, které spolu nějak souvisí. Např. v osobních financích můžeme sledovat náklady na údržbu vozu a náklady na spotřebu paliva. Souhrnně však chceme sledovat celkové náklady za údržbu a provoz vozů. Jedná se o nákladové účty, u kterých je využívána hierarchická struktura, zachycená na obrázku 5-4 class sumarni ucet Account - entries [abstract] balance :quantity Transaction Entry Detail Account entries 2 Summary Account Obrázek 5-4 sumární účty a detailní účty Sumární účet se zde může sestávat z jednotlivých detailních, ale i sumárních účtů. K pohybu financí dochází pouze na detailních účtech. Pohyb na sumárních účtech je odvozen z pohybu na detailních účtech. V praxi je třeba řešit i specifický typ finančních transakcí, na jejichž základě vzniká jiný závazek. Typicky se jedná o daně. Na účet sloužící k podnikání připíšeme částku, ale současně chceme vědět, že nám celá částka nenáleží a v budoucnu bude třeba odvést daň z přidané hodnoty. Vzniká tedy závazek tuto daň uhradit. K zachycení takového případu poslouží specifický „memo“ účet. Ten eviduje objem peněz, ale nejedná se o reálné peníze, což mimo jiné znamená, že nemůže dojít k převodu z klasického účtu na memo účet a obráceně. V případě vzniku daňového závazku bude vypadat příklad následovně: na účet vyhrazený k podnikání přijmeme platbu. Současně vzniká závazek zaplatit daň, který musí 28 být zaznamenán na zvláštní typ memo účtu. Tento účet představuje budoucí závazek zaplatit daň. Jak bylo uvedeno dříve, nelze přenášet peníze ze standardního účtu na memo účet, což přináší otázku, co je vlastně protiúčtem v případě memo účtu, protože transakce má mít vždy dva účty. Zde se pak nabízejí dvě možnosti. Buď v případě memo účtu odstraníme dříve zavedení omezení, které říká, že každá transakce má vždy dva účty. Protože memo účet je veden jako účet zvláštního typu, lze pro tento typ účtu omezení zrušit. Druhým způsobem, který více odpovídá účetní praxi, je zavedení kontra účtu k danému memo účtu. Vznik závazku zaplatit daň je tak pohybem z kontra účtu daňových závazků na účet daňových závazků. Poslední transakci představuje vyrovnání závazku, kdy v tomto uvedeném příkladu provedeme transakci z reálného účtu v bance na nákladový účet „odvedená daň“ a současně s uskutečněním této platby musíme snížit závazek na memo účtu. To je provedeno opačným zápisem na memo účet, tedy převedením částky z účtu daňových závazků na příslušný kontra účet. Touto operací je pak bilance na memo účtu závazků vyrovnaná. Zavedením memo účtu máme úplnou informaci nejenom o skutečném stavu peněz, který je dán součtem záznamů na obyčejných účtech, ale i informaci o tom, kolik peněz nám skutečně náleží, což představuje součet záznamů na obyčejných i memo účtech. 5.4. Alternativa jednoduchého záznamu o výdajích a pří- jmech Zatímco předchozí model založený na účtech a transakcích představuje bezpečný a flexibilní model zachycení pohybu financí, v případě jednoduché aplikace pro správu osobních financí lze zvažovat i jednodušší model postavený na příjmech a výdajích a jejich zařazení do příjmových a výdajových kategorií. Tento zjednodušený koncept je zachycen na obrázku 5-5. class prij my-v ydaj e Client Expense - amount :Money date :Date Obrázek 5-5 náklady a nákladové kategorie 29 Expense Category Tento koncept bude fungovat dobře do chvíle, než se rozhodneme realizovat složitější operace. Dosud byl uvažován pouze jednoduchý případ, kdy transakce zahrnuje odchozí záznam z jednoho účtu a příchozí záznam na jiný účet, tedy vždy právě dva účetní záznamy. V praxi je ale běžné, že je např. nákup jedné položky realizován platbou ze dvou různých zdrojů. To lze u modelu založeném na účtech a transakcích realizovat pomocí transakce, která má více jak dva účetní záznamy. Tedy např. nákup v hodnotě 300, realizujeme platbou v hotovosti v hodnotě 100 a převodem z účtu v hodnotě 200. To jsou dva odchozí (záporné) účetní pohyby ze dvou účtů. Třetím účetním záznamem v transakci je pak připsání částky 300 na nákladový účet. Opět platí, že celková bilance v transakci je rovna nule. Ve zjednodušeném modelu nákladů a výdajů však takovou finanční operaci nelze zaznamenat. Je možné namítnout, že takové mnohočetné transakce nebudou v jednoduché PFM aplikaci potřeba. Je ale vždy dobré zvážit, jakým směrem se může systém ve svých funkčnostech rozrůstat a zvážit tak užití komplexnějších struktur. Obecné pravidlo říká, že použití modelu účtů a transakcí je vhodné všude tam, kde je struktura účtů více statická. 1 5.5. Transformace modelu do tabulek a relací Tato kapitola popisuje konkrétní návrh, jak budou data z oblasti účtů a transakcí zachycena v databázi Oracle. Na obrázku 5-6 je znázorněna struktura tabulek pokrývající danou oblast. 1 FOWLER, Martin: Analysis Patterns – Reusable Object Models. ,Addison Wesley, 1998, s. 131 30 Obrázek 5-6 tabulky a relace pro oblast účtů a transakcí 5.6. Účetní období Navrhovaný model účetních transakcí by mohl představovat zdroj výkonnostních problémů při velkém počtu účetních záznamů na jednom účtu. Záznamy nekonečně přibývají, přičemž je bilance na účtu determinována součtem všech těchto záznamů. To představuje vzrůstající složitost v čase. Pro omezení počtu záznamů, které budou vstupem pro určení bilance účtu, se využívá mechanismu účetních období. Ta mohou být nastavena v určité periodě, tedy např. měsíční, kvartální, či roční, podle očekávaného počtu záznamů ve zvolené periodě. Tato perioda rozděluje data na úseky, které mohou být vyhodnoceny samostatně. Děje se tak pomocí 31 transakcí specifického typu, které nejprve předchozí období uzavřou. Uzavření stavu účtu představuje zjištění aktuální bilance účtu a zápisem specifické transakce dorovnávající bilanci na nulu. V novém období je pak provedena stejná operace v rámci transakce, ale s opačným znaménkem. Nové období je tak otevřeno záznamem nesoucím souhrnnou částku bilance předchozího období. Pokud je tedy třeba zjistit stav účtu v novém období, není se třeba dotazovat na účetní záznamy všech předchozích období, ale postačí sečíst záznamy spadající do nového období. Pokud chceme zjistit stav účtu kdykoliv v historii, bude se jednat o součet všech záznamů od počátku daného období, až po datum, ke kterému dotazujeme stav. 5.7. Konstrukce dotazů a nastavení indexů Klíčovou kapitolou pro zajištění efektivního dotazování se na data, je správné nastavení indexů. To by mělo odpovídat způsobu, jakým budou konstruovány dotazy do databáze. Indexy přestavují aditivní strukturu k tabulkám a umožňují výrazně rychlejší spuštění SQL dotazů. Pokud však hovoříme o efektivitě, je třeba říci, že indexy zvyšují náročnost na diskovou kapacitu. Jako další neefektivní jev může být zvýšená náročnost zápisu záznamu do tabulky, která obsahuje indexy, či mazání záznamu z této tabulky. Protože jsou indexy samostatnou strukturou, mohou být smazány (DROP) a kdykoliv znovu vytvořeny (CREATE), aniž bychom ovlivnili samotná data v tabulce. Oracle poskytuje široké možnosti indexování, je ale třeba zdůraznit, že některé typy indexů nejsou dostupné ve všech edicích Oracle (např. jsou nedostupné bitmapové indexy v Oracle Standard One), což může představovat vysoké náklady při využití výkonnějších indexů. Můžeme volit mezi těmito indexy: B-tree index – je založen na B-tree vyhledávacích stromových strukturách a jedná se o nejčastěji využívaný typ indexu b-tree cluster index – speciální B-tree index pro clustery hash cluster index – speciální index pro Hash clustery globální a lokální indexy – souvisí s partitioningem, který je přestaven v dalších kapitolách bitmap indexy – jsou efektivní na sloupcích, kde je jen několik málo unikátních hodnot. Je však nutné vzít v potaz, že bitmapové in- 32 dexy výrazně omezují paralelismus. Při UPDATE operacích totiž dochází k uzamčení celého bloku indexu, tj. několik řádků. function-based indexy – obsahují předem spočtené hodnoty funkcí. V průběhu návrhu, které sloupce tabulek budou indexovány a jakým způsobem, je vhodné ctít několik pravidel: index je vhodné vytvářet tam, kde budeme dotazy získávat méně než 15% všech řádek tabulky (platí pro velké tabulky)1. Tento práh je velmi relativní a může jej ovlivnit řada dalších charakteristik ukládaných dat. index je třeba tam, kde se tabulky spojují pomocí JOIN. Primární a unikátní klíče mají indexy automaticky. U cizích klíčů je vhodné zvážit jejich zavedení. malé tabulky nepotřebují index Pro vytipování správných sloupců Oracle dokumentace uvádí následující doporučení. Indexy jsou vhodné tam, kde: jsou převážně unikátní hodnoty je široký rozsah hodnot (vhodné pro B-tree indexy) je malý rozsah hodnot (vhodné pro bitmapové indexy) sloupce obsahují velký počet null hodnot, ale dotazy převážně získávají řádky, které obsahují hodnoty 1. V tomto případě je navíc vhodné nepoužívat v dotazech konstrukci: WHERE MUJSLOUPEC IS NOT NULL ale je vhodnější dotazovat se na konkrétní hodnotu tak, aby byl index využit WHERE MUJSLOUPEC >= minimalni_hodnota Po vytvoření struktur tabulek a určení primárních a cizích klíčů jsou v databázi Oracle založeny indexy pro primární a unikátní klíče. Pro cizí klíče je třeba indexy zavést, stejně tak jako pro hodnoty, podle kterých budou dotazy omezovat data. Efektivitu nasazení jednotlivých indexů sledujeme na typických dotazech, které jsou podchyceny v kapitole 4.2. 1 http://docs.oracle.com/cd/B14117_01/server.101/b10739/indexes.htm 33 Následující dotaz vrací seznam všech nákladových kategorií klienta (tedy i těch, které ve sledovaném období nemají žádné výdaje, což je docíleno spojením LEFT JOIN) a výdajů v uvedeném období jednoho měsíce. Seznam je dále seřazen sestupně podle výše výdajů: Dotaz A: select a.idaccount, a.accountname, nvl(sum(e.amount),0) amnt from account a left join (select idaccount, amount from accentry where REALIZATIONDATE between to_date('1.6.2014','dd.mm.yyyy') and to_date('1.7.2014','dd.mm.yyyy') ) e on e.idaccount = a.idaccount join ACCOUNTCATEGORY ac on ac.CODE = a.CODECATEGORY where a.idclient = 2087 and a.CODECATEGORY = 'COST' and ac.BALANCESTATEMENT = 'S' group by a.idaccount, a.accountname order by amnt desc; V této podobě trvá spuštění selectu nad vygenerovanými daty a načtení úplného výsledku 186 vteřin. Potřeba zavést vhodné indexy je tedy zřejmá. Pro další sledování výkonnosti dotazů budeme používat funkci autotrace dostupnou např. v nástroji Oracle SQL Developer. Pomocí této funkce získáme úplný přehled výsledků měření bez použití indexů, který je zachycen v tabulce 5-1. Dalším dotazem zmiňovaným v kapitole 4.2. je zjištění aktuálního stavu všech účtů klienta. Jedná se o součet všech položek finančních operací nad daným účtem. Dotaz B: select a.idaccount, a.accountname, nvl(sum(e.amount),0) amount from account a left join accentry e on e.idaccount = a.idaccount join ACCOUNTCATEGORY ac on ac.CODE = a.CODECATEGORY where a.idclient = 2087 and ac.BALANCESTATEMENT = 'B' group by a.idaccount, a.accountname; Pokud bychom navíc implementovali i účetní období, zmiňované v kapitole 5.6, pak nepůjde o součet všech finančních operací, ale pouze o součet operací po34 sledního účetního období a to proto, že vycházíme z předpokladu, že každé účetní období obsahuje řádku, která sumarizuje předchozí stav účtu. Dotaz se pak změní následovně: select a.idaccount, a.accountname, nvl(sum(e.amount),0) amount from account a left join (select idaccount, amount from accentry where REALIZATIONDATE between to_date('1.6.2014','dd.mm.yyyy') and to_date('1.7.2014','dd.mm.yyyy') ) e on e.idaccount = a.idaccount join ACCOUNTCATEGORY ac on ac.CODE = a.CODECATEGORY where a.idclient = 2087 and ac.BALANCESTATEMENT = 'B' group by a.idaccount, a.accountname; Bez použití indexů čas (s) physical reads physical read total bytes select A 186,047 1 313 914 10 763 583 488 select B 169,390 1 313 908 10 763 534 336 select C 223,922 1 797 766 14 727 299 072 Tabulka 5-1 hodnoty měření selectu bez nasazení indexů Poslední z dotazů poskytuje prostý seznam operací za uvedené období: Dotaz C: select t.idtransaction, t.name , e.amount, e.realizationdate, a.accountname, a.codecategory from transaction t join accentry e on t.idtransaction = e.idtransaction join account a on e.idaccount = a.idaccount where e.REALIZATIONDATE between to_date('1.6.2014','dd.mm.yyyy') and to_date('1.7.2014','dd.mm.yyyy') and a.idclient = 2087 and a.codecategory in ('COST','INCOME') Oracle poskytuje nástroj, pomocí nějž lze sledovat tzv. exekuční plán, tedy jednotlivé kroky, které představují, jak je dotaz před svým spuštěním vyhodnocen, jaké indexy budou použity a jak jsou časově náročná dílčí vyhledávání a sloučení (JOIN) tabulek. Pro načtení exekučního plánu se využívá příkazu „EXPLAIN PLAN“, za kterým následuje select (popř. update, insert, delete), který je předmětem analýzy. Mimo to lze využít komfortnějších náhledů na exekuční plány po35 mocí nástrojů integrovaných v řadě existujících aplikací (např. v Oracle SQL Developer). V nich jsou pak lépe stromově zobrazeny jednotlivá vnoření iterací. Výsledek příkazu EXPLAIN PLAN pro select A je vidět na obrázku 5-7. Obrázek 5-7 výsledek funkce EXPLAIN PLAN v Oracle SQL Developer Varovná čísla jsou v tomto exekučním plánu vidět ve sloupcích CARDINALITY a COST. COST představuje míru využití prostředků, jakými jsou CPU, a I/O operace. Hodnota nemá žádnou specifickou jednotku měření a je spíše váženou hodnotou, která slouží pro srovnání náročnosti a využití prostředků jednotlivých kroků exekučního plánu. Detailněji lze pak sledovat dílčí hodnoty CPU_COST (jak byl využit daném kroku procesor) a IO_COST (počet datových bloku načtených v operaci). Hodnota CARDINALITY pak představuje počet řádek, ke kterým daná operace přistupuje. Pokud trvá spuštěný dotaz nepřiměřeně dlouho, pak hledáme operace s nejvyšší hodnotou COST, které jsou příčinou dlouhých naměřených časů. V uvedeném příkladu lze vyčíst, že operace s nejvyšší hodnotou má ve svém popisu TABLE ACCES (FULL) u tabulky ACCENTRY. Operace nesoucí v popisu TABLE ACCES (FULL) mohou být často zdrojem problémů. Znamená to, že operace procházela všechny řádky tabulky ACCENTRY, aby byly nalezeny řádky vyho- 36 vující podmínkám, přičemž nebyl využit žádný index. To nutně nemusí znamenat problém, pokud tabulka obsahuje malé množství záznamů. Pro takové tabulky není použití indexu vhodné. Tabulka ACCENTRY je ovšem tabulkou s nejvyšším počtem záznamů a sloupec CARDINALITY odhaluje, že jich operace projde přes 8 mil. V tabulce ACCENTRY jsou vyhledávány položky podle data REALIZATIONDATE a dotaz je omezen na účty jednoho klienta. Z toho je patrné, že schází vhodný index nad datumovými sloupci a především indexy pro cizí klíče. Index nad cizím klíčem zavedeme pomocí příkazu: create index accen_fk_idacc on accentry(idaccount); Pokud není v příkaze CREATE INDEX blíže specifikováno, jedná se o nejběžnější B-Tree index a protože tabulka obsahuje více jak 100 miliónů záznamů, může být vytvoření stromu časově náročné. Dále nebylo v příkazu specifikováno fyzické umístění indexů, které jsou v Oracle řešeny skrze tzv. tablespaces. Je vhodné, aby měly indexy úložiště oddělené od tabulek, ale samotné fyzické rozložení datových objektů bude řešeno následně v samostatné kapitole. Indexy tak budou založeny v implicitním tablespace USERS. Velikost tohoto tablespace již v tuto chvíli vytváření indexů může překročit hranici 32GB, což představuje maximální velikost datového souboru .DBF (maximální velikost je ovlivněna Oracle parametrem db_block_size, který je v testovací DB na hodnotě 8192). Je tedy třeba pro tablespace USERS vytvořit další datový soubor pomocí: alter tablespace users add datafile 'D:\ora11g\oradata\orcl\USERS02.DBF' size 2M autoextend on; Dále je třeba uvést způsob, jakým lze eliminovat vliv cache paměti na opakované spouštění dotazů. Cache databáze Oracle je třeba před každým jednotlivým měřením promazat pomocí příkazu: ALTER SYSTEM FLUSH BUFFER_CACHE; Bez jeho spuštění vrací opakovaná spuštění dotazu data z cache paměti okamžitě, bez ohledu na složitost. Dalším krokem je eliminace cache souborového systému implementovaná přímo v operačním systému Windows. Tu lze vyčistit např. pomocí externího nástroje RamMap (www.sysinternals.com) a to volbou z menu aplikace (Empty Standby List). V souvislosti se zavedením nových indexů je třeba zmínit, že index nemusí zafungovat okamžitě po jeho vytvoření. Při rozhodování, jaké indexy se použijí, využívá DB Oracle statistik, jejichž přepočtení lze vynutit. Nad tabulkou ACCENTRY vypadá přepočet statistik takto: 37 EXECUTE dbms_stats.gather_table_stats ( ownname=>'PFMTEST', tabname=>'ACCENTRY', estimate_percent=>100, cascade=>true); Pokud zavedeme výše zmíněný index v tabulce ACCENTRY nad sloupcem IDACCOUNT, který představuje cizí klíč a přepočteme statistiky, dojde okamžitě ke zrychlení selectu. . Obdobným způsobem jsou zavedeny další indexy nad cizími klíči. Jejich výčet a patřičné skripty pro vytvoření jsou přílohou této práce. Kromě indexů u cizích klíčů je vhodné zavést indexy tam, kde budeme často při vyhledávání omezovat data a z toho lze vyvodit nutnost indexovat čas provedených finančních transakcí. Téměř vždy totiž agregujeme záznamy za nějaké období. Index je tak zaveden pro sloupec REALIZATIONDATE v tabulce ACCENTRY. Všechny doposud zavedené indexy jsou typu B-tree. Je ovšem třeba zvážit, zda nebude vhodné i nasazení jiných typů indexů. U sloupců, kde se vyskytuje několik málo unikátních hodnot, nejsou B-tree indexy dostatečné. Takové sloupce jsou pak vhodnými kandidáty na bitmapový index. V navrženém schématu je většina dat omezena na konkrétního klienta a čas, což nakonec představuje malý objem dat, ve kterém bude efekt bitmapového indexu minimální. Jeho efektivita by byla zřetelná, pokud bychom položili např. dotaz „kolik máme v systému celkem nákladových účtů“. Data v tomto případě nejsou omezena jinak, než na typ účtu, což je právě sloupec s malým počtem unikátních hodnot. Dotaz by vypadal takto: select count(idaccount) from account where codecategory = 'COST'; Pokud bude sloupec CODECATEGORY využívat B-tree index, dostaneme hodtnotu za 1,36 vteřiny. V případě bitmapového indexu je ale odpověď mnohem rychlejší (0,42s). Využijeme-li dříve představených účetních období, které mají specifické typy transakcí, pak i typ transakce je vhodný kandidát na bitmapový index. Po nasazení všech zmíněných indexů jsou výsledné časy zachyceny v tabulce 5-2) 38 S použítím indexů čas (s) physical reads physical read total bytes select A 5,187 846 6 930 432 select B 6,203 947 7 757 824 select C 7,726 1 056 8 650 752 Tabulka 5-2 hodnoty měření selectu po nasazení indexů 5.8. Partitioning Koncepce „partition“ je zajímavá nejenom proto, že může zefektivnit SQL dotazy a tím zvýšit výkonnost systému, ale přináší řadu dalších výhod, jakými jsou snazší správa dat a levnější ukládání velkých objemů dat. Partitions umožňují rozdělení tabulek a indexů (popř. index-organized tables) na menší části a přistupovat k nim s jemnější úrovní granularity. Takto oddělené části se nazývají partitions. K tabulce, která je rozdělena do několika partitions, přistupujeme standardně jako k běžné tabulce a to jak pomocí SQL dotazů, tak pomocí příkazů DML (Data Manipulation Language). Každá řádka tabulky spadá do jedné partition a to na základě předem stanoveného klíče (partition key). Jako klíč lze velmi často vnímat čas. Data finančních transakcí rozdělená na partitions po měsících přinesou značné zrychlení, pokud víme, že pracujeme s omezenými daty právě jednoho období. Za 5 let běhu systému dostáváme tabulku rozdělenou po měsících na 60 částí a data budeme dotazovat pouze v jedné z nich. To zmenšuje 60ti násobně objem dat, ve kterých budeme vyhledávat. Pokud spojujeme dvě tabulky (JOIN) a obě jsou rozděleny do partition na základě klíče, dochází k významnému zrychlení JOIN operace (tzv. partition-wise join). Dalším benefitem souvisejícím se zavedením partitions je snazší správa dat. Data rozdělená do jednotlivých období lze efektivněji zálohovat, či po čase ze systému odebrat. Jednotlivým partitions lze navíc vyhradit samostatné úložiště pomocí tablespaces a tak lze např. aktuální data provozovat na výkonnějších avšak dražších SSD discích a data starší udržovat na pomalejších a levnějších discích. Schopnost pracovat samostatně s časově oddělenými bloky dat lze využít, pokud plánujeme systém s vysokou dostupností. S jednotlivými partitiony lze pracovat nezávisle a výpadek jedné neovlivní funkčnost systému (pokud s těmito daty není nezbytné pracovat). Existují tři různé přístupy k rozdělení dat do partitions: 39 Range partitioning – je asi nejběžnějším přístupem. Pro každou partition vymezíme rozsah hodnot a klíč, podle kterého budou řádky distribuovány mezi jednotlivé partitions. Typicky se využívá pro datumy. Hash partitioning – zvolíme klíč, který je dále interpretován pomocí hash algoritmu. Tato hash hodnota je dále mapována do jednotlivých partition, přičemž se algoritmus snaží zajistit rovnoměrnou distribuci mezi jednotlivé partition. List partitioning – určí se klíč a explicitní výčet hodnot, které vymezují, že řádka spadá pod tuto partition. Kromě těchto jednoduchých přístupů (single-level partitioning) lze ještě využít jejich vzájemných kombinací (composite partitioning). Oracle dokumentace uvádí doporučení pro zavedení partitions u tabulek: u tabulek s objemem větším než 2GB dat je vždy vhodné zvážit zavedení partition tabulky obsahující historická data, kdy zapisována jsou pouze data z posledního období, je vhodné rozdělit do partition když je třeba obsah tabulek distribuovat na různé typy paměťových zařízení, je vhodné zavést partitions v různých tablespacech přestavujících jednotlivá zařízení. Motivací pro zavedení partition u indexů může být jeden z těchto případů: potřeba vyhnout se přestavbě celého indexu při odmazání dat potřeba udržovat data po částech bez nutnosti zneplatnění celého indexu snížení efektu nerovnoměrné distribuce hodnot (tzv. index skew) V aplikaci pro správu osobních financí, která ukládá data o finančních operacích provedených v čase, se nabízí zavedení range partitions, kde dělícím klíčem partition bude právě čas. V tomto případě pro datově nejobjemnější tabulku ACCENTRY zavedeme range partition s rozdělením podle hodnot ve sloupci REALIZATIONDATE. Lze uvažovat rozdělení na kalendářní roky. Pokud však běžné dotazy nepřekračují období jednoho měsíce, může být rozdělení partition jemnější, tedy po měsících. Je důležité zmínit, že zavedení partitions nelze jednoduše provést nad existující tabulkou, ale pouze spolu s vytvořením nové tabulky. Proto je vhodné parametry partitions rozmyslet předem. Pokud bychom plánovali zavést partitions, či změnit její parametry později, muselo by dojít k zavedení nové 40 struktury tabulky a přenosu dat. Zavedení partition vypadá pro tabulku ACCENTRY následovně: CREATE TABLE AccEntry ( IdAccEntry NUMBER(20) NOT NULL, IdAccount NUMBER(20) NOT NULL, Amount NUMBER(20,2) NOT NULL, RealizationDate DATE NOT NULL, AccountedDate DATE NOT NULL, IdTransaction NUMBER(20) ) partition by range (realizationdate) ( partition acc_012013 values less than(to_date('1.2.2013','dd.mm.yyyy')), partition acc_022013 values less than(to_date('1.3.2013','dd.mm.yyyy')), partition acc_032013 values less than(to_date('1.4.2013','dd.mm.yyyy')), partition acc_042013 values less than(to_date('1.5.2013','dd.mm.yyyy')), partition acc_052013 values less than(to_date('1.6.2013','dd.mm.yyyy')), … ) Nebo lze zavést partitions automaticky pomocí intervalového partitioningu, tedy následujícím způsobem. Při zápisu dat vznikají další partitions automaticky podle nastaveného intervalu (systém tyto partitions automaticky pojmenovává) … partition by range (realizationdate) INTERVAL (NUMTOYMINTERVAL(1,'MONTH')) ( PARTITION part_01 values LESS THAN (TO_DATE('1.1.2013','dd.mm.yyyy')) ); Protože tabulka ACCENTRY již existuje, není možné dodatečně takovou tabulku rozdělit do partitions. Proto je vhodné odhadnout potřebu zavedení partitions na počátku. Je ale možné vytvořit novou strukturu rozdělenou do partitions, do které se původní nerozdělená tabulka zkopíruje. Kompletní postup, který využívá funkcí modulu DBMS_REDEFINITION, je uveden v přiloženém souboru (08. rozedeleni_do_partition.sql). Dále je třeba rozhodnout, jakým způsobem převedeme indexy, zda se bude jednat o indexy globální, či lokální. V následujících měřeních jsou pro stěžejní sloupec IDACCOUNT tabulky ACCENTRY zkoumány a porovnány oba způsoby. 41 Globální index je vytvořen standardním způsobem, lokální pak za použití klíčkového slova LOCAL. create index accen_inx_acnt_lcl on accentry(idaccount) local; Efektivitu rozdělení dat do partition lze sledovat opět měřením doby vykonání selectu, kde došlo k dalšímu časovému snížení. V tabulce 5-3 je ale zejména patrné snížení počtu diskových operací, což lze vysvětlit tím, že byla použita právě jedna partition. Že byla skutečně použita jen jedna partition je zase možné ověřit v exekučním plánu, kde lze pod příslušnou operací nalézt název „PARTITION RANGE (SINGLE)“. Dále je zřetelné, že zavedení partitions nemělo vliv na dotaz B. To proto, že aktuální stav je součtem za všechna období, tedy dotaz směruje skrze všechny partitions. Toto lze eliminovat zavedením účetních období, kdy se budeme dotazovat pouze na poslední účetní období a dotaz tak bude směrován právě do jedné partition. ddddfsdfsdDáDá partition global index čas (s) physical reads physical read total bytes select A 0,723 82 671 744 select B 6,328 948 7 766 016 select C 2,266 205 1 679 360 partition local index čas (s) physical reads physical read total bytes select A 0,468 52 425 984 select B 6,422 948 7 766 016 select C 1,204 163 1 335 296 Tabulka 5-3 hodnoty měření selectu po nasazení partitions Uvedené časové rozdělení dat navíc skýtá možnost další optimalizace. PFM systém pracuje převážně s aktuálními daty. Pokud vymezíme pro jednotlivé časové období různé diskové prostory pomocí TABLESPACE, lze tak data aktuální uchovávat na rychlých SSD discích a postupně v čase přesouvat do TABLESPACE na pomalejších discích. 5.9. Využití materializovaných pohledů Stejně jako řada jiných relačních databází, nabízí i Oracle nástroje pro materializaci dat do materializovaných pohledů. Materializované pohledy jsou ve své pod42 statě tabulky, které vznikají na základě definice pomocí select konstrukce. Výsledek takto zkonstruovaného dotazu je potom fyzicky uložen do tabulky, ke které lze opět přistupovat pomocí dotazů. Možností využití materializovaných pohledů je celá řada a mimo jiné je lze využít tam, kde je třeba urychlit složitější dotazy, ve kterých dochází k agregaci, či transformaci dat. Data jsou pak v materializovaném pohledu předem připravena v podobě blízké tomu, jak je chceme dotazovat, tedy např. již transformovaná, či agregovaná. Dotaz na materializovaný pohled je pak již rychlý, vzhledem k tomu, že složitější operace již byly vykonány. Nevýhodou materializovaných pohledů může být objem dat, která pak v databázi udržujeme duplicitně. Rovněž je třeba zvážit způsob, jakým chceme mít data v materializovaném pohledu aktualizovaná. Aktualizaci lze zajistit explicitním vyvoláním, nebo lze nastavit aktualizaci automatickou, na základě manipulace s daty některé ze zdrojových tabulek. Je několik způsobů jak zajistit aktualizaci. Jednou z možností je COMPLETE REFRESH, při kterém dojde ke spuštění selectu, načtení zdrojových dat a k uložení jeho výsledku do materializovaného pohledu. To ale může být časově náročný proces, zejména v případech, kdy je zpracováván velký objem dat. Efektivním přístupem k aktualizaci struktur je FAST REFRESH, který na rozdíl od COMPLETE REFRESH aktualizuje inkrementálně pouze část dat, kde došlo ke změnám. To představuje výrazně rychlejší časy aktualizace než COMPLETE REFRESH. K tomu, aby mohl být využit FAST REFRESH, je třeba nad zdrojovými tabulkami vytvořit MATERIALIZED VIEW LOG, který zajišťuje sledování změn nad příslušnými sloupci, a tyto změny pak iniciují aktualizaci materializovaného pohledu. LOG je ve své podstatě tabulka, do které jsou zapisovány jednotlivé změny, kdykoliv je vyvolána DML operace (data manipulation language) nad zdrojovou tabulkou. V PFM aplikaci je možné využít materializovaných pohledů pro složitější agregace finančních transakcí. Lze tak například připravit měsíční agregace jednotlivých nákladových kategorií, či sumarizovat aktuální stavy účtu, které jsou jinak výsledkem agregace transakcí probíhajících na účtu. Nejprve vytvoříme log nad tabulkou účetních záznamů ACCENTRY: CREATE MATERIALIZED VIEW LOG ON accentry WITH SEQUENCE, ROWID (idaccount,amount, realizationdate) INCLUDING NEW VALUES; a následně samotný materializovaný pohled MV_COSTS: 43 CREATE MATERIALIZED VIEW mv_costs PCTFREE 10 BUILD IMMEDIATE REFRESH FAST AS select e.idaccount, to_number(to_char(e.realizationdate,'YYYY')) year, to_number(to_char(e.realizationdate,'MM')) month, sum(e.amount) amnt from ACCENTRY e group by e.idaccount, to_number(to_char(e.realizationdate,'YYYY')), to_number(to_char(e.realizationdate,'MM')); Parametr PCTFREE je popsán v následující kapitole a pomáhá nám optimalizovat diskový prostor. BUILD IMEDIATE zajistí, aby byl materializovaný pohled vystavěn okamžitě. REFRESH FAST poskytne částečnou aktualizaci na základě vytvořeného logu ve zdrojové tabulce ACCENTRY. Výsledkem je materializovaný pohled se sloupci: IDACCOUNT – id účtu YEAR – rok MONTH – měsíc AMNT – součet účetních záznamů na účtu v uvedeném roce a měsíci Následný dotaz nad nově vzniklým materializovaným dotazem nebude optimální, dokud nebudou zavedeny potřebné indexy. Ty lze zavést stejným způsobem, jako u běžné tabulky. Vyhledávání bude probíhat na základě složeného klíče, vždy vyhledáváme podle ID účtu a období: create index mv_costs_inx1 on mv_costs(idaccount, year, month); Dotaz na náklady v jednotlivých kategoriích a v daném měsíčním období pak bude vypadat následovně: Dotaz A: select cst.* from mv_costs cst join account ac on cst.idaccount = ac.idaccount where ac.idclient = 2087 and year = 2014 and month = 6 and ac.CODECATEGORY = 'COST'; Pro uvedený příklad jsou pak naměřené hodnoty v tabulce 5-4. Pro dotaz B budeme předpokládat zavedení účetních období tak, abychom se mohli dotazovat na jednu agregovanou hodnotu v materializovaném pohledu. 44 Dotaz B: select cst.* from mv_costs cst join account a on cst.idaccount = a.idaccount join ACCOUNTCATEGORY ac on ac.CODE = a.CODECATEGORY where a.idclient = 2087 and year = 2014 and month = 12 and ac.BALANCESTATEMENT = 'B'; s materializovaným pohledem čas (s) physical reads physical read total bytes select A 0,297 26 212 992 select B 0,312 18 147 456 select C - - - Tabulka 5-4 hodnoty měření s použitím materializovaných pohledů Dotaz C nelze realizovat pomocí tohoto materializovaného pohledu, protože nedotazuje agregované hodnoty, ale jednotlivé transakce. Z uvedených měření je zřejmé, že zavedení materializovaných pohledů je v tomto objemu dat jednoznačně efektivní. Všechny doposud naměřené časy jsou měřeny s eliminací vlivu cache paměti a to jak vlastního cachovacího mechanismu implementovaného v DB Oracle, tak cache operačního systému. V praxi to znamená, že časy dotazů budou výrazně lepší a to tím více, čím bude k dispozici větší prostor paměti pro cache. 5.10. Organizace diskového prostoru 5.10.1. Tablespace Databáze Oracle poskytuje nástroje pro správu úložiště datových souborů a to pomocí tabulkových prostorů „TABLESPACE“. Jednotlivé tabulky, indexy, partitiony, materializované pohledy a další lze přiřazovat předem definovaným tablespace a určit tak jejich fyzické umístění. Datové objekty lze umístit do různých tablespace, k čemuž vede řada motivací, ať již s ohledem na výkon, snadnou údržbu, či možnosti zálohování. Protože pro jednotlivé tablespace lze definovat fyzické uložení, lze oddělit aktuální provozní data rozdělená do partitions a umístit je na rychlé disky SSD, zatímco historická data mohou být umístěna na levnější 45 a pomalejší disky. Je třeba zjistit, jak velký je objem dat a nároky na udržení partition s aktuálními daty. Oracle umožňuje přistupovat k řadě vlastních metadat pomocí systémových view. Obsazenost diskového prostoru lze např. sledovat v systémovém pohledu USER_EXTENTS. Dotaz na segmenty, které využívají největší diskový prostor, pak vypadá následovně: select segment_name, segment_type, sum(e.bytes)/(1024*1024) MBytes from user_extents e group by segment_name, segment_type order by mbytes desc Výsledný seznam v tabulce 5-5 ukazuje největší segmenty a typ segmentu. Z něj je zřejmé, že nejobjemnější tabulkou je tabulka účetních záznamů a jejich indexů. Dva roky dat tak v celkovém úhrnu obsadí cca 50GB diskového prostoru. # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 SEGMENT_NAME ACCENTRY ACCEN_FK_IDTRANS PK_ACCENTRY ACCEN_FK_IDACC ACCEN_INX_RDATE_LCL TRANSACTION TMP$$_ACCEN_FK_IDACC0 TMP$$_PK_ACCENTRY0 PK_TRANSACTION TRANS_FK_IDPERS I_SNAP$_MV_COSTS MV_COSTS MV_COSTS_INX2 MV_COSTS_INX1 ACCOUNT PERSONACCOUNT PERSACC_FK_IDACC ACC_FK_IDCLIENT PERSACC_FK_IDPERS PK_ACCOUNT SEGMENT_TYPE TABLE PARTITION INDEX INDEX INDEX INDEX PARTITION TABLE INDEX INDEX INDEX INDEX INDEX TABLE INDEX INDEX TABLE TABLE INDEX INDEX INDEX INDEX MBYTES 10333 4860 4642 4568 4321 3819 3732 3725 1884 1769 1730 1440 1218 1093 136 72 56 53 53 52 Tabulka 5-5 seznam 20ti největších segmentů v MB Další doporučenou praktikou je oddělení samostatné tablespace pro indexy a tedy jejich fyzické oddělení od vlastních dat v tabulkách. Tímto způsobem lze data lépe spravovat. Indexy totiž např. z hlediska archivace nejsou nijak významné a lze je kdykoliv zrekonstruovat. 46 5.10.2. Optimalizace využití prostoru pomocí PCTFREE Z hlediska optimalizace diskového prostoru je třeba zmínit atribut, který ovlivňuje obsazenost diskového prostoru. Data jsou v Oracle ukládána po blocích, což je nejmenší jednotka úložiště v Oracle. Databáze má vždy svou implicitní velikost bloku. Tu je ale možné měnit pro jednotlivé tablespace. PCTFREE je pak parametr pro blokové ukládání a udává, jak velký prostor má být rezervován při ukládání pro budoucí update operace. Hodnota PCTFREE = 10 tak například říká, že bude blok využíván, dokud není naplněn na 90%. Hodnota 10 je implicitní hodnotou u tabulek, u kterých není hodnota explicitně nastavena. Z hlediska optimalizace prostoru tak lze uvažovat nastavení hodnoty nižší (např. 0, tedy úplné využití bloku) a to tam, kde víme, že nedochází k updatům, ale jsou pouze vkládány nové záznamy (insert). 6. Návrh implementace v MongoDB Princip objektových databází je diametrálně rozdílný proti relačním databázím. Přesto lze mezi těmito databázovými principy hledat souvislosti. Běžnou tabulku relačního systému zde představuje kolekce objektů. V případě MongoDB jsou objekty reprezentovány dokumenty. Dokument lze tedy vnímat jako řádku tabulky v relační databázi, současně ale může reprezentovat několik řádek různých tabulek. U relačních databází je struktura tabulky předem definována, MongoDB však u kolekce fixní strukturu nepředepisuje. Je tak možné do kolekce vkládat objekty o různé struktuře. V praxi však dává smysl, aby dokumenty v jedné kolekci měly alespoň podobnou strukturu. Mezi jednotlivými dokumenty existují vazby a ty lze zachytit dvojím způsobem: Reference – zachycuje relaci odkazem jednoho dokumentu na jiný. Vnořené dokumenty – dokumenty jsou ukládány jako vnořené struktury nadřízených dokumentů (embedded documents) Princip, jakým bychom měli volit mezi referencemi a vnořenými dokumenty, vychází především z potřeby izolace atomických operací. V MongoDB je operace atomická na úrovni dokumentu, tedy jedna atomická operace nemůže ovlivnit několik dokumentů. Struktura samotného dokumentu je ve formátu BSON, což je binární zápis formátu JSON (JavaScript Object Notation). 47 Při návrhu objektů v databázi MongoDB je třeba vzít na vědomí několik omezení, která předurčují rozdíly ve struktuře dat oproti relační databázi. MongoDB nepodporuje atomickou operaci (respektive operaci dodržující ACID) nad více dokumenty. Atomicita operace je zajištěna právě nad jedním dokumentem. Stejně tak dotazování se provádí právě nad jednou kolekcí dokumentů a nejsou možné joiny mezi dokumenty tak, jak jsou známy v relačních databázích. To ve svém důsledku znamená, že atributovou součástí dokumentu se stávají i atributy jiných kolekcí, protože je třeba se na ně dotazovat. To vede k redundanci dat a porušení normální formy. Příkladem může být konstrukce uvedená v návrhu relační databáze, kde je definován vztah mezi klientem, účtem a transakcí. Pokud je třeba se v MongoDB dotazovat na transakce klienta, musí být atribut IDCLIENT součástí objektu transakce. Pokud budeme dotazovat u transakcí i názvy účtů, měl by být součástí transakce i název účtu. Lze samozřejmě postupovat i jinak a názvy účtu dodatečně doplnit na základě jejich ID postupným dotazováním nad výslednou kolekcí. 6.1. Návrh objektů (dokumentů) V této kapitole jsou popsány návrhy stěžejních dokumentů, které budou předmětem kriticky exponovaných dotazů. Návrh vychází z účetních transakcí dříve popsaného relačního modelu, které transformuje do objektů databáze MongoDB. Clients { "_id" : 170105, "name" : "Jan Novak", "validfrom" : ISODate("2015-04-07T23:00:00Z"), "validto" : ISODate("9999-03-31T23:00:00Z") } Accounts { "_id" : 6089750, "accountname" : "COST_6089750", "codecategory" : "COST", "codecurrency" : "CZK", "idclient" : 198185 } Dokument transakce je příklad emedded dokumentu, který v sobě zapouzdřuje jednotlivé účetní operace: Transactions { "_id" : 592696726, "idclient" : 166275, 48 "codetransactiontype" : "N", "idperson" : 166276, "name" : "Trans_592696726", "note" : "", "accentries" : [ { "codecategory" : "CASH", "balancestatement" : "B", "idaccount" : 5452746, "amount" : -5214.69, "realizationdate" : ISODate("2012-1231T23:00:00Z"), "accounteddate" : ISODate("2012-1231T23:00:00Z"), "accountname" : "ACCOUNT_5452746" }, { "codecategory" : "COST", "balancestatement" : "S", "idaccount" : 5452766, "amount" : 5214.69 "realizationdate" : ISODate("2012-1231T23:00:00Z"), "accounteddate" : ISODate("2012-1231T23:00:00Z"), "accountname" : "COST_5452766", } ] } 6.2. Konstrukce dotazů a zavedení indexů I v případě objektové databáze je měřena výkonost třech základních dotazů, odpovídajících dotazům v relační databázi. Ve dvou prvních dotazech (dotazy A,B) jde o agregační funkci. Ta je v MongoDB zastoupena metodou aggregate dostupnou u každé kolekce objektů. Agregační funkce je implementována jako pipeline postupně jdoucích operací. Dotaz A: db.transactions.aggregate ( [ {$match : {idclient:2087}}, {$unwind:"$accentries"}, {$match : {"accentries.codecategory":"COST", "accentries.realizationdate" : {$gte: ISODate("2014-0601T00:00:00.000Z"),$lt: ISODate("2014-07-01T00:00:00.000Z")}}}, {$group:{ _id : {idaccount:"$accentries.idaccount",accountname:"$accentries.accountname"}, total : {$sum : "$accentries.amount"}}},{$sort:{"accentries.accountname":1}}]) V tomto konkrétním případě jsou záznamy omezeny na konkrétního klienta na úrovni objektu transakce. Následně je pomocí $unwind postoupeno o úroveň ní- 49 že, tedy na embedded objekt accentries představující jednotlivé účetní pohyby a zde je dodatečně kolekce omezena na datum období, které poptáváme a konkrétní typ nákladových účtů (accentries.codecategory“COST“). Sumu nad hodnotami z atributu amount pak zajišťuje naplnění parametru $sum. Obdobně vypadá i dotaz na zjištění aktuálního stavu všech účtů: Dotaz B: db.transactions.aggregate ([ {$match : {idclient:2087}}, {$unwind:"$accentries"}, {$match : {"accentries.balancestatement":"B"}}, {$group:{ _id : {idaccount:"$accentries.idaccount",accountname:"$accentries.accountname"}, total : {$sum : "$accentries.amount"}}},{$sort:{"accentries.accountname":1}}]) Poslední dotaz na prostý výpis transakcí v určitém období je zajištěn pomocí metody find a vypadá následovně: Dotaz C: db.transactions.find ( { idclient:2087, "accentries.realizationdate" : {$gte: ISODate("2014-0601T00:00:00.000Z"),$lt: ISODate("2014-07-01T00:00:00.000Z")}, "accentries.codecategory" : { $in : ["COST","INCOME"] }}) Výsledky měření bez použití indexů jsou zachyceny v tabulce 6-1. bez použití indexů čas (s) select A 759,501 1 635 657 1 492 - - select B 800,008 1 634 985 696 - - select C 932,993 9 291 465 21 389 numYield nScannedObjects nReturned responseLength 100 122 113 Tabulka 6-1 hodnoty měření na MongoDB bez použití indexů Měření probíhá pomocí metod třídy db.system.profile. Ta poskytuje jednak časové údaje o spuštěných dotazech, ale i další statistiky o průběhu vyhledávacích, či agregačních algoritmů. Je třeba zdůraznit, že rozsah poskytovaných informací se pro agregační a vyhledávací funkce různí. Stejně tak jako v případě měření nad databází Oracle i zde je eliminován efekt cache paměti pomocí aplikace RamMap 50 45 a současně uzavřením a znovuspuštěním instance mongod.exe, kdy dojde k zahození veškerých struktur v paměti. Zachytávání informací o probíhajících dotazech je třeba aktivovat pomocí příkazu: db.setProfilingLevel(2) a hodnoty naposledy spuštěného dotazu lze vyžádat pomocí této konstrukce: db.system.profile.find({},{ ns:1,query:1, nscannedObjects:1, numYield:1,nreturned:1, responseLength:1,millis:1} ).limit(1).sort({ts : -1}).pretty() Jednotlivé výstupní hodnoty představují: nscannedObjects – počet dokumentů, které algoritmus prošel při vyhledávání. Není dostupné u agregací. numYield – počet čekání na dokončení operace. Ve většině případů jde o čekání při čtení z disku. nreturned – počet získaných záznamů. Není dostupné u agregací. millis – celková doba provedení dotazu v milisekundách responseLength – délka odpovědi v bytech Obdobně jako relační databáze, nabízí i objektově založená MongoDB možnosti pro indexování záznamů, založenou na principu stromů B-tree. Možnosti nastavení indexů jsou ovšem výrazně jednodušší. MongoDB poskytuje tyto typy indexů: Indexy nad jedním polem Compound indexy – složené indexy nad více poli Multikey indexy – slouží k indexování atributů, které obsahují pole Text indexy – pro indexování textových řetězců a řešení vyhledávání v textech Geofrafické indexy – pro řešení vyhledávání geografických lokací 51 Hash Indexy – nad několika atributy je vypočten hash, který je následně indexován. Používá se např. pro hash sharding (vysvětlen později) Pro vyhledávání transakcí určitého klienta přidáme index nad atributem idclient následovně: db.transactions.createIndex( { idclient: 1} ) Výsledek naměřených hodnot je zachycen v tabulce 6-2: index idclient čas (s) numYield responseLength select A 8,063 935 1 492 select B 8,063 935 696 select C 8,645 937 21 389 nScannedObjects nReturned 935 Tabulka 6-2 hodnoty měření na MongoDB s použitím indexu Další testované variace indexů zahrnují compound index nad atributy realizationdate a idclient, ale v měření nedochází k žádnému zlepšení oproti hodnotám naměřeným v tabulce 6-2. Stejně tak, jako dva založené samostatné klíče nad idclient a realizationdate, kdy MongoDB proklamuje efekt tzv. index intersection, nepřináší výrazně lepší výsledky. Je třeba znovu zdůraznit, že i při měření výsledků v MongoDB je eliminována cache paměť. 6.1. Organizace diskového prostoru Obsazení diskového prostoru získáme u jednotlivých kolekcí pomocí příkazu db.collections.stats(). Pro kolekci transakcí je pak požadavek na velikost obsazeného prostoru v megabytech zjišťována takto: db.transactions.stats({scale:1024*1024}) Obsazenost je zachycena v tabulce 6-3 52 45 . transactions accounts clients data v MB indexy v MB 47 360 7 206 419 70 10 2 Tabulka 6-3 obsazení diskového prostoru daty jednotlivých kolekcí a jejich indexů MongoDB poskytuje metodu rozdělení velkých dat na menší části na základě dělícího klíče. Jednotlivým blokům se říká shards a jde v podstatě o obdobu partitions popsanou v části řešení Oracle. Význam je ovšem především v distribuci jednotlivých shards na různé servery. Podle dokumentace MondoDB tedy shards řeší především problém velké zátěže generované velkým objemem dotazů, které jsou pak rozloženy na jednotlivé servery a dále problém uložení velkého objemu dat na jednom serveru. V tomto případě tedy shards neřeší problém rozdělení vyhledávání na menší části, jako je tomu v případě partitions v databázi Oracle. Z hlediska návrhu datové struktury je ale třeba tuto vlastnost zmínit. 53 7. Závěr Aplikace typu Personal Finance Manager pracují s relativně velkým množstvím dat účetního charakteru. Sleduje totiž toky financí na jednotlivých účtech. Problematiku sledování výdajových kategorií, která je stěžejní poskytovanou funkčností PFM aplikací, lze vnímat jako pohyb financí na nákladových účtech. Práce představuje zjednodušený přístup k pohybu financí, postavený na pohledu příjmů a výdajů a současně představuje a dále rozvíjí myšlenku účetních transakcí, které zachycují pohyb mezi jednotlivými účty. V práci je zmíněna celá řada funkčností a identifikována řada entit nezbytných pro plnohodnotný systém. Současně jsou ale identifikovány klíčové entity, které mohou mít dopad na výkonost celého systému. Právě u těchto entit je dále sledována efektivita vytěžování dat a nároky na kapacitu úložiště. Jsou to tedy zejména účty, účetní operace a transakce, které je zastřešují. V práci jsou dokumentovány známé postupy v implementaci uložení dat. Přínosem této práce je zasazení těchto obecných postupů do konkrétního řešení využitelného v aplikacích, které pracují se záznamem o přenosu finančních dat. Představeno je řešení v relační databázi Oracle a také řešení pro zástupce objektových databází MongoDB. Relační databáze Oracle je ve své verzi 11g (nejedná se o poslední verzi) vyspělým systémem pro řízení a správu dat. Pro potřeby úložiště PFM aplikace bylo vyžito několik funkčností, které vedou k efektivnější práci s daty. Je třeba zmínit bohatou škálu různých typů indexů, jimiž Oracle disponuje. Správné nastavení indexů má potom zcela zásadní vliv na výkonnost celého systému. Po nasazení vhodných indexů dochází k řádovému zlepšení odezvy databázových dotazů. Oproti MongoDB byly využity i některé specifické indexy, jako např. bitmapový index, který je vhodný u sloupců s velmi malou variabilitou hodnot. Protože PFM aplikace pracují většinou s omezeným množstvím dat určitého období, byla využita i schopnost rozdělit data do menších logických celků na základě období . tzv. partitioning. Rozdělením dat do menších bloků, nejenom že zmenšujeme množinu dat, se kterou dotaz pracuje, ale jsme schopni data rozdělit na různá fyzická úložiště (různě výkonná a nákladná). Další aplikovanou funkčností Oracle jsou materializované pohledy. Ty zde poskytují rychlý přístup k předem agregovaným datům. 54 Databáze MongoDB zdaleka neposkytuje takovou škálu nástrojů, jakou oplývá databáze Oracle. Přesto kromě základní výbavy poskytuje nástroje, které bychom jinde těžko hledali. I zde dochází k výraznému poklesu v odezvě dotazu za použití indexů. Pro navrhované struktury a konstrukce dotazů nedosahovaly dotazy v implementaci MongoDB takové odezvy, jako v případě implementace v Oracle. Nedocenitelnou vlastností MongoDB je však možnost distribuce databáze na několik serverů. Vlastnost se nazývá sharding a jde o mocný nástroj, který skýtá široké možnosti při škálování výkonu. Není smyslem této práce a dost dobře ani není možné hledat vítěze porovnání objektové a relační databázi. Práce pouze poukazuje na rozdílné možnosti obou implementací a dokladuje, že PFM aplikace lze provozovat v obou databázích. 55 8. Seznam použitých zdrojů [1] FOWLER, Martin: Analysis Patterns – Reusable Object Models. ,Addison Wesley, 1998, ISBN: 0-201-89542-0 [2] RIORDAN, M, Rebecca: Vytváříme relační databázové aplikace, Computer Press, Praha 2000, ISBN: 80-7226-360-9 [3] STONEBRAKER, Michael, BROWN Paul: Objektově relační SŘBD, analýza příští velké vlny, BEN – technická literatura, Praha 2000, ISBN 80-86056-94-5,str. 19 [4] HEY, David C.: Data model patterns: Conventions of Though, New York: Dorset House 1996, ISBN 0-932633-29-3 [5] ŠEŠERA, L., MIČOVSKÝ, A., ČERVEŇ J. Datové modelování v příkladech. Praha: Grada Publishing 2001, ISBN 80-247-0049-2 [6] HERNANDEZ, Michael J., Návrh databází, Praha: Grada Publishing 2005, ISBN 80-247-0900-7 [7] KNUTH, Donald E., Art of Computer Programming, Volume 3: Sorting and Searching, Addison-Wesley 1998 | ISBN 0201896850 [8] International Journal of Computer Science and Electronics Engineering (IJCSEE) Volume 1, Issue 2 (2013) ISSN 2320–4028, Software Architecture of Online Personal Finance Management System, Hossain. Syed Akhter, Akter. Nasrin, and Akhter. Maria [9] LANE, Paul, Oracle Database Data Warehousing Guide, 11g Release 2 (11.2), Oracle 2013, dostupné z: http://docs.oracle.com/cd/E11882_01/server.112/e25554/toc.htm [10] CHAN, Immanuel, ASHDOWN Lance, Oracle Database Performance Tuning Guide, Oracle 2013, dostupné z: http://docs.oracle.com/cd/E11882_01/server.112/e41573/toc.htm [11] KIMBALL, Ralph, ROSS, Margy, The Data Warehouse Toolkit: The Complete Guide to Dimensional Modeling, Wiley 2002, ISBN 0471200247 [12] HERNANDEZ, Michal J., Database Design for Mere Mortals, Addison-Wesley 2003, ISBN 0-201-75284-0 [13] The MongoDB 2.4 Manual, Dostupné z: http://docs.mongodb.org/manual/ 56 9. Seznam obrázků Obrázek 2-1: Vztah dvou entit znázorněný v ER diagramu. Obrázek 2-2: Notace kardinality vztahů Obrázek 3-1 matice DB systémů Obrázek 5-1 entity PFM systému Obrázek 5-2 účet a účetní záznam Obrázek 5-3 transakce Obrázek 5-4 sumární účty a detailní účty Obrázek 5-4 sumární účty a detailní účty Obrázek 5-5 náklady a nákladové kategorie Obrázek 5-6 tabulky a relace pro oblast účtů a transakcí Obrázek 5-7 výsledek funkce EXPLAIN PLAN v Oracle SQL Developer 57 10. Seznam tabulek Tabulka 5-1 hodnoty měření selectu bez nasazení indexů Tabulka 5-2 hodnoty měření selectu po nasazení indexů Tabulka 5-3 hodnoty měření selectu po nasazení partitions Tabulka 5-4 hodnoty měření s použitím materializovaných pohledů Tabulka 5-5 seznam 20ti největších segmentů v MB Tabulka 6-1 hodnoty měření na MongoDB bez použití indexů Tabulka 6-2 hodnoty měření na MongoDB s použitím indexu Tabulka 6-3 obsazení diskového prostoru daty jednotlivých kolekcí a jejich indexů 58 11. Přílohy 01_ddl.sql – zakládací skripty datových struktur v Oracle 02_seq.sql – založení sekvence na Oracle 03_inserts.sql – založení řádek číselníků v Oracle 04_functions_gen.sql – funkce pro generování testovacích dat v Oracle 05_constraint_drop_begore_generating.sql – pomocný skript pro vypnutí constraints při generování dat v Oracle 06_indexes.sql – vytvoření indexů v Oracle 07_constraint_reenable.sql – obnovení constraints po generování dat 08. rozedeleni_do_partition.sql – skripty které převedou existující tabulku ACCENTRY do tabulky rozdělené na partition 08_materialized_views.sql – skript pro založení materializovaného pohledu a jeho indexů export_to_mongodb.sql – skripty PL/SQL pro vytvoření exportní dávky ve formátu JSON indexy_vypnout_zapnout – zneplatnění a obnovení indexů, které slouží pro testování chování DB Oracle bez indexů měření.xlsx – záznamy naměřených hodnot MongoDB skripty – různé mongoDB skripty, dotazy, parametry pro mongoimport pred_po_migraci.sql – pomocné skripty pro Oracle, které slouží pro akceleraci migrace, popř. přesunu datových souborů na jiná úložiště select_for_longloops.sql – select, který ověřuje průběh exportu do JSON selecty.sql – dotazy do pro DB Oracle, které jsou zmíněny v práci velikosti_db_objektu.sql – zjištění velikosti objektů v DB Oracle 59
Podobné dokumenty
Automatic Storage Management (ASM)
ASM dokáže pracovat i s jejími částmi (např.
jemnější striping používá 128 KB bloky)
soubory rozděleny na bloky této velikosti a
umístěny na disky dle nastavené politiky
(striping, mirroring…) do...
Výzkumné centrum Pokročilé sanační technologie a procesy
Zdeněk Kučera, Josef Pour, Helena Paběradová, Milada Bernášková, a Jan Lochman) byla zaměřena na
experimentální výzkum in situ a vybudování a vedení laboratorních experimentů v nových laboratořích
...
Sborník příspěvků
a velkou variabilitu klientských zařízení. Platforma J2EE nabízí pouze dvě technologie, nepočítáme-li Swing jakožto desktopovou variantu dostupnou ve standardní J2SE platformě.
JavaServer Pages (JS...
UNICORN COLLEGE BAKALÁŘSKÁ PRÁCE
zátěžové testování DB jsem vypracoval samostatně pod vedením vedoucího bakalářské
práce a s použitím odborné literatury a dalších informačních zdrojů, které jsou v práci
citovány a jsou též uvedeny...
3 Ladění databázového systému Oracle
dokumenty přístupné kdekoli, je dobré použít jako klienta nejrozšířenějšího klienta, což je
internetový prohlížeč. Z toho také vyplívá, že aplikace, by měla být webovou aplikací.
Požadavky na takov...
Petr Šaloun and Dušan Chlapek
Efektivní využívání systémů zahrnujících zpracování velkých objemů dat vyžaduje
v mnoha aplikačních scénářích odpovídající nástroje pro ukládání a zpracování těchto dat
na nízké úrovni a analytické...