DBAtlas · Атлас эксплуатации баз данных

Решение: выбор правильного типа данных

Выбор типа данных — одно из самых дорогих для последующего исправления решений: неверный тип даёт неверные результаты (например, float для денег), лишнее место и медленные запросы. Это дерево ведёт к правильному типу для числовых, текстовых полей, даты/времени, ключа (PK), полуструктурированных (JSON) и категориальных (ENUM) полей и указывает на классические ловушки, такие как деньги и кодировки.

Какие данные вы храните?

Правильный тип определяется природой данных. К какой категории относится поле: число, текст, дата/время, первичный ключ таблицы, гибкие/полуструктурированные (JSON) данные или ограниченный набор категорий?

  • Числовое значение (количество, деньги, измерение, счётчик)
  • Текст (имя, описание, код)
  • Дата и/или время
  • Я проектирую первичный ключ (PK)
  • Гибкие/вложенные/переменные поля (полуструктурированные данные)
  • Ограниченный известный набор категорий (статус, тип, приоритет)

Число целое или дробное — и это деньги?

Для чисел самое важное различие — точность. Значение целое (количество, ID, счётчик) или дробное? Если дробное, это ДЕНЬГИ/финансовая сумма? Двоичная плавающая точка (FLOAT/DOUBLE) никогда не используется для денег и везде, где требуется точность, так как даёт ошибки округления.

  • Целое (количество, счётчик, id)
  • Деньги или точное десятичное (цена, баланс, ставка)

Рекомендация: целое (SMALLINT / INT / BIGINT)

Для целых выбирайте наименьший тип, покрывающий нужный диапазон. Неоправданно большой тип тратит место и увеличивает размер индекса; но для растущих полей, таких как счётчики/PK, достаточная разрядность обязательна, чтобы избежать переполнения.

Рекомендация: NUMERIC / DECIMAL — НИКОГДА не FLOAT для денег

Для денег и точных десятичных значений используйте NUMERIC/DECIMAL с фиксированной точкой (точные). FLOAT/DOUBLE — двоичная плавающая точка, они не могут точно хранить значения вроде 0.1; сложение/умножение даёт расхождения в копейках, неверные балансы и проблемы при аудите.

Рекомендация: текст — VARCHAR vs TEXT vs CHAR

Для текста используют VARCHAR/TEXT при переменной длине и CHAR при действительно фиксированной длине. В современных СУБД разница в хранении между VARCHAR и TEXT в основном пренебрежимо мала; реальное решение — вводить ли смысловое ограничение (ограничение длины).

Рекомендация: дата/время — TIMESTAMP с часовым поясом

Если вы храните момент времени (время события), выбирайте тип с учётом часового пояса. Хранение без часового пояса ведёт к неверным вычислениям и сравнениям между регионами/при переходе на летнее время.

Рекомендация: первичный ключ — BIGINT vs UUID

Для PK есть два основных варианта: возрастающее число (BIGINT identity/sequence) или UUID. Числовой PK мал и удобен для индекса, но предсказуем и требует централизованной генерации; UUID можно генерировать распределённо, но он больше, а его случайный порядок может вредить индексу.

Рекомендация: JSON / JSONB — используйте умеренно

Тип JSON удобен для полей с гибкой схемой, вложенных или разреженных полей; но реляционная дисциплина (ограничения, индексы, типобезопасность) может быть утрачена. Правило: выносите постоянные и часто запрашиваемые поля в обычные столбцы, в JSON держите только действительно изменчивую часть.

Рекомендация: ENUM vs справочная (lookup) таблица

Для ограниченных наборов категорий есть два варианта: тип ENUM СУБД или справочная таблица + внешний ключ. ENUM компактен и прост, но добавление значения требует изменения схемы; справочная таблица гибка и может нести дополнительные атрибуты (описание, флаг активности, порядок).

Открыть в DBAtlas →