В чем разница между типами данных VARCHAR и TEXT в SQL?

Ответ

VARCHAR и TEXT — это типы данных для хранения символьных строк, но с фундаментальными различиями в использовании и внутреннем устройстве (на примере MySQL/MariaDB).

Основные различия:

Критерий VARCHAR(n) TEXT
Максимальная длина Ограничена значением n (до 65,535 байт, зависит от кодировки и версии СУБД). Большие объемы. TEXT ~64KB, MEDIUMTEXT ~16MB, LONGTEXT ~4GB.
Определение длины Обязательно указывается при создании: VARCHAR(255). Указывается только тип: TEXT.
Хранение In-row storage: Значение хранится в той же строке таблицы, если помещается в лимит страницы. Более быстрое чтение. Off-row storage: В строке таблицы хранится лишь указатель (pointer), а сами данные — отдельно. Чтение может требовать дополнительного обращения.
Индексация Можно создать индекс по всему полю. В MySQL нельзя проиндексировать поле TEXT целиком, можно только указать длину префикса (Prefix Index): CREATE INDEX idx ON table (text_column(100)).
Выделение памяти Выделяется память под максимально возможную длину (n), что может быть неэффективно для длинных значений. Выделяется память под фактическую длину строки + накладные расходы на указатель.
Использование в ключах Может быть частью PRIMARY KEY или UNIQUE ключа. Не может быть частью ключа (кроме полнотекстовых индексов).

Практический пример и рекомендации:

CREATE TABLE articles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(200) NOT NULL,        -- Заголовок, всегда ограниченной длины
    slug VARCHAR(200) UNIQUE NOT NULL,  -- URL-адрес, нужен UNIQUE индекс
    excerpt VARCHAR(500),               -- Короткое описание
    content TEXT NOT NULL,              -- Основной текст статьи, может быть очень длинным
    meta_description TEXT               -- Для SEO, тоже может быть длинным
);

Когда что использовать:

  • Используйте VARCHAR: Для полей с предсказуемой и относительно небольшой длиной: имена (VARCHAR(100)), email (VARCHAR(255)), коды, хэши, заголовки. Когда необходимо наложить ограничение по длине или создать индекс по всему полю.
  • Используйте TEXT: Для неограниченного или потенциально очень большого текста: тело статьи, комментарии пользователей, лог-сообщения, JSON/XML-данные. Когда индексация по префиксу достаточна или не требуется.

Важно: Конкретные лимиты и поведение (особенно по хранению) могут отличаться в PostgreSQL, SQL Server и других СУБД.

Ответ 18+ 🔞

А, ну это классика вечная, про VARCHAR и TEXT. Сидишь такой, проектируешь базу, и тут бац — выбор. А выбор-то, блядь, неочевидный, если не копнуть.

Короче, смотри. Оба типа — для текста, но разница между ними, ёпта, как между точным ударом скальпеля и работой кувалдой. Один — хирург, другой — сантехник.

В чём, собственно, соль:

Признак VARCHAR(n) TEXT
Сколько влезет Есть жёсткий потолок n (ну, там до 65 тысяч байт, но это уже детали). А тут просто дохуя. TEXT — это как «ну, много», а LONGTEXT — это уже «да пиши хоть всю «Войну и мир», хватит».
Как объявлять Обязательно ткни пальцем и скажи длину: VARCHAR(255). Без этого нихуя не получится. Просто сказал TEXT и всё, свободен. Никаких цифр.
Где лежит В основном теле строки. Если влезает — то всё быстро, под рукой. Как ключи от квартиры в кармане. Отдельно, на съёмной хате. В самой строке только записка «ищи там». Чтение — лишний поход, может тормозить.
Можно ли проиндексировать Да запросто, хоть весь столбец в индекс пихай. А вот нихуя. Только кусочек начала (префикс) можно проиндексировать. Типа (text_field(100)). На всё поле — низзззя.
Память жрёт Выделяет под самый худший случай — под максимальную длину n. Может быть расточительно, если у тебя VARCHAR(500), а пишешь ты туда три буквы. Выделяет по факту: сколько написал, столько и съел, плюс маленькая плата за указатель на ту самую съёмную хату.
Можно в ключи? Может быть PRIMARY KEY или UNIQUE. Без проблем. Ни в какие ключи, кроме специальных полнотекстовых, его не воткнёшь. Забудь.

Ну и пример из жизни, чтобы вообще всё встало на свои места:

CREATE TABLE articles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(200) NOT NULL,        -- Заголовок, ясно дело, короткий. 200 символов — овердохуища.
    slug VARCHAR(200) UNIQUE NOT NULL,  -- Человекопонятный URL. Должен быть уникальным, поэтому VARCHAR.
    excerpt VARCHAR(500),               -- Краткое описание, аннотация. Тоже ограниченная хуйня.
    content TEXT NOT NULL,              -- А вот тут уже тело статьи. Может быть на 10 тысяч слов. Это TEXT.
    meta_description TEXT               -- SEO-описание. Тоже хрен знает какой длины.
);

Итоговая мысль, чтобы не ебать себе мозг:

  • Юзай VARCHAR: Когда заранее знаешь разумные пределы. Имя, почта, телефон, хэш пароля, код города. Когда нужны ограничения или полные индексы. Это твой точный инструмент.
  • Херачь TEXT: Когда понятия не имеешь, сколько пользователь намолотит. Комментарий, пост в блог, описание товара, JSON-потроха. Когда индексация по первым 100 символам — норм, или она вообще не нужна. Это твой тяжёлый арсенал на непредсказуемый случай.

И да, чувак, это всё про MySQL. В других базах (PostgreSQL, например) детали могут отличаться, там свои тараканы. Так что всегда гляди в мануал, а не верь слепо первому ответу из интернета, а то будет тебе хиросима.