← Назад к вопросам
Сколько символов хранит поле VARCHAR в PostgreSQL?
1.2 Junior🔥 71 комментариев
#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
VARCHAR в PostgreSQL: лимиты и особенности
VARCHAR(n) в PostgreSQL может хранить ДО n символов, где n — число, указанное в скобках. Но есть важные детали, которые часто забывают разработчики.
Базовая информация
-- Определение типа VARCHAR
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255), -- До 255 символов
name VARCHAR(100), -- До 100 символов
bio TEXT, -- Неограниченный текст
description VARCHAR -- Без лимита (как TEXT)
);
Сравнение типов
┌──────────────┬────────────────────────┬──────────────┐
│ Тип │ Лимит │ Хранение │
├──────────────┼────────────────────────┼──────────────┤
│ VARCHAR(n) │ До n символов │ Переменное │
│ CHAR(n) │ Ровно n символов │ Фиксированное│
│ VARCHAR │ До 1 GB (1073741823) │ Переменное │
│ TEXT │ До 1 GB │ Переменное │
│ SMALLTEXT │ Нет (используй TEXT) │ - │
└──────────────┴────────────────────────┴──────────────┘
Примеры использования в Java
@Entity
@Table(name = "users")
public class User {
@Id
private UUID id;
// VARCHAR(255) — email должен быть разумной длины
@Column(name = "email", length = 255, nullable = false, unique = true)
private String email; // max 255 символов
// VARCHAR(100) — имя
@Column(name = "name", length = 100, nullable = false)
private String name; // max 100 символов
// TEXT — описание может быть длинным
@Column(name = "bio", columnDefinition = "TEXT")
private String bio; // max ~1 GB
// VARCHAR(50) — статус
@Column(name = "status", length = 50)
@Enumerated(EnumType.STRING)
private UserStatus status; // ACTIVE, INACTIVE, DELETED
}
// Validation
@NotBlank
@Email
@Column(length = 255)
private String email; // Валидация на уровне приложения
@NotBlank
@Size(max = 100)
@Column(length = 100)
private String name; // Максимум 100 символов
Что происходит при переполнении?
// VARCHAR(10)
CREATE TABLE test (
id SERIAL,
value VARCHAR(10)
);
// ❌ Это вызовет ошибку
INSERT INTO test (value) VALUES ('12345678901'); -- 11 символов
// ERROR: value too long for type character varying(10)
// ✅ Это работает
INSERT INTO test (value) VALUES ('1234567890'); -- 10 символов
// ✅ Это тоже работает (меньше)
INSERT INTO test (value) VALUES ('12345'); -- 5 символов
В Java:
@Column(length = 10)
private String value;
public void insertData() {
User user = new User();
user.setValue("12345678901"); // 11 символов!
userRepository.save(user); // ← DataIntegrityViolationException!
}
Практические рекомендации по выбору длины
-- Email: RFC 5321 говорит максимум 254 символов
-- На практике: 255 (распространённый лимит)
CREATE TABLE users (
email VARCHAR(255) NOT NULL UNIQUE
);
-- Имена: зависит от языка
-- Англ: 20-50 символов
-- Китайский: может быть 1-2 символа
-- На практике: 100 хватает для 99% случаев
CREATE TABLE users (
first_name VARCHAR(50), -- John
last_name VARCHAR(50), -- Smith
full_name VARCHAR(100) -- John Smith
);
-- URL: могут быть длинными
-- На практике: 2000 символов хватает для большинства
CREATE TABLE posts (
url VARCHAR(2000)
);
-- Телефон: +1 (555) 123-4567
-- На практике: 20 хватает
CREATE TABLE users (
phone VARCHAR(20)
);
-- Статус/Enum: фиксированный список
CREATE TABLE orders (
status VARCHAR(20) -- PENDING, PROCESSING, COMPLETED, FAILED
);
-- Пароль (хэш): SHA-256 = 64 hex символа
CREATE TABLE users (
password_hash VARCHAR(255) -- Запас на bcrypt и др.
);
Сравнение: VARCHAR(n) vs TEXT
-- VARCHAR(255)
CREATE TABLE posts_varchar (
title VARCHAR(255)
);
-- Pros: ясная граница, валидация на БД
-- Cons: может быть слишком коротко
-- TEXT
CREATE TABLE posts_text (
title TEXT
);
-- Pros: неограниченная длина
-- Cons: может быть слишком большой, медленнее индексирование
-- В PostgreSQL оба хранят одинаково эффективно!
-- Разница минимальна
INDEX post_title_varchar ON posts_varchar(title); -- OK
INDEX post_title_text ON posts_text(title); -- OK
Проблемы с очень короткими VARCHAR
// ❌ Слишком коротко
@Column(length = 10)
private String username; // "john_smith" = 10 символов, а если 11?
// ✅ Разумно
@Column(length = 50)
private String username; // Места хватит для большинства
// ❌ Слишком коротко
@Column(length = 5)
private String countryCode; // Только для 4-символьных кодов
// ✅ Правильно
@Column(length = 10)
private String countryCode; // ISO 3166-1 alpha-2 = 2 символа
Проблемы с очень длинными VARCHAR
-- ❌ Неправильно: для простого текста
CREATE TABLE users (
email VARCHAR(1000) -- Зачем 1000 для email?
);
-- ✅ Правильно: для действительно больших данных
CREATE TABLE articles (
content TEXT -- Статья может быть 10000+ символов
);
-- VARCHAR(1000) занимает столько же места, что и TEXT для малых данных
-- Но при индексировании может быть неэффективно
CREATE INDEX idx_email ON users(email); -- OK для VARCHAR(255)
CREATE INDEX idx_content ON articles(content(100)); -- TEXT требует спецификации префикса
Оптимизация в PostgreSQL
-- PostgreSQL хранит VARCHAR(n) эффективно:
-- Если текст меньше page size (8KB), то всё локально
-- Если текст больше, идёт в TOAST (The Oversized-Attribute Storage Technique)
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
title VARCHAR(255), -- На основной page
content VARCHAR(10000) -- Если > 8KB, идёт в TOAST
);
-- Сжатие для TOAST
ALTER TABLE documents ALTER COLUMN content SET STORAGE EXTENDED;
-- EXTENDED: сжимать и вкусно
-- MAIN: сначала сжимать, потом TOAST
-- EXTERNAL: никогда не сжимать
-- PLAIN: никогда не сжимать и не TOAST
Реальные примеры схем
-- E-Commerce
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL, -- Название продукта
sku VARCHAR(50) NOT NULL UNIQUE, -- Stock Keeping Unit
description TEXT, -- Полное описание
manufacturer_code VARCHAR(100), -- Код производителя
category_code VARCHAR(20) -- Категория
);
-- Социальная сеть
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
author_id BIGINT NOT NULL,
title VARCHAR(255), -- Заголовок
content TEXT NOT NULL, -- Основной контент
tags TEXT, -- JSON или CSV
hashtags VARCHAR(1000) -- #programming #java
);
-- Система тикетов
CREATE TABLE tickets (
id UUID PRIMARY KEY,
issue_key VARCHAR(20) UNIQUE, -- PROJ-123
summary VARCHAR(255) NOT NULL, -- Краткое описание
description TEXT, -- Полное описание
status VARCHAR(20) NOT NULL, -- OPEN, IN_PROGRESS, CLOSED
priority VARCHAR(20) NOT NULL, -- LOW, MEDIUM, HIGH, CRITICAL
assignee_email VARCHAR(255), -- user@example.com
labels VARCHAR(500) -- tag1,tag2,tag3
);
Миграция между VARCHAR типами
-- Была VARCHAR(100), нужна VARCHAR(200)
ALTER TABLE users
ALTER COLUMN name TYPE VARCHAR(200);
-- Fast! Нет перезаписи данных
-- Была VARCHAR(1000), нужна VARCHAR(100)
ALTER TABLE users
ALTER COLUMN name TYPE VARCHAR(100);
-- МЕДЛЕННО! Может быть ошибка если есть data > 100
ALTER TABLE users
ALTER COLUMN name TYPE VARCHAR(100) USING name; -- Явно указываем
-- Была VARCHAR(100), нужна TEXT
ALTER TABLE users
ALTER COLUMN name TYPE TEXT;
-- Очень быстро (совместимые типы)
Вывод
- VARCHAR(n) хранит ДО n символов
- PostgreSQL эффективно использует пространство (переменная длина)
- Выбирай разумные лимиты:
- Email: 255
- Имя: 100
- Опис: TEXT
- Статус: 20
- URL: 2000
- VARCHAR vs TEXT: в PostgreSQL почти нет разницы в производительности
- Всегда валидируй на уровне приложения (Java annotations)
- Лучше переполнить VARCHAR, чем потом менять схему