Wybór typu danych to jak wybór narzędzia do roboty. Przecież nie będziesz używać śrubokręta, żeby wbić gwóźdź (mam nadzieję). Tak samo w bazie danych: właściwy typ danych mocno wpływa na wydajność, oszczędność pamięci i wygodę zarządzania danymi. Na przykład, jeśli trzymamy kasę w formacie REAL, możemy mieć problemy z dokładnością, a użycie TEXT zamiast VARCHAR dla krótkich stringów zwiększa ilość pamięci zajmowanej przez bazę.
Wybierając typ danych, zwróć uwagę na kilka rzeczy:
Charakter danych
Określ, do jakiej kategorii należą dane: liczby, stringi, wartości logiczne, daty czy coś bardziej złożonego, np. struktury JSON.
Ilość danych
Ile danych planujesz przechowywać? Na przykład, dla tekstów do 50 znaków lepiej wybrać VARCHAR(50) zamiast TEXT.
Dokładność i zakres
Czy musisz zachować wysoką dokładność (np. do obliczeń finansowych)? Chcesz ograniczyć zakres wartości?
Częstotliwość i charakter zapytań
Jak często będziesz sięgać po te dane? Pamiętaj, że złożone typy, jak JSONB, wymagają więcej zasobów do obsługi.
Przykłady wyboru typów danych
Różne dane — różne zadania. Czasem liczy się dokładność co do grosza, a czasem po prostu żeby wszystko się zmieściło. Poniżej przykłady, jak dobrać odpowiedni typ danych do konkretnej sytuacji.
Dane finansowe
Kiedy chodzi o przechowywanie kasy, jak w księgowości, błędy są niedopuszczalne. Dlatego najlepszym wyborem będzie typ NUMERIC, który daje wysoką dokładność. Na przykład chcemy tabelę z takimi kolumnami:
| Nazwa kolumny | Typ danych | Komentarz |
|---|---|---|
| id | SERIAL | Klucz główny |
| amount | NUMERIC(10, 2) | Dziesięć cyfr, z czego dwie po przecinku |
| currency_code | CHAR(3) | Kod waluty ISO, np. "USD", "EUR" |
| transaction_date | TIMESTAMP | Czas transakcji, domyślnie — aktualny czas |
Dlaczego nie REAL? Bo liczby zmiennoprzecinkowe mogą tracić dokładność, a to krytyczne przy finansach.
Dane tekstowe
Jeśli chcesz przechowywać nazwy użytkowników, adresy albo inne stringi, zawsze ustawiaj maksymalną długość, jeśli się da. Na przykład VARCHAR(50) zamiast TEXT. To pomaga uniknąć potencjalnych błędów i optymalizuje pamięć.
| Nazwa kolumny | Typ danych | Komentarz |
|---|---|---|
| id | SERIAL | Klucz główny |
| username | VARCHAR(50) | Login użytkownika, unikalny i wymagany |
| VARCHAR(255) | ||
| bio | TEXT | Biografia, powiedzmy, tekst dużej długości |
Jeśli długość stringa jest sztywno ustalona (np. dwuznakowe kody krajów), użyj CHAR:
| Nazwa kolumny | Typ danych | Komentarz |
|---|---|---|
| code | CHAR(2) | Kod kraju ISO (np. "US"), klucz główny |
| name | VARCHAR(100) | Nazwa kraju, wymagane |
Dane dla znaczników czasu
Do przechowywania czasu zdarzeń lub harmonogramów najczęściej pasuje TIMESTAMP, bo zawiera jednocześnie datę i czas.
| Nazwa kolumny | Typ danych | Komentarz |
|---|---|---|
| id | SERIAL | Klucz główny |
| event_name | VARCHAR(100) | Nazwa wydarzenia |
| start_time | TIMESTAMP | Czas rozpoczęcia wydarzenia, wymagane |
| end_time | TIMESTAMP | Czas zakończenia wydarzenia, wymagane |
Jeśli potrzebujesz tylko czasu bez daty, użyj TIME, a jeśli tylko daty bez czasu — DATE.
Unikalne identyfikatory
Kiedy trzeba tworzyć identyfikatory, które będą unikalne globalnie, użyj UUID. Na przykład do generowania unikalnego identyfikatora transakcji:
| Nazwa kolumny | Typ danych | Komentarz |
|---|---|---|
| request_id | UUID | Unikalny identyfikator żądania, generowany domyślnie przez gen_random_uuid() |
| endpoint | VARCHAR(255) | Adres wywoływanego API-endpointa |
| timestamp | TIMESTAMP | Czas żądania, domyślnie — aktualny czas |
JSONB: złożone struktury
Kiedy trzeba przechowywać dane, których struktura może się zmieniać lub być złożona, np. ustawienia użytkownika czy metadane, użyj JSONB.
| Nazwa kolumny | Typ danych | Komentarz |
|---|---|---|
| user_id | SERIAL | Klucz główny (ID użytkownika) |
| preferences | JSONB | Ustawienia użytkownika w formacie JSON |
Z JSONB wygodnie się pracuje, ale pamiętaj, że może to obniżać wydajność przy dużej liczbie insertów/aktualizacji.
Tablice
Tablice są spoko, jeśli musisz przechowywać listy jednorodnych danych. Na przykład listę tagów:
| Nazwa kolumny | Typ danych | Komentarz |
|---|---|---|
| id | SERIAL | Klucz główny |
| title | VARCHAR(255) | Tytuł artykułu |
| tags | TEXT[] | Tablica tagów |
Przegląd typów danych według zadań
| Typ zadania | Rekomendowany typ danych | Przykład |
|---|---|---|
| Identyfikator rekordu | SERIAL, BIGSERIAL, UUID |
id SERIAL PRIMARY KEY |
| Ilość, liczby całkowite | INTEGER, BIGINT |
quantity INTEGER |
| Obliczenia finansowe | NUMERIC |
price NUMERIC(10, 2) |
| Przechowywanie stringów | VARCHAR(n), TEXT |
username VARCHAR(50) |
| Krótkie stałe stringi | CHAR(n) |
status CHAR(1) |
| Daty i czas | DATE, TIME, TIMESTAMP |
created_at TIMESTAMP DEFAULT NOW() |
| Unikalne identyfikatory | UUID |
id UUID PRIMARY KEY DEFAULT gen_random_uuid() |
| Złożone struktury (JSON) | JSONB |
metadata JSONB |
| Listy wartości | ARRAY |
tags TEXT[] |
| Wartość logiczna | BOOLEAN |
is_active BOOLEAN |
Pewnie już znasz wszystkie typy oprócz SERIAL. Chodzi o to, że SERIAL to w zasadzie ten sam INTEGER, który jest używany jako identyfikator wierszy w tabelach.
On automatycznie zwiększa się o 1 przy dodaniu nowego wiersza do tabeli. Czyli jeśli dodasz do tabeli 10 wierszy, to pierwszy będzie miał id 1, drugi - 2 itd. Więcej o tym wszystkim dowiesz się w następnej lekcji :)
GO TO FULL VERSION