view = vjúTakéPohled, SQL view, Virtuální tabulkaPokročilý
Definice
Databázový pohled je pojmenovaný uložený SELECT dotaz, na který se v databázi odkazuje jako na tabulku. Pohled sám o sobě data neukládá: při každém použití se jeho definice vyhodnotí nad zdrojovými tabulkami. Slouží k zjednodušení složitých dotazů, k omezení přístupu na vybrané sloupce a řádky a ke stabilnímu rozhraní nad měnícím se datovým modelem.
Než se na to spolehnete: Tvrzení o chování CREATE OR REPLACE VIEW a o absenci nativních materializovaných pohledů v MySQL platí pro současné hlavní verze, ale jde o detail, který se mezi databázemi liší; doporučuji ověřit proti verzi, kterou používá cílové publikum.
Co pohled ve skutečnosti je
Databázový pohled je záznam v katalogu databáze, který spojuje jméno s textem dotazu. Když se na pohled odkážete v klauzuli FROM, plánovač jeho definici vloží do vašeho dotazu a optimalizuje celek dohromady. Výsledkem je jediný plán nad skutečnými tabulkami, ne dvě samostatná vyhodnocení. Proto pohled nezabírá místo na disku a proto se jeho obsah mění spolu se zdrojovými daty.
Tři důvody, proč pohledy vznikají
Prvním důvodem je opakování. Spojení pěti tabulek přes cizí klíče, které se objevuje v deseti reportech, se napíše jednou a dál se používá jako jedno jméno. Chyba se pak opravuje na jednom místě.
Druhým důvodem je bezpečnost. Uživateli lze odebrat právo na tabulku zamestnanci a dát mu právo jen na pohled, který vynechává sloupec se mzdou nebo filtruje řádky na jeho oddělení. Databáze tak vynucuje omezení sama, nezávisle na aplikaci.
Třetím důvodem je odstínění změn. Když se tabulka rozdělí kvůli normalizaci, pohled se stejným jménem a stejnými sloupci udrží starší aplikace v chodu.
Kdy je pohled zapisovatelný
Jednoduchý pohled nad jednou tabulkou bez agregací, DISTINCT a GROUP BY bývá automaticky zapisovatelný: INSERT a UPDATE se přeloží na zápis do zdrojové tabulky. Jakmile pohled obsahuje spojení nebo agregaci, databáze neví, do kterého řádku zápis patří, a příkaz odmítne. Řešením je pravidlo nebo trigger typu INSTEAD OF, kde zápis dopíšete ručně.
Cena za pohodlí
Pohled nezrychluje nic. Dotaz nad pohledem stojí přesně tolik, kolik stojí jeho definice, a pokud pohled agreguje milion řádků, zaplatíte to při každém volání. Nebezpečné je i vrstvení: pohled nad pohledem nad pohledem vypadá čistě, ale plánovač nakonec skládá dotaz přes tucet tabulek a odhady kardinalit se rozjedou. Filtr, který napíšete zvenku, se navíc do definice nemusí propsat, pokud jej blokuje okno nebo agregace.
Materializovaný pohled jako druhý režim
Materializovaný pohled výsledek skutečně uloží na disk a chová se jako tabulka s indexy. Čtení je pak rychlé, ale data jsou stará od posledního obnovení příkazem REFRESH. Hodí se na těžké agregace v reportingu, kde je zpoždění v řádu minut přijatelné. PostgreSQL i Oracle materializované pohledy podporují nativně, MySQL nikoli a řeší se tam pomocnou tabulkou plněnou dávkově.
Praktická pravidla
- Pohled pojmenujte podle významu, ne podle tabulek, ze kterých čerpá.
- Vrstvení držte na dvou úrovních; hlubší řetězec je pro plánovač i pro čtenáře past.
- U pohledů určených pro oprávnění zvažte
WITH CHECK OPTION, aby zápisem nevznikl řádek mimo definici pohledu. - Než pohled zmaterializujete, změřte skutečný dotaz. Často stačí chybějící index.
Příklady z praxe
Pohled jako bezpečnostní filtr nad mzdami
Personální tabulka obsahuje mzdy, ale manažeři potřebují jen kontakty a oddělení. Vytvoří se pohled bez citlivých sloupců a manažerská role dostane právo pouze na něj. Aplikace se tak nemusí starat o skrývání sloupců, protože samotná databáze citlivá data nikdy nevydá.
CREATE VIEW zamestnanci_verejne AS SELECT id, jmeno, email, oddeleni_id FROM zamestnanci WHERE datum_odchodu IS NULL; REVOKE ALL ON zamestnanci FROM manazer; GRANT SELECT ON zamestnanci_verejne TO manazer;Denní tržby v e-shopu a přechod na materializaci
Report tržeb spojuje objednávky s položkami a agreguje po dnech. Jako běžný pohled se počítá při každém otevření dashboardu a nad miliony řádků trvá desítky sekund. Po převodu na materializovaný pohled s indexem nad dnem se dotaz vrací okamžitě a data se obnovují jednou za hodinu naplánovaným REFRESH.
CREATE MATERIALIZED VIEW trzby_denne AS SELECT date_trunc('day', o.vytvoreno) AS den, SUM(p.cena * p.mnozstvi) AS trzba FROM objednavky o JOIN polozky p ON p.objednavka_id = o.id WHERE o.stav = 'zaplaceno' GROUP BY 1; CREATE INDEX ON trzby_denne (den); REFRESH MATERIALIZED VIEW CONCURRENTLY trzby_denne;
Časté omyly
- MýtusPohled je rychlejší než ten samý dotaz napsaný ručně.
- Ve skutečnostiPohled je jen uložený text dotazu, který se při použití vloží do plánu. Výkon je stejný jako u ručně napsaného dotazu; zrychlení přinese až materializovaný pohled nebo vhodný index.
- MýtusPohled zabírá místo v databázi, protože v sobě drží data.
- Ve skutečnostiKlasický pohled ukládá pouze definici a spotřebuje jednotky kilobajtů v katalogu. Data drží zdrojové tabulky. Místo na disku zabírá až materializovaný pohled, který výsledek skutečně uloží.
- MýtusDo pohledu se nedá zapisovat.
- Ve skutečnostiJednoduchý pohled nad jednou tabulkou bez agregace bývá zapisovatelný automaticky. U složitějších pohledů se zápis povolí triggerem nebo pravidlem INSTEAD OF, který určí, kam se data uloží.
Časté dotazy
- Kdy použít databázový pohled místo dotazu v aplikaci?
- Databázový pohled se vyplatí tehdy, když stejnou logiku potřebuje víc konzumentů: aplikace, BI nástroj, exportní skript i ruční dotazy analytiků. Definice pak žije na jednom místě a její oprava se projeví všude. Naopak dotaz specifický pro jednu obrazovku jedné aplikace patří spíš do kódu, kde jej má tým ve verzování a v code review. Rozhodujícím kritériem bývá vlastnictví logiky: pokud pravidlo patří datům, patří i do databáze.
- Jak se verzují změny pohledů při nasazení?
- Definice pohledů patří do migračních skriptů stejně jako tabulky. Většina týmů používá CREATE OR REPLACE VIEW, což zachová oprávnění, ale neumožní změnit pořadí ani typy existujících sloupců; při takové změně je nutné pohled smazat a vytvořit znovu a poté znovu přidělit práva. U řetězců závislých pohledů je potřeba respektovat pořadí, protože DROP na spodní pohled selže nebo si vyžádá CASCADE, který tiše smaže i nadřazené pohledy.
- Proč je dotaz nad pohledem pomalý, i když má tabulka index?
- Pomalý dotaz nad pohledem obvykle znamená, že se filtr z vnějšího dotazu nedostal dovnitř k tabulce. Blokovat jej může agregace, DISTINCT, okenní funkce nebo LIMIT v definici pohledu: databáze musí nejdřív spočítat celý vnitřní výsledek a teprve pak filtrovat. Pomáhá podívat se na EXPLAIN, přesunout filtr přímo do definice pohledu, případně pohled parametrizovat pomocí funkce vracející tabulku.
- Jak často obnovovat materializovaný pohled?
- Interval obnovy materializovaného pohledu se odvozuje od toho, jak stará data ještě dávají smysl pro rozhodování. Finanční uzávěrka snese noční obnovu, provozní dashboard chce minuty. V PostgreSQL umožňuje REFRESH MATERIALIZED VIEW CONCURRENTLY obnovu bez blokování čtenářů, vyžaduje ale unikátní index a je pomalejší. U velkých objemů bývá levnější inkrementální řešení: vlastní tabulka doplňovaná jen o nové řádky podle časového razítka.
Zdroje
- CREATE VIEW(otevře se v novém okně)
- CREATE MATERIALIZED VIEW(otevře se v novém okně)
- CREATE VIEW(otevře se v novém okně)
- Views (SQL Server)(otevře se v novém okně)