← Назад к вопросам

В чем разница между char и varchar в SQL?

1.3 Junior🔥 161 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между CHAR и VARCHAR в SQL: ключевые различия

CHAR и VARCHAR — это оба строковые типы данных в SQL, но они существенно различаются по использованию памяти и производительности. Выбор между ними критичен для эффективного дизайна БД.

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

CHAR(n) — Fixed Length (фиксированная длина)

CREATE TABLE users (
    id INT PRIMARY KEY,
    country_code CHAR(2),  -- ВСЕГДА 2 символа
    phone_code CHAR(3)     -- ВСЕГДА 3 символа
);

-- Вставляем данные
INSERT INTO users VALUES (1, 'US', '202');  -- 2 + 3 символа
INSERT INTO users VALUES (2, 'RU', '495');  -- 2 + 3 символа

-- Что происходит в памяти:
-- 'US'  -> 'US  ' (заполняется пробелами до 2 символов)
-- 'RU'  -> 'RU  ' (заполняется пробелами до 2 символов)

VARCHAR(n) — Variable Length (переменная длина)

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(255),      -- ДО 255 символов
    description VARCHAR(1000) -- ДО 1000 символов
);

-- Вставляем данные
INSERT INTO users VALUES (1, 'John', 'Developer');       -- 4 + 9 символов
INSERT INTO users VALUES (2, 'Alice', 'Senior Engineer'); -- 5 + 15 символов

-- Что происходит в памяти:
-- 'John'  -> занимает ровно 4 байта
-- 'Alice' -> занимает ровно 5 байт

Сравнение таблица

КритерийCHAR(n)VARCHAR(n)
РазмерВСЕГДА n байтДо n байт
ПамятьФиксированная (потери на пробелы)Переменная (экономит на пробелах)
PerformanceБыстрее поиск (выравнивание)Медленнее (нужно искать длину)
StorageВсегда занимает n байтЗанимает только нужное
ИспользованиеКоды, номера (фиксированной длины)Текст, имена, описания
СравнениеТочное совпадениеС учётом переменной длины

Практические примеры

Пример 1: Коды (CHAR)

-- ХОРОШО: CHAR для кодов фиксированной длины
CREATE TABLE countries (
    code CHAR(2) PRIMARY KEY,    -- 'US', 'RU', 'DE' всегда 2
    code3 CHAR(3),              -- 'USA', 'RUS', 'DEU' всегда 3
    name VARCHAR(100)           -- Имя переменной длины
);

-- ПЛОХО: VARCHAR для кодов
CREATE TABLE countries (
    code VARCHAR(2) PRIMARY KEY, -- Почему? Всегда 2 символа
    code3 VARCHAR(3),           -- Потеря памяти и производительности
    name VARCHAR(100)
);

Пример 2: Текст (VARCHAR)

-- ХОРОШО: VARCHAR для текста
CREATE TABLE posts (
    id INT PRIMARY KEY,
    title VARCHAR(500),      -- Заголовок переменной длины
    content VARCHAR(10000),  -- Контент переменной длины
    author VARCHAR(100)      -- Имя автора переменной длины
);

-- ПЛОХО: CHAR для текста
CREATE TABLE posts (
    id INT PRIMARY KEY,
    title CHAR(500),         -- Потеря ОГРОМНОГО объёма памяти
    content CHAR(10000),     -- Каждый пост займёт 10KB минимум
    author CHAR(100)         -- Вспомогательные пробелы везде
);

Расчёт памяти

-- Таблица с 1 миллионом пользователей

-- Вариант 1: VARCHAR
CREATE TABLE users_varchar (
    id INT,                      -- 4 байта
    name VARCHAR(100),           -- В среднем 30 байт
    email VARCHAR(255),          -- В среднем 50 байт
    city VARCHAR(100)            -- В среднем 20 байт
);

-- На 1,000,000 пользователей:
-- id: 1,000,000 * 4 = 4 MB
-- name: 1,000,000 * 30 = 30 MB
-- email: 1,000,000 * 50 = 50 MB
-- city: 1,000,000 * 20 = 20 MB
-- ИТОГО: ~104 MB

-- Вариант 2: CHAR (плохо!)
CREATE TABLE users_char (
    id INT,                  -- 4 байта
    name CHAR(100),         -- ВСЕГДА 100 байт
    email CHAR(255),        -- ВСЕГДА 255 байт
    city CHAR(100)          -- ВСЕГДА 100 байт
);

