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 КБ — это правило для любого строкового типа. Длинные тексты не индексируют целиком: для поиска по ним есть полнотекстовый поиск.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





