# Datovy typ primarniho klice -- popis a porovnani typu
## Popisy jednotlivych skumanych typov
### UUID (+GUID)
Universally Unique IDentifier je znacka pouzivana na jednozcnacnu identifikaciu lubovolnych veci v pocitacovych systemoch. Sklada sa z 128 bitov a bol definovany v RFC 4122. Hodnoty tohto identifikatoru nie su garantovane unikatne, ale pravdepodobnost kolizie je statisticky zanedbatelna. Pouzivaju sa napriklad v suborovych systemoch, ale jednym z vyuziti je ako unikatny kluc v databazovych tabulkach. V nami skumanom databazovom systeme PostgreSQL specialny datovy typ pre UUID a tiez od verzie 13 priama podpora pre generovanie UUID. Vyhodou pouzitia UUID oproti sekvencne generovanym klucom je ich globalna unikatnost. Casto ich preto najdeme napriklad v distribuovanych systemoch, kde nam nestaci unikatnost v ramci jednej tabulky. GUID je implementacia UUID v mnohych systemoch od Microsoftu, preto sa s nim stretneme vo vela produktoch od tejto firmy, napriklad v operacnom systeme Windows. V PostrgreSQL nie su podporovane a preto sa nimi zaoberat nebudeme.
#### Pouzitie v PostgreSQL a verzie
- datovy typ `uuid` ulozeny ako binarne 128 bitove cislo, nie ako string
- priklad v standardnej forme: `a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11`
- rozne verzie UUID su podporovane ako third-party modul `uuid-ossp`, ktory poskytuje funkcie `uuid_generate_vX`
- format je vo verziach vzdy rovnaky, rozny je algoritmus a data pouzite na generaciu
- napriklad verzia 1 pouziva kombinaciu aktualnej MAC adresy, casovej znamky a nahodnej hodnoty
- v sucasnosti najviac pouzivana verzia 4 je tvorena cisto na zaklade nahodnych cisel
- priklad DDL s uuid typom:
```sql
CREATE TABLE contacts (
contact_id uuid DEFAULT uuid_generate_v4 (),
first_name VARCHAR NOT NULL,
last_name VARCHAR NOT NULL,
email VARCHAR NOT NULL,
phone VARCHAR,
PRIMARY KEY (contact_id)
);
```
- v PostgreSQL verzie 13+ pomocou funckie `gen_random_uuid()`, tvori UUIDv4 a nie je treba ziadne externe moduly
### Network address
- Jedna z moznosti je pouzit textove typy a do nich ulozit textovu reprezentaciu adresy
- PostgreSQL dokumentacia odporuca pouzivat specialne typy **inet**, **cidr** a **macaddr** na pracu s adresami kvoli dodatocnym input error checkom a specializovanym funkciam a operatorom (toto moze mat performance overhead)
- Mohlo by byt zaujimave porovnat rychlost stringu a inet pre vkladanie a search
- Dalej sa da sledovat velkost, aku jednotlive typy zaberaju na disku
#### inet and cidr
- 7 alebo 19 bajtov
- inet drzi adresu, pripadne jej podsiet
- cidr drzi adresu siete
- definicia:
```c=
typedef struct
{
unsigned char family; /* PGSQL_AF_INET or PGSQL_AF_INET6 */
unsigned char bits; /* number of bits in netmask */
unsigned char ipaddr[16]; /* up to 128 bits of address */
} inet_struct;
typedef struct
{
char vl_len_[4]; /* Do not touch this field directly! */
inet_struct inet_data;
} inet;
```
#### macaddr
- Uklada MAC adresy zname napr. z hardwerovych adres eternetovych kart
- Standardne formaty zapisu:
```
'08:00:2b:01:02:03'
'08-00-2b-01-02-03'
```
- Alternativa by opat mohol byt varchar
### Geometricke typy
- zakladny geometricky typ **point** je bod v dvojrozmernom priestore
- uklada sa ako dvojica (x, y) kde x a y su typu float a dokopy zaberaju 16 bajtov
- tento typ ako primarny kluc by default pouzit nejde lebo postgres ho nevie indexovat bez pouzitia custom operator class (co je task na ktori sa bezni uzivatelia postgres neodhodlaju)
- geometrickym bodom sa teda z hladiska vykonnosti dalej zaoberat nebudeme
### Cela cisla (int, bigint)
#### Int a Bigint
Datovy typ celych cisel. Rozidl mezi bigint a int je v poctu bajtu pouzitych pro ulozeni hodnoty. Integer pouziva 4 bajty a bigint pouziva 8 bajtu. Tedy integer ma rozsah od -2 147 483 648 do +2 147 483 647 a bigint ma rozsah od -9 223 372 036 854 775 808 to +9 223 372 036 854 775 807. Pri preteceni vyhodi postgreSQL error.
Cela cisla jsou dobre vybalancovane v ramci vyhledavani v rozmezi, velikosti a rychlosti.
#### Serial a bigserial
Jedna se o odnoze celych cisel s rozsahem od 1 do 2 147 483 647 pro serial a od 1 do 9 223 372 036 854 775 807 pro bigserial. Da se rict, ze se jedna o celocisleny typ, ktery je navic zabaleny spolecne s `AUTO_INCREMENT` funkci. Chovaji se tedy stejne jako cela cisla.
#### Pripady uziti celych cisel jako primarni klic
- Telefonni cisla -- vhodna pro ulozeni dat o cisle u operatoru
- Rodne cislo -- pro ulozeni zamestnance
#### Priklad pouziti integer jako primarniho klice
```sql=
CREATE TABLE meal (
meal_id SERIAL PRIMARY KEY, -- integer with autoincrement
cook_name VARCHAR(20),
description TEXT
);
```
#### Vyhody a nevyhody pouziti celych cisel jako primarni klic
| vyhody | nevyhody |
| -------------------- | -------- |
| Jednoduche | V url adresach je velmi jednoduche id rozpoznat. Pokud nema web dobre osetrene prava, muze se uzivel dostat tam, kam by nemel. |
| Zabiraji malo pameti | Casto bez pridane informace (arbitralni cislo) |
| Jednoducha citelnost | |
| Rychle | |
#### Reference
- https://www.postgresql.org/docs/current/datatype-numeric.html
- https://exceptionnotfound.net/integers-vs-guids-the-great-primary-key-debate/
- https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-primary-key/
### Textové typy (char, varchar, text)
#### Char(n), varchar(n)
Char(n) je dátový typ, ktorý ukladá presne n znakov. Pokiaľ je počet znakov menší ako n doplní medzery. Char bez n je rovný Char(1).
Varchar(n) je dátový typ, do ktorého je možné uložiť maximálne n znakov.
V oboch prípadoch pokus o uloženie viac ako n znakov vyústi v chybu.
#### Varchar, text
Varchar bez n ukladá stringy hocijakej veľkosti.
Text ukladá stringy hocijakej veľkosti.
varchar a text by mali mať rovnaký výkon (otestovať v praxi?)
### Veľkosť
Veľkosť záznamu je pre krátke stringy (do 126B) 1B + veľkosť stringu v B. Pre väčšie stringy je 4B + veľkosť stringu. Maximálna veľkosť stringu je 1GB.
#### Tip
There is no performance difference among these three types, apart from increased storage space when using the blank-padded type, and a few extra CPU cycles to check the length when storing into a length-constrained column. While character(n) has performance advantages in some other database systems, there is no such advantage in PostgreSQL; in fact character(n) is usually the slowest of the three because of its additional storage costs. In most situations text or character varying should be used instead.
Generovanie IDs tip:
https://stackoverflow.com/questions/19530736/how-can-i-generate-a-unique-string-per-record-in-a-table-in-postgres
#### References
- https://www.postgresql.org/docs/current/datatype-character.html
- https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-char-varchar-text/
## Vzajemne porovnani
| Cela cisla | Text | UUID (GUID) | inet a cidr |
| ------------------------------------------------- |:------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| + Jednoduche | + možno vkladať náhodné hodnoty | + globalna unikatnost | - umoznuje rozne dotazy specificke pre adresy "is in network", nerovnost... |
| + Zabiraji malo pameti | + uložená informácia môže mať informačnú hodnotu | - potencialne kolizie (velmi mala sanca) | - dokazu ulozit konkretnu adresu aj siet |
| + Jednoducha citelnost | - netrivialné vytváranie kľúča | - az 128 bitov | |
| + Rychle | - zložité indexovanie | + nativna podpora v Postgre | |
| - Citelne uzivatelem --> mozne bezpecnosti riziko | - zaberá veľa miesta | + v novych verziach pouzitie modernych algoritmov na generaciu nahodnych cisiel, rychle a spolahlive | |
| - Casto bez pridane informace (arbitralni cislo) | | | |
| inet | varchar |
|----------------------------------- | -------------------------------- |
| - obsahuje dotazy na rovnost/rozsah | - da sa dotazovat len na rovnost |
| - velkost 19B | - velkost = pocet znakov adresy (masky) |