-- На 1,000,000 пользователей:
-- id: 1,000,000 * 4 = 4 MB
-- name: 1,000,000 * 100 = 100 MB
-- email: 1,000,000 * 255 = 255 MB
-- city: 1,000,000 * 100 = 100 MB
-- ИТОГО: ~459 MB

-- Разница: 4.4x больше памяти с CHAR!

Поведение при сравнении

-- CHAR: заполняет пробелами
CREATE TABLE test_char (
    code CHAR(3)
);

INSERT INTO test_char VALUES ('US');
INSERT INTO test_char VALUES ('US '); -- Пробел в конце

-- Оба SELECT вернут 2 строки (одинаково сравниваются)
SELECT COUNT(*) FROM test_char WHERE code = 'US';
-- Result: 2 (оба совпадают, пробел игнорируется)

-- VARCHAR: без пробелов
CREATE TABLE test_varchar (
    code VARCHAR(3)
);

INSERT INTO test_varchar VALUES ('US');
INSERT INTO test_varchar VALUES ('US '); -- Пробел в конце

-- Вернёт только 1 строку
SELECT COUNT(*) FROM test_varchar WHERE code = 'US';
-- Result: 1 (без пробела не совпадает)

Производительность при поиске

-- CHAR быстрее в поиске (fixed offset)
-- БД знает точное место каждой строки
SELECT * FROM char_table WHERE code = 'US';
-- Прямой access (быстро)

-- VARCHAR медленнее (variable offset)
-- БД нужно считать размер
SELECT * FROM varchar_table WHERE code = 'US';
-- Поиск с расчётом размера (медленнее)

Best Practices

-- 1. CHAR для кодов фиксированной длины
CREATE TABLE countries (
    code CHAR(2) PRIMARY KEY,     -- Правильно
    phone_prefix CHAR(3),         -- Правильно
    currency_code CHAR(3)         -- Правильно
);

-- 2. VARCHAR для текста переменной длины
CREATE TABLE articles (
    id INT PRIMARY KEY,
    title VARCHAR(500),           -- Правильно
    content VARCHAR(50000),       -- Правильно
    tags VARCHAR(1000)            -- Правильно
);

-- 3. Не используй CHAR когда unknown длина
CREATE TABLE users (
    name VARCHAR(255),  -- Правильно (переменная)
    email VARCHAR(255), -- Правильно (переменная)
    gender CHAR(1)      -- Правильно (F/M - фиксированная)
);

-- 4. TEXT для больших объёмов
CREATE TABLE documents (
    id INT PRIMARY KEY,
    content TEXT  -- Неограниченный размер
);

Реальный пример из Java

// Entity с правильными типами
@Entity
@Table(name = "users")
public class User {
    @Id
    private Long id;
    
    // CHAR для фиксированных кодов
    @Column(name = "country_code", length = 2)
    private String countryCode; // CHAR(2)
    
    // VARCHAR для текста
    @Column(name = "name", length = 255)
    private String name; // VARCHAR(255)
    
    // VARCHAR для email
    @Column(name = "email", length = 255)
    private String email; // VARCHAR(255)
    
    // TEXT для больших текстов
    @Column(columnDefinition = "TEXT")
    private String bio; // TEXT (неограниченный)
}

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

CHAR(n):

  • Коды (страны, валюты): CHAR(2), CHAR(3)
  • Номера фиксированной длины: CHAR(10) для ИНН
  • Статусы: CHAR(1) для F/M/O
  • ID формата (всегда одна длина)

VARCHAR(n):

  • Имена пользователей
  • Email адреса
  • Адреса
  • Описания
  • Заголовки
  • Любой текст переменной длины

TEXT:

  • Большие документы
  • Контент статей
  • Неограниченный размер

Итог

  • CHAR: фиксированная длина, быстро ищется, потери памяти на пробелы
  • VARCHAR: переменная длина, экономит память, медленнее поиск
  • Правило: используй VARCHAR по умолчанию, CHAR только для кодов фиксированной длины
  • Расчёт: разница в памяти может быть 4-5x для больших таблиц

Правильный выбор типа данных — основа хорошей БД архитектуры.