UNSIGNED — это модификатор числового типа, который запрещает хранение отрицательных значений и за счёт этого удваивает максимальный диапазон положительных чисел.
Ключевые аспекты
Только положительные числа — диапазон начинается с 0, а не с отрицательного значения
Удвоение диапазона — INT хранит до 2.1 млрд, INT UNSIGNED — до 4.3 млрд
Тот же размер — UNSIGNED не увеличивает размер хранения в байтах
Семантическая ясность — ID, возраст, количество не могут быть отрицательными
Плюсы использования UNSIGNED
Больший диапазон положительных значений без увеличения размера
Защита от случайной вставки отрицательных значений
Более понятная семантика данных
Оптимизация для AUTO_INCREMENT полей
Минусы
Не поддерживается в PostgreSQL (нужны CHECK constraints)
Ошибки при вычитании: 5 - 10 вызовет ошибку или переполнение
Сложности при миграции между СУБД
Частые ошибки на собеседованиях
Путают UNSIGNED с увеличением размера типа — размер остаётся прежним
Забывают про арифметические ошибки при вычитании
Не знают, что PostgreSQL не поддерживает UNSIGNED напрямую
Считают UNSIGNED обязательным для PRIMARY KEY — это рекомендация, не требование
Введение и проблематика
При работе с числовыми данными в базе данных часто возникают ситуации, когда значения по определению не могут быть отрицательными: идентификаторы, возраст, количество товаров, просмотры. Модификатор UNSIGNED позволяет явно указать это ограничение и получить дополнительные преимущества.
UNSIGNED удваивает максимальное положительное значение без увеличения размера хранения. INT UNSIGNED может хранить числа до 4 294 967 295 вместо 2 147 483 647.
Базовая теория
Как работает UNSIGNED
В компьютере числа хранятся в двоичном формате. Для signed (знаковых) чисел один бит используется для хранения знака (+ или -). UNSIGNED использует все биты для хранения величины числа.
graphTD A[INT - 32 бита]--> B[Signed] A --> C[Unsigned] B --> D[1 бит знака + 31 бит значения] C --> E[32 бита значения] D --> F[-2 147 483 648 ... +2 147 483 647] E --> G[0 ... 4 294 967 295]
Сравнение диапазонов
Тип
Signed диапазон
Unsigned диапазон
TINYINT
-128 ... 127
0 ... 255
SMALLINT
-32 768 ... 32 767
0 ... 65 535
INT
-2 147 483 648 ... 2 147 483 647
0 ... 4 294 967 295
BIGINT
-9.2 × 10¹⁸ ... 9.2 × 10¹⁸
0 ... 1.8 × 10¹⁹
Практические примеры
Типичные сценарии использования UNSIGNED
sql
-- ID не может быть отрицательным-- UNSIGNED удваивает максимальное количество записейCREATETABLEusers ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL);-- С UNSIGNED: до 4.3 млрд записей-- Без UNSIGNED: до 2.1 млрд записей
Объявление UNSIGNED в разных СУБД
sql
-- MySQL полностью поддерживает UNSIGNEDCREATETABLEexample ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,counterBIGINT UNSIGNED DEFAULT0);
Пограничные кейсы
⚠️
Арифметика с UNSIGNED может давать неожиданные результаты при вычитании.
Проблема вычитания
sql
-- MySQL с UNSIGNEDSET @a =CAST(5AS UNSIGNED);SET @b =CAST(10AS UNSIGNED);-- Ожидаем: -5-- Получаем: ошибку или огромное положительное число!SELECT @a - @b;-- Результат зависит от sql_mode:-- С STRICT_TRANS_TABLES: ошибка-- Без: переполнение (очень большое число)
Решение проблемы вычитания
sql
-- Вариант 1: приведение к signed перед вычитаниемSELECTCAST(@a AS SIGNED) -CAST(@b AS SIGNED);-- Вариант 2: использование GREATEST для защитыSELECTGREATEST(0, @a - @b);-- Вариант 3: проверка перед вычитаниемSELECTIF(@a >= @b, @a - @b, 0);
🚫
Никогда не используйте UNSIGNED для колонок, где возможны отрицательные результаты вычислений: балансы счетов, разницы значений, временные зоны.
Когда НЕ использовать UNSIGNED
sql
-- ❌ Баланс счёта (может быть отрицательным — овердрафт)balance INT UNSIGNED -- Плохо!balance INT-- Хорошо-- ❌ Разница температурtemp_diff INT UNSIGNED -- Плохо!temp_diff SMALLINT-- Хорошо-- ❌ Координаты (могут быть отрицательными)latitude DECIMAL UNSIGNED -- Плохо!latitude DECIMAL(10, 8) -- Хорошо
Преимущества UNSIGNED для PRIMARY KEY
sql
-- AUTO_INCREMENT с UNSIGNEDCREATETABLEorders ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, created_at TIMESTAMPDEFAULT CURRENT_TIMESTAMP);-- Преимущества:-- 1. Вдвое больше возможных ID (4.3 млрд vs 2.1 млрд)-- 2. Семантически корректно (ID не бывает отрицательным)-- 3. Небольшая оптимизация сравнений
Плюсы и минусы
Аспект
Плюсы
Минусы
Диапазон
Удвоение положительных значений
Потеря отрицательных
Семантика
Явное указание ограничения
Требует понимания
Размер
Без изменений
—
Переносимость
—
PostgreSQL/SQL Server не поддерживают
Арифметика
—
Проблемы с вычитанием
Вопросы интервьюера
Q: Увеличивает ли UNSIGNED размер хранения?
Нет. UNSIGNED использует те же байты, что и signed тип. Размер INT всегда 4 байта, независимо от UNSIGNED.
Q: Можно ли использовать UNSIGNED в PostgreSQL?
Напрямую нет. Нужно использовать CHECK constraint: CHECK (column >= 0) или создать пользовательский домен.
Q: Что произойдёт при вставке -1 в UNSIGNED колонку?
В MySQL с strict mode — ошибка. Без strict mode — значение обрежется до 0 или произойдёт переполнение.
Q: Обязательно ли использовать UNSIGNED для AUTO_INCREMENT?
Не обязательно, но рекомендуется. Это удваивает количество возможных ID и семантически корректно.