Что такое…

text или varchar — что выбрать в Postgres, и откуда взялось число 255

Иллюстрация: свободный рулон бумаги и коробка с ячейками, где длинная лента застряла

Ты просишь нейросеть создать таблицу пользователей. Она пишет:

name varchar(255),
email varchar(255),
bio varchar(255)

Почему 255? Ты не просил. Это число ходит по коду двадцать лет — из MySQL, из старых туториалов, из чужих миграций. А через месяц пользователь вставляет длинное «О себе» и получает ошибку:

value too long for type character varying(255)

Смотри, что неожиданно: в Postgres у varchar(255) нет никакого выигрыша в скорости перед text. Ни на байт. Разберём, откуда тогда это число и что писать на самом деле.

Коротко: в чём разница

  • text — строка любой длины.
  • varchar(n) — строка не длиннее n символов. Длиннее — ошибка при записи.
  • varchar без числа — то же самое, что text.

И всё. Хранятся они в Postgres одинаково. Документация говорит прямо: разницы в производительности между ними нет, кроме нескольких тактов процессора на проверку длины.

Сравним по пунктам

Скорость и место.

  • text: эталон.
  • varchar(n): то же самое плюс проверка длины при каждой записи. Миф «varchar быстрее» пришёл из других баз.

Защита от мусора.

  • text: принимает хоть мегабайт. Если лимит нужен — его добавляют отдельно (ниже покажу как).
  • varchar(n): лимит встроен в тип. Это его единственный реальный плюс.

Сообщение об ошибке.

  • text с проверкой: ты сам называешь правило — name_too_long. Его легко поймать и показать человеку понятный текст.
  • varchar(n): безликое value too long for type character varying(255). Пользователю такое не покажешь.

Изменение лимита.

  • text с проверкой: удалил старое правило, добавил новое. Две строки в миграции.
  • varchar(n): меняешь тип колонки. Увеличить лимит дёшево. А вот уменьшить — Postgres перепроверит каждую строку таблицы, и на большой таблице это долго.

Что считается длиной.

  • В Postgres varchar(10) — это 10 символов, не байт. «Привет» влезает целиком, хоть русская буква и весит 2 байта.

Откуда взялись 255 и 191

Это история MySQL, не Postgres.

255 — наследие старых версий, где длина VARCHAR хранилась в одном байте. А один байт — это максимум 255. Лимит давно поднят, а привычка осталась.

191 — ещё забавнее. В MySQL с кодировкой utf8mb4 один символ может занимать 4 байта. А старый InnoDB разрешал индекс не длиннее 767 байт. 767 / 4 = 191 с хвостиком. Поэтому Laravel годами советовал defaultStringLength(191), и это число разошлось по туториалам.

В Postgres ни одно из этих ограничений не действует. Писать там varchar(255) — значит переносить чужой шрам на здоровую базу.

А в SQLite ещё смешнее: она длину varchar вообще не проверяет. varchar(10) молча проглотит строку на тысячу символов. Отличия этих баз — в статье «SQLite или Postgres».

Как ограничить длину правильно

Если лимит нужен по смыслу — имя не длиннее 100 символов, твит не длиннее 280 — пиши так:

name text not null
  constraint name_too_long check (char_length(name) <= 100)

Что ты получаешь:

  • лимит есть, как у varchar(100);
  • у ошибки понятное имя name_too_long;
  • поменять лимит — значит заменить одно правило, а не тип колонки;
  • в правило можно добавить что угодно: «не пустое», «без пробелов по краям».

И главное: проверяй длину ещё и в форме. База — последний рубеж, а не первый. Человек должен увидеть «максимум 100 символов» до отправки, а не после.

Кому что подойдёт

Бери text — почти всегда. Имена, email, заголовки, описания, комментарии. Вики Postgres в списке «Чего не делать» прямо пишет: не используй varchar(n) по привычке. Лимиты — через check, когда они реально нужны.

Бери varchar(n) — если лимит жёсткий, не будет меняться и часть самих данных: код страны из 2 букв, номер по стандарту фиксированной длины. Или если проект должен работать и на MySQL, где разница между типами настоящая.

Не бери char(n) — он дополняет строку пробелами до нужной длины. В Postgres это самый медленный из трёх вариантов и источник странных сравнений.

Если ты только поднимаешь базу, правило одно: text по умолчанию, лимит — осознанно и с именем.

Можно ли поменять varchar на text в готовой таблице?

Да, одной командой alter table ... alter column ... type text. Postgres хранит их одинаково, поэтому переписывать данные не нужно — операция быстрая.

Длинный text не тормозит индекс?

Для обычных строк нет. Но в индекс B-tree не влезет значение длиннее примерно 2,7 КБ — это правило для любого строкового типа. Длинные тексты не индексируют целиком: для поиска по ним есть полнотекстовый поиск.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →