Зачем нужно много типов INT, почему нельзя использовать один тип?
Databases → SQL → Types
Основная идея
Разные типы INT (TINYINT, SMALLINT, INT, BIGINT) существуют для оптимизации хранения данных — каждый тип занимает разное количество байт и поддерживает разный диапазон значений, что позволяет экономить дисковое пространство и память.
Ключевые аспекты
Размер хранения — TINYINT занимает 1 байт, INT — 4 байта, BIGINT — 8 байт
Диапазон значений — чем больше размер, тем больший диапазон чисел можно хранить
Производительность — меньшие типы быстрее обрабатываются и занимают меньше места в индексах
Экономия ресурсов — в таблице с миллионами записей разница в размере существенна
Плюсы правильного выбора типа
Экономия дискового пространства (особенно важно для больших таблиц)
Более эффективное использование кэша базы данных
Быстрее работа с индексами
Меньшее потребление оперативной памяти
Минусы использования только больших типов
Избыточный расход места: статус 0/1 в BIGINT — это 8 байт вместо 1
Замедление запросов при работе с большими объёмами данных
Неэффективное использование ресурсов сервера
Частые ошибки на собеседованиях
Считают, что разницы в производительности нет — на больших таблицах она значительная
Забывают про ограничения диапазона — переполнение TINYINT при значении > 127 (signed)
Не учитывают unsigned — диапазон удваивается для положительных чисел
Используют BIGINT везде "на всякий случай" — это плохая практика
Введение и проблематика
При проектировании базы данных выбор правильного типа данных — одно из ключевых решений. Может показаться, что проще использовать один универсальный целочисленный тип для всех случаев, но на практике это приводит к серьёзным проблемам с производительностью и хранением.
В таблице с 10 миллионами записей замена BIGINT на TINYINT для одной колонки экономит около 70 МБ дискового пространства.
Почему это важно?
База данных работает с дисковым пространством и оперативной памятью. Чем меньше места занимают данные:
Тем больше записей помещается в кэш
Тем быстрее читаются данные с диска
Тем эффективнее работают индексы
Тем меньше стоимость хранения
Базовая теория
Типы целых чисел в SQL
Тип
Размер
Диапазон (signed)
Диапазон (unsigned)
TINYINT
1 байт
-128 до 127
0 до 255
SMALLINT
2 байта
-32 768 до 32 767
0 до 65 535
MEDIUMINT
3 байта
-8 388 608 до 8 388 607
0 до 16 777 215
INT
4 байта
-2 147 483 648 до 2 147 483 647
0 до 4 294 967 295
BIGINT
8 байт
-9.2 × 10¹⁸ до 9.2 × 10¹⁸
0 до 1.8 × 10¹⁹
⚠️
MEDIUMINT (3 байта) поддерживается не во всех СУБД. В PostgreSQL его нет, используется SMALLINT или INT.
Визуализация размеров
graphLR A[TINYINT<br/>1 байт]--> B[SMALLINT<br/>2 байта] B --> C[INT<br/>4 байта] C --> D[BIGINT<br/>8 байт]
Практические примеры
Выбор типа для разных сценариев
sql
-- Возраст: 0-150 лет-- Используем TINYINT UNSIGNED (0-255)CREATETABLEusers ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,nameVARCHAR(100), age TINYINT UNSIGNED -- 1 байт, достаточно для возраста);
Сравнение размера таблиц
sql
-- Таблица со статусами (0/1/2)-- Плохо: используем INTCREATETABLEorders_bad ( id INTPRIMARY KEY,statusINT-- 4 байта на статус 0/1/2);-- Хорошо: используем TINYINTCREATETABLEorders_good ( id INTPRIMARY KEY,statusTINYINT-- 1 байт на статус 0/1/2);-- При 10 млн записей:-- orders_bad.status: 10 000 000 × 4 = 40 МБ-- orders_good.status: 10 000 000 × 1 = 10 МБ-- Экономия: 30 МБ только на одной колонке!
Влияние на производительность
Размер индексов
Индексы хранят копии значений колонок. Меньший тип = меньший индекс = быстрее поиск.
sql
-- Индекс на INT (4 байта) vs TINYINT (1 байт)-- При 1 млн записей:-- INT индекс: ~4 МБ-- TINYINT индекс: ~1 МБCREATEINDEXidx_statusON orders(status);
Кэширование
База данных кэширует часто используемые данные в RAM. Меньшие типы = больше данных в кэше = меньше обращений к диску.
graphTD A[Запрос данных]--> B{Данные в кэше?} B -->|Да| C[Быстрый ответ из RAM] B -->|Нет| D[Чтение с диска] D --> E[Загрузка в кэш] E --> C
Пограничные кейсы
🚫
Переполнение типа — критическая ошибка, которая может привести к потере данных или падению приложения.
Проблема переполнения
sql
-- Счётчик в TINYINT UNSIGNED (max 255)UPDATE counters SETvalue=value+1WHERE id =1;-- Когда value = 255, следующий инкремент вызовет ошибку-- или (в зависимости от настроек) обернётся в 0
Когда использовать BIGINT
sql
-- AUTO_INCREMENT ID для высоконагруженных систем-- Twitter: миллиарды твитов-- YouTube: миллиарды видеоCREATETABLEtweets ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, content TEXT, created_at TIMESTAMP);
INT UNSIGNED позволяет хранить ~4.3 миллиарда записей. Для большинства проектов этого достаточно на годы работы.
Рекомендации по выбору типа
Сценарий
Рекомендуемый тип
Обоснование
Булевые значения (0/1)
TINYINT(1)
1 байт, явная семантика
Возраст, рейтинг (1-5)
TINYINT
Диапазона 0-255 достаточно
Год
SMALLINT
0-65535 покрывает все года
Количество товаров
SMALLINT/INT
Зависит от масштаба бизнеса
ID записей
INT UNSIGNED
4.3 млрд записей — достаточно для 99% проектов
Большие счётчики
BIGINT
Просмотры, лайки в соцсетях
Плюсы и минусы разных подходов
Подход
Плюсы
Минусы
Всегда BIGINT
Никогда не переполнится
Расход места и памяти × 8
Точный подбор типа
Оптимальное использование ресурсов
Требует анализа данных
TINYINT для всего
Минимальный размер
Риск переполнения
Вопросы интервьюера
Q: Почему бы не использовать BIGINT везде для надёжности?
Это приводит к 8-кратному увеличению размера данных по сравнению с TINYINT. На больших таблицах это терабайты лишнего места, замедление запросов и увеличение стоимости хранения.
Q: Как понять, какой тип выбрать?
Оцените максимальное значение, которое может быть в колонке. Добавьте запас на рост. Выберите минимальный тип, который покрывает этот диапазон.
Q: Что произойдёт при переполнении типа?
Зависит от настроек SQL_MODE. Может быть ошибка, обрезание значения до максимума, или "заворачивание" (wrap around) к минимальному значению.
Q: Влияет ли тип колонки на размер NULL?
NULL хранится отдельно (обычно 1 бит на колонку в битовой маске), размер типа на NULL не влияет.