---
tags: Společný základ
---
Ukládání dat, adresování záznamů. Indexování a hašování více atributů, bitmapové indexy, dynamické hašování. Vyhodnocování dotazu a algoritmy, statistiky a odhady nákladů. Optimalizace dotazů a schémat, pravidla pro transformaci dotazů, rozdělování dat. Zpracování transakcí, výpadky a zotavení. Bezpečnost, přístupová oprávnění. (PA152)
# SZ 4. Databáze
Dalsi fajn zdroj https://github.com/asketak/statnice-umi/blob/master/1databaze.md
Budeme hovořit hlavně o RDBMS (Relational Database Management System) systémech. RDBMS tvoří softwarové vybavení, které zajišťuje práci s relační databází.
Hl. součásti databázového systému:
- **Storage Manager** - správa vyrovnávací paměti a bloků na disku
- **Query Processor** - překlad a vyhodnocení dotazu, optimalizace
- **Transaction Manager** - atomičnost, izolovanost a trvalost transakcí
Částí db systému:

## Ukládání dat
### Hierarchie pamětí
Databazi využívají celu hierarchii pameti:
| | rychlost klesa z hora nadol ▼, kapacita sa zvysuje ▲ |
|------------|----------------------------------------------------------|
| Primární | vyrovnávací (cache), *procesor* hlavní (operační), *RAM* |
| Sekundární | *disk, flash* |
| Terciární | záložní, *pásky, optické disky* |
#### Cache
- nejrychlejší a nejdražší, závislé na napájení
#### RAM
- rychlé (10-100 ns, 1 ns = 10–9 s)
- přiliš malé nebo drahé pro uložení celé databáze
- závislé na napájení
#### Rotační disk
- velká kapacita, nezávislost na napájení
- čtení a zápis téměř stejně rychlé

