Выбор типа данных — это как выбор инструмента для работы. Вы же не будете использовать отвертку, чтобы забить гвоздь (надеюсь). Так и в базе данных: правильный тип данных существенно влияет на производительность, экономию памяти и удобство управления данными. Например, если мы храним деньги в формате REAL, то можем получить проблемы с точностью, а использование TEXT вместо VARCHAR для коротких строк увеличивает объем памяти, занимаемой базой.
При выборе типа данных учитывайте несколько факторов:
Характер данных
Определите, какой категории принадлежат данные: числа, строки, логические значения, даты или что-то более сложное, например, JSON-структуры.
Объем данных
Сколько данных вы планируете хранить? Например, для текстов до 50 символов лучше выбрать VARCHAR(50) вместо TEXT.
Точность и диапазон
Нужно ли поддерживать высокую точность (например, для финансовых расчетов)? Хотите ли ограничить диапазон значений?
Частота и характер запросов
Как часто вы будете обращаться к данным? Учитывайте, что сложные типы, такие как JSONB, требуют больше ресурсов на обработку.
Примеры выбора типов данных
Разные данные — разные задачи. Где-то важна точность до копейки, а где-то — просто чтобы всё влезло. Ниже примеры, как подобрать подходящий тип данных под конкретную ситуацию.
Финансовые данные
Когда дело доходит до хранения денег, как и в бухгалтерии, ошибки недопустимы. Поэтому лучшим выбором будет тип NUMERIC, который обеспечивает высокую точность. Например мы хотим таблицу с такими колонками:
| Имя колонки | Тип данных | Комментарий |
|---|---|---|
| id | SERIAL | Первичный ключ |
| amount | NUMERIC(10, 2) | Десять цифр, из которых две — после запятой |
| currency_code | CHAR(3) | ISO-код валюты, например "USD", "EUR" |
| transaction_date | TIMESTAMP | Время транзакции, по умолчанию — текущее время |
Почему не REAL? Дело в том, что числа с плавающей точкой могут терять точность, а это критично для финансов.
Текстовые данные
Если вы собираетесь хранить имена пользователей, адреса или любые другие строки, всегда задавайте максимальную длину, когда это возможно. Например, VARCHAR(50) вместо TEXT. Это помогает избежать возможных ошибок и оптимизирует память.
| Имя колонки | Тип данных | Комментарий |
|---|---|---|
| id | SERIAL | Первичный ключ |
| username | VARCHAR(50) | Логин пользователя, уникальный и обязательный |
| VARCHAR(255) | Электронная почта | |
| bio | TEXT | Биография, допустим, текст большой длины |
Если длина строки строго фиксирована (например, двухзначные коды страны), используйте CHAR:
| Имя колонки | Тип данных | Комментарий |
|---|---|---|
| code | CHAR(2) | ISO код страны (например, "US"), первичный ключ |
| name | VARCHAR(100) | Название страны, обязательно для заполнения |
Данные для временных меток
Для хранения времени событий или расписаний чаще всего подойдет TIMESTAMP, так как он одновременно содержит дату и время.
| Имя колонки | Тип данных | Комментарий |
|---|---|---|
| id | SERIAL | Первичный ключ |
| event_name | VARCHAR(100) | Название события |
| start_time | TIMESTAMP | Время начала события, обязательно |
| end_time | TIMESTAMP | Время окончания события, обязательно |
Если нужно только время без даты, используйте TIME, а если только дату без времени — DATE.
Уникальные идентификаторы
Когда необходимо создавать идентификаторы, которые будут уникальны на глобальном уровне, используйте UUID. Например, для генерации уникального идентификатора транзакции:
| Имя колонки | Тип данных | Комментарий |
|---|---|---|
| request_id | UUID | Уникальный идентификатор запроса, генерируется по умолчанию с помощью gen_random_uuid() |
| endpoint | VARCHAR(255) | Адрес вызываемого API-энпойнта |
| timestamp | TIMESTAMP | Время запроса, по умолчанию — текущее время |
JSONB: сложные структуры
Когда нужно хранить данные, структура которых может меняться или быть сложной, например, пользовательские настройки или метаданные, используйте JSONB.
| Имя колонки | Тип данных | Комментарий |
|---|---|---|
| user_id | SERIAL | Первичный ключ (ID пользователя) |
| preferences | JSONB | Настройки пользователя в формате JSON |
С JSONB удобно работать, но стоит учитывать, что это может снижать производительность при большом количестве вставок/обновлений.
Массивы
Массивы подходят, если нужно хранить списки однородных данных. Например, список тегов:
| Имя колонки | Тип данных | Комментарий |
|---|---|---|
| id | SERIAL | Первичный ключ |
| title | VARCHAR(255) | Заголовок статьи |
| tags | TEXT[] | Массив тегов |
Обзор типов данных по задачам
| Тип задачи | Рекомендуемый тип данных | Пример |
|---|---|---|
| Идентификатор записи | SERIAL, BIGSERIAL, UUID |
id SERIAL PRIMARY KEY |
| Количество, целые числа | INTEGER, BIGINT |
quantity INTEGER |
| Финансовые расчеты | NUMERIC |
price NUMERIC(10, 2) |
| Хранение строк | VARCHAR(n), TEXT |
username VARCHAR(50) |
| Краткие фиксированные строки | CHAR(n) |
status CHAR(1) |
| Даты и время | DATE, TIME, TIMESTAMP |
created_at TIMESTAMP DEFAULT NOW() |
| Уникальные идентификаторы | UUID |
id UUID PRIMARY KEY DEFAULT gen_random_uuid() |
| Сложные структуры (JSON) | JSONB |
metadata JSONB |
| Списки значений | ARRAY |
tags TEXT[] |
| Логическое значение | BOOLEAN |
is_active BOOLEAN |
Вы наверное уже знакомы со всеми типами кроме SERIAL. Все дело в том, что SERIAL - это фактически тот же INTEGER, который используется как идентификатор строк в таблицах.
Он автоматически увеличивается на 1 при добавлении новой строки в таблицу. Таким образом, если добавить в таблицу 10 строк, то у первой строки id будет 1, у второй - 2 и т.д. Подробнее об этом всем вы узнаете в следующей лекции :)
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