- **Access time** = čas mezi požadavkem na čtení/zápis a počátkem přenosu dat
- **Seek time** (vystavení hlaviček) = přesun na správnou stopu disku (4-10 ms)
- *Average seek time = ½ nejhorší případ seek time*
- **Rotační zpoždění** = čas pro otočení disku na správný sektor (4-11ms, 5400-15k rpm)
- *Average latency = ½ nejhorší případ latency*
- *atomická jednotka čtení je sektor/diskový blok, data jsou blokována*
- **Přenosová rychlost** = rychlost čtení/zápisu dat z/na disk
- náhodné čtení je pomalé, sekvenční čtení je rychlé
- **optimalizace přístupu v HW**: cache (buffery pro zápis, zálohovány baterií nebo flash), algoritmy pro minimalizaci pohybu hlavičky ("výtah")
#### SSD
- diskové úložiště na "flash" pamětech
- žádné pohyblivé části
- odolnější proti manualnemu poškození
- nižší přístupová doba a zpoždění
- 4x dražší než HDD (za GB)
- organizace do bloků (stránka 4KiB)
### Techniky přístupu k datům v DBMS
- Alg. v DBMS pracují s bloky (skup. sousedních sektorů disku) = atomická jednotka, 4KB – 16KB
- operace:
- čtení bloku
- zápis bloku *(otočení disku + čtení! kvůli ověření)*
- modifikace bloku: čtení, změna v paměti, zápis a ověření
Přístup na disk je velmi nákladný proto se ho DBMS snaží řešit aplikováním různých technik: eliminace náhodných přístupů, optimalizace objem dat (velikost bloku), použita organizace úložiště (diskové pole), double buffering
> Náklady:
> P = čas zpracování bloku
> R = čas k přečtení 1 bloku
> n = počet bloků ke zpracování
>
> Single Buffer: `n(R+P)`
>
> Double Buffering: *dva buffery v paměti používané střídavě*
>
> 
>
> ```
> if P ≥ R: R + nP
> else: nR + P
> ```
> [color=#df0000]
### Diskové pole
Diskové pole tvoří více disků uspořádaných do jednoho logického:
- zvětšení kapacity
- paralelní čtení / zápis
- průměrná doba vystavení hlaviček typicky zachována

Metody:
**Rozdělování dat (data striping)** = **zvýšení přenosové rychlosti rozdělením na
více disků**, snížení spolehlivosti, vyrovnání zátěže -> zvýšení propustnosti
- **Bit-level**: rozdělení každého bajtu na bity mezi disky *(přístupová doba je horší než u jednoho disku, málo používané)*
- **Block-level**: `n` disků, blok `i` je uložen na disk `(i mod n) + 1` => čtení různých bloků lze paralelizovat, pokud jsou na různých discích
**Zrcadlení dat (mirroring)** = logický disk sestaven ze 2 fyzických disků, zápis na každý z disků, čtení lze z libovolného disku => **zvýšení spolehlivosti pomocí replikace**
### RAID

RAID0: block striping, neredundantní, velmi vysoký výkon, ale snížená spolehlivost, nesnížená kapacita
RAID1: zrcadlení disků, kapacita 1/n, rychlé čtení, zápis jako 1 disk
RAID2: bit-striping, Hamming Error Correcting Code, zotavení z výpadku 1 disku
RAID3: Byte-striping with parity, zápis: spočítání a uložení parity, obnova jednoho disku = XOR **bajtů** z ostatních disků
RAID4: obnova jednoho disku = XOR **bloků** z ostatních disků, vyšší rychlost než RAID3 *(blok je čtený pouze z 1 disku -> paralelizace)*
- paritní disk je úzké místo! - zápis libovolného bloku vede k zápisu parity
RAID5: block-Interleaved Distributed Parity, rozděluje data i paritu mezi `n` disků (odstranění zátěže na paritním disku RAID4), vyšší výkon než RAID4: zápis bloků je paralelní, pokud jsou na různých discích
RAID6: P+Q Redundancy scheme, podobné RAID5, ale ukládá extra informace pro obnovu při výpadku více disků
RAID – kombinace: jednotlivé varianty polí lze kombinovat (RAID5+0, RAID1+0, RAID0+1)

### Výpadky disků
- občasný výpadek (jen chyba při čtení/zápisu), stačí opakovat
- vada média: moderní disky samy detekují a opraví
- detekce: kontrolní součty
- opravy: stabilní uložení *(diskové pole, uložení na více místech stejného disku, žurnálování (log/záznam změn))*, samoopravné kódy *(sudá/ lichá parita, Hamming, Reed-Solomon)*
- zničení disku: musí se úplně vyměnit disk
U disků se uvadza **Mean Time To Failure (MTTF)** (/ Mean Time Between Failures (MTBF)) - průměrná doba fungování mezi výpadky *(polovina disků má výpadek během této doby, snižuje s věkem disku)*.
> Prumerna doba mezi vypadky disku 1 000 000 a vice hodin = polovina disku failne za 114 let = 0.44% za rok = AFR(Anualized failure rate) MeanTimeTo Repair(MTTR) = Čas od výpadku do obnovení činnosti = čas výměny vadného disku + obnovení dat MTTDL(Mean time to data loss) - Musi nam vypadnout dalsi disk pri opravovani jineho. Stovky tisic let pro dva zrcadlici disk s MTTR = 3 hodiny.
>
> SSD jsou rychlejsi, ale zase maji presny pocet zapisu -> po jiste dobe dojde k uplnemu vypadku, V RAIDu vypadnou vsechny naraz.
> [color=#df0000]
## Adresování záznamů
RDBM si musí udržovat odkazy na záznamy (adresy) v paměti i na disku. To lze zajistit různymi přístupy:
### Přímá adresace
Jako identifikátor záznamu se využije fyzická adresa záznamu v úložišti (ID disku, stopa, povrch, blok, byte offset v bloku). Takové řešení je velmi přímočaré ale nepraktické, vyžaduje úpravu všech odkazů na objekt při realokaci bloku nebo záznamu.
### Nepřímá adresace:
- Převodní tabulka (map table):
- Udržuje sa tabuľka *ID → fyz. adresa*
- Nevýhodou jsou zvýšené náklady na průchod map table. Její velikost je omezena velikostí paměti nebo přístup k ní bude velmi pomalý.
- Výhodou je největší flexibilita
- Kombinace předchozích:
- *Fyz. adresa záznamu = fyz. adresa bloku + record offset*
- Lze přesouvat záznamy v bloku
- Presuvani bloku je obtiazne
- S využitím systému souborů:
- Používaná varianta v RDBMS systemoch
- *Adresa záznamu = ID souboru + číslo bloku + record offset v bloku*
- Uložení bloku (fyz. adresu) určuje file system
## Indexování
### Indexování a hašování více atributů
Možné řešení:
- Nezávislé indexy pro atributy + průnik vyhovujících
- Index v indexu
- Spojení klíčů v jeden
#### Nezávislé indexy pro atributy + průnik vyhovujících
Každý index vrátí seznam kandidátů; Průnik seznamů → výsledek dotazu
#### Index v indexu

#### Spojení klíčů v jeden
- V indexování velice podobné indexu pro jeden klíč pouze hodnota klíče je spojená: Např. zřetězení řetězců pri vkladani aj vyhladavni
- V hašování se využíva dělená hašovací funkce (funkce pre každy klíč vytvoří část výsledné adresy):

### Bitmapové indexy
Vhodne iba pre atributy s malym poctom moznych hodnot

Výhody
- Rychlé operace na bitech (AND, OR)
- Snadné kombinace více indexů dohromady
Aktualizace záznamů
- Nová hodnota → nové bitové pole
- Nový záznam → rozšíření všech polí
Paměťovou náročnost (typicky málo 1, hodně 0) je možné řešit kompresi pomocou RLE (Run-Length Encoding)
> 
> [color=#df0000]
### Dynamické hašování
Cílem dynamického hašování je přemísťovat pouze malý počet prvků ovlivněn jedním krokem zvětšení (na rozdíl od statického hašování které vyžaduje reorganizace). Vhodné pro měnící se data. Méně plýtvá místem (než statické hašování).
#### Rozšiřitelné
- Využití pouze několika **prvních** (horních) bitů adresy.
- Datová struktura se skládá z adresáře a kyblíků.
- Pokud při vkládání nového záznamu již v kyblíku podle hašované adresy není volné místo, dojde k rozštěpení kyblíku.
- Pokud je adresář plný → zdvojnásobení (přidání bitu).
- Podobně při mazání klíče může dojít k sloučení sousedních kyblíků (mající stejný prefix o jeden bit kratší) nebo zmenšení adresáře.

#### Lineární
- Využití pouze několika **posledních** (dolních) bitů adresy.
- Soubor roste lineárně a nevyžaduje žádnou dodatečnou překladovou tabulku. Ale využívá přetokové oblasti.

## Zpracování dotazu
### Vyhodnocení dotazu
- SQL dotaz
- Syntaktická a sémantická analýza (vytvoří strom dotazu)
- Konverze (vytvoří logický plán dotazu - podobný relační algebře)
- Aplikují se pravidla pro transformaci dotazů
- Odhadne se velikost jednotlivých relací a částí dotazu
- Vytvoří se možné fyzické plány dotazu
- Odhaduje se náklady pro každy fyzický plán a vybere nejlepší
- Vyhodnocení dotazu
- Výsledek
### Pravidla pro transformaci dotazů
Pravidla se vyuzivaj k optimalizaci relační algebry pomocí transformačních pravidel:
- Presunutí selekce nejblíže relacím
- Presunutí projekce nejblíže relacím
- Eliminace společných podvýrazů a duplicit
Pří klad transformačních pravidel:

### Odhad nákladů
Základní statistiky pro relaci R:
- $T(R)$ – počet záznamů
- $S(R)$ – velikost záznamu v bajtech
- $S(R,A)$ – velikost atributu (hodnoty) v bajtech
- $B(R)$ – počet obsazených bloků
- $V(R, A)$ – počet unikátních hodnot atributu A
- **Kartézský součin $W = R_1 × R_2$**
- $T(W) = T(R_1) \cdot T(R_2)$
- $S(W) = S(R_1) + S(R_2)$
- **Selekce $W = \sigma_{Z=val} (R)$**
- $S(W) = S(R)$
- Jedna z možností na odhad $T(W)$ je $T(W) = \frac{T(R)}{V(R,A)}$ (Predpokladame rovnomerné rozloženie hodnot mezi hodnotami v R)
- Alternativně můžeme předpokládat rovnoměrné rozložení hodnot v celé doméně alebo použiť ďalšiu podrobnejšiu štatistiku - histogram hodnot atributu (využití kvantizace a ukladní intervalu hodnot se stejným počtem záznamů).
- **Přirozené spojení**
- Ak $V(R_1, A) \leq V(R_2, A)$ předpokladáme 1 záznam se spojí s $\frac{T(R_2)}{V(R_2, A)}$ záznamy a rovnoměrné rozložení
- Obecný závěr: $T(W) = \frac{T(R_1) . T(R_2)}{\max{V(R_1, A), V(R_2, A)}}$
- je to jako Kartézský součin a selekce
### Algoritmy vyhodnocování dotazu
#### Jednoprůchodové algoritmy
Čtení relace → zpracování → výstupní paměť
- **Projekce, selekce, rušení duplicit (DISTINCT)**
- Náklady $B(R)$
- Algoritmus: otestuj, zda je již záznam ve výstupu. Jestli ne, přidej na výstup. Musíme si pamatovat už zpracované záznamy, ideálně s využitím hašování.
- **Agregační funkce (GROUP BY)**
- Náklady $B(R)$
- Algoritmus: vytvářejí se skupiny pro group-by atributy (pomocou hašování), a k ním se ukládají atributy pro agregačních funkce:
- MIN, MAX, COUNT, SUM – pouze jedno „číslo/hodnota“
- AVG – dvě čísla (SUM a COUNT)
- **Množinové sjednocení**
- Algoritmus: načti S, vybuduj vyhledávací strukturu. Eliminuj duplicitní řádky a unikátní řádky, hned vypisuj. Při čtení R ověřuj přítomnost záznamu vo vyhledávací strukture. Pokud není, pak vypiš a přidej do struktury.
- **Množinový průnik**
- Načti S, vybuduj vyhledávací strukturu. Při čtení R ověřuj přítomnost záznamu vo vyhledávací strukture. Je, pak vypiš a smaž z interní struktury.
- **Kartézský součin**
- Náklady $B(R) + B(S)$
- Algoritmus: menší relace se načte celá, větší se čte postupně a zpracovávají se dvojice záznamů.
#### Dvouprůchodové algoritmy
Předzpracování vstupu → uložení napríklad s využitím třídění (vícecestný MergeSort) alebo Hašování. A až poté zpracování.
https://www.vertica.com/docs/9.2.x/HTML/Content/Authoring/AnalyzingData/Optimizations/HashJoinsVs.MergeJoins.htm
Rozdíl mezi mergejoin a hash join je ten, že mergejoin je rychlejší pokud jsou již data / relace uspořádány. Optimalizátor si pak vybere který z nich je lepší použít.
- **Algoritmy pro spojení – MergeJoin**

- Vylepšení: není potřeba mít relace zcela uspořádané. Je možné číst uspořádané dávky a hned na nich provádět spojení bez ukládání uspořádané relace.
- **Algoritmy pro spojení – HashJoin**

## Optimalizace schémat
<span style="color:blue">modrý atribut</span> = primární klíč
### 1NF
požadavky:
- všechny attributy musí být atomické (nedělitelné)
#### Příklad, který není 1NF:
| <span style="color:blue">user_id</span> | fullname |
| -------- | -------- |
| 1 | Henry Foo |
| 2 | Boaty McBoatface |
#### Upraveno do 1NF:
| <span style="color:blue">user_id</span> | firstname | surname
| -------- | -------- | -------- |
| 1 | Henry | Foo |
| 2 | Boaty | McBoatface |
### 2NF
požadavky:
- musí být ve 1NF
- žádný atribut nesmí záviset na nějaké (necelé) části primárního klíče
#### Příklad, který není v 2NF:
| <span style="color:blue">manufacturer</span> | <span style="color:blue">model</span> | max_speed | manufacturer_country |
| -------- | -------- | -------- | -------- |
| Forte | X-Prime | 200 | Italy
| Forte | Ultraclean | 150 | Italy
| Dent-o-Fresh | EZbrush | 220 | USA
| Brushmaster | SuperBrush | 180 | USA
| Kobayashi | ST-60 | 240 | Japan
problémy:
- `manufacturer_country` je zde duplicitně pro každý řádek se stejným `manufacturer`
- hrozí nekonzistence
- plýtvání úložištěm
#### Upraveno do 2NF:
| <span style="color:blue">manufacturer</span> | manufacturer_country |
| -------- | -------- |
| Forte | Italy
| Forte | Italy
| Dent-o-Fresh | USA
| Brushmaster | USA
| Kobayashi | Japan
| <span style="color:blue">manufacturer</span> | <span style="color:blue">model</span> | max_speed |
| -------- | -------- | -------- |
| Forte | X-Prime | 200
| Forte | Ultraclean | 150
| Dent-o-Fresh | EZbrush | 220
| Brushmaster | SuperBrush | 180
| Kobayashi | ST-60 | 240
### 3NF
požadavky:
- musí být ve 2NF
- nesmí existovat tranzitivní závislost
#### Příklad, který není 3NF:
| <span style="color:blue">user_id</span> | username | skill_level | rank |
| -------- | -------- | -------- | -------- |
| 1 | mace-windu | 9 | Master |
| 2 | obi-wan | 8 | Master |
| 3 | anakin | 6 | Not Master |
problémy:
- `rank` je sice závislý na `user_id`:
- funkční závislost:
`user_id` → `rank`
- ale je závislý transitivně přes `skill_level`:
- `user_id` → `skill_level` → `rank`
- příklad je v 2NF protože zde není parciální závislost na části klíče
- ale jinak jde o podobný problém (a podobné důsledky)
#### Upraveno do 3NF:
| <span style="color:blue">user_id</span> | username | skill_level |
| -------- | -------- | -------- |
| 1 | mace-windu | 9 |
| 2 | obi-wan | 8 |
| 3 | anakin | 6 |
| <span style="color:blue">skill_level</span> | rank |
| -------- | -------- |
| 0 | Amateur |
| 1 | Amateur |
| 2 | Amateur |
| 3 | Intermediate |
| 4 | Intermediate |
| 5 | Intermediate |
| 6 | Not Master |
| 7 | Master |
| 8 | Master |
| 9 | Master |
| 10 | Master |
## Zpracování transakcí, výpadky a zotavení
Integrita = data jsou "bezesporná" a "správná"
- **Integritní omezení** = predikáty, které musí data splňovat *("x je primární klíč relace R, doména(fň) = {červená, modrá, zelená}, zaměstnanci nemají záporný plat")*
- *"konzistentní DB" je v konzistentním stavu (tj. splňuje všechna omezení)*
- **transakce** (soubor akcí měnící data, ale udržujících konzistenci):
`Konzistentní DB -> TRANSAKCE -> Konzistentní DB'`
Předpoklad: pokud transakce T začíná v konzistentním stavu a T
běží samostatně, T končí také v konzistentním stavu.
Příčiny porušení konzistence
- chyba transakce
- chyba DB systému
- výpadek HW
### Model výpadků
Shromáždíme možná rizika a řešíme výpadky jednotlivých komponent.

Kategorizace událostí (rizik):
```mermaid
graph LR
ud(události)-->zad(žádoucí)
ud -->nez(nežádoucí)
nez-->p(předpokládané)
nez-->nep(nepředpokládané)
```
Žádoucí: viz manuál DB systému
Nežádoucí očekávané: ztráta obsahu paměti, zastavení procesoru, reset procesoru, násilné vypnutí počítače
Nežádoucí neočekávané: vše ostatní *(ztráta dat na disku, chyba paměti bez zastavení procesoru, živelné pohromy)*
Jak omezit rizika? Přidáním kontrol na nejnižší úrovni. Redundance (zvýší pravděpodobnost zachování podmínek).
### Základní operace transakce
```
Input (x): blok obsahující x -> paměť
Read (x,t): a. Input(x), pokud je potřeba
b. t <- hodnota x v bloku
Write (x,t): a. Input(x), pokud je potřeba
b. hodnota x v bloku <- t
Output (x): blok obsahující x -> disk
```
**Atomičnost**: řešení problému nedokončených transakcí (provedení všech akcí transakce nebo vůbec žádné).
Implementačně: logování provedených změn (vytvoření **žurnálu** = souboru se záznamy o změnách)
- během transakce do žurnálu záznamy o změnách: `Začátek, konec, uložení, aktualizace,...`
- potom při obnově po výpadku systému: některé transakce se provedou znovu (REDO), některé transakce se zruší (UNDO)
#### Undo logging
= "zrušení podle žurnálu"
- změny prováděné transakcí jsou ihned ukládány na disk a pokud není 100% jistota uložení změn dokončené transakce, tak se změny podle žurnálu odstraní *(obnovení předchozího stavu DB)*
Pravidla
1. Pro každou akci write(X,t) vytvoř v žurnálu záznam obsahující $starou$ hodnotu X
2. Před změnou X na disku (output(X)) musí být na disku záznamy žurnálu týkající se X
(write ahead logging, WAL)
3. Před vytvořením záznamu <T, commit> v žurnálu musí být všechny zápisy transakce uloženy na disku.
Nevýhoda: ze zálohy DB nelze vytvořit aktuální stav DB.
#### Redo logging
= "znovu provedení podle žurnálu"
- změny provedené transakcí jsou ukládány později (při potvrzení (commit)) - ušetření zápisů na disk
- při obnově jsou ignorovány nedokončené transakce
- vyžaduje uložení žurnálu před uložením změn v DB
Pravidla
1. Pro každou akci write(X,t) vytvoř v žurnálu záznam obsahující $novou$ hodnotu X
2. Před změnou X na disku (v DB) (output(X)) musí být na disku všechny záznamy žurnálu (včetně commit) pro transakci měnící X
- 2a) Ulož záznamy žurnálu na disk
- 2b) Ulož změněná data na disk
- 2c) Zapiš end do žurnálu
Nevýhoda: všechny modifikované bloky musíme držet v paměti až do potvrzení (commit) transakce.
Kontrolní body (checkpoint) - př. UNDO/REDO logging: všechny změněné záznamy (bloky) jsou uloženy na disk.
#### Proces obnovy z výpadku
Zpětný průchod: *(z konce žurnálu na začátek posledního ukončeného kontrolního bodu)*
1. Vytvoř množinu S potvrzených transakcí
2. Vrať (undo) akce transakcí, které nejsou v S
Dopředný průchod:
1. Opakuj akce transakcí v množině S (bez end)
## Bezpečnost, přístupová oprávnění
- analogie se souborovým systémem
- specifická práva pro tabulky, pohledy, sekvence, schéma, databáze, procedury,...
- **základní nástroj pro řízení přístupu**: pohledy (VIEW)
- subjektem jsou obvykle uživatelé a skupiny (role + "ostatní" PUBLIC)
Práva pro relace (tabulky):
- SELECT – čtení obsahu (tj. výběr řádků, lze omezit na vybrané atributy)
- INSERT – vkládání řádků (lze omezit na vybrané atributy)
- DELETE – mazání řádků
- UPDATE – aktualizace řádků (lze omezit na vybrané atributy)
- REFERENCES – vytvoření cizího klíče
PŘ:
```sql=
INSERT INTO Beers(name)
SELECT beer FROM Sells
WHERE NOT EXISTS
(SELECT * FROM Beers
WHERE name = beer);
```
Požadavky: INSERT pro relaci Beers, SELECT pro relace Sells a Beers.
### Omezení přístupu pomocí pohledu
Relace: Zamestnanci(id, jmeno, adresa, plat)
Chci skrýt výši platu:
```sql=
CREATE VIEW ZamestnanciAdresa AS
SELECT id, jmeno, adresa
FROM Zamestnanci;
```
Odeberu práva SELECT na relaci Zamestnanci, přidám práva SELECT na ZamestnanciAdresa.
```sql=
-- Udileni prav:
GRANT <list of privileges>
ON <relation or object>
TO <list of authorization ID’s>;
GRANT SELECT
ON TABLE ZamestnanciAdresa
TO karel
WITH GRANT OPTION; -- povoli opravneni udilet prava
-- Odebirani prav:
REVOKE <list of privileges>
ON <relation or object>
FROM <list of authorization ID’s>;
```
Pozor: po odebrání práv REVOKE mohou mít uživatelé stále přístup
povolený (mohl jim ho udělit i někdo jiný, případně jsou členy nějaké skupiny, která má přístup).
```sql=
CASCADE -- zruší i oprávnění povolené uživatelem, kterému právě oprávnění odebírám
RESTRICT -- (implicitní volba) – odebere pouze toto oprávnění
```
Diagram reprezentující práva udělená kým a komu:

- oprávnění `all` pro tabulku = insert, update, delete, select, references
- oprávnění `*` (grant option) = oprávnění s povolením udílení oprávnění dalším
- oprávnění `**` = zdroj vzniku oprávnění (vlastník objektu)
- vlastník objektu má dovoleno vše, toto implikuje povolení udílet oprávnění dalším.