PostgreSQL после многих лет с MySQL: что меня удивило
Последние годы я в основном работал с MySQL. PostgreSQL периодически встречался, но особой необходимости глубоко в него погружаться не было.
Ситуация изменилась, когда появился новый проект — AI-ассистент. Для него мне понадобились PostgreSQL, JSONB, Full-Text Search и, самое главное, pgvector для векторного поиска.
И вот после нескольких недель более плотного знакомства с PostgreSQL я понял, что это не просто «ещё одна SQL-база, почти такая же, как MySQL».
Синтаксис действительно во многом похож, но философия и набор возможностей заметно отличаются.
Сразу оговорюсь: я не считаю, что PostgreSQL во всём лучше MySQL. Но для сложных приложений, где база должна делать больше, чем просто хранить данные и выполнять CRUD, PostgreSQL мне кажется значительно интереснее.
1. Гораздо больше встроенных возможностей
Одно из первых впечатлений — PostgreSQL очень богат на различные типы данных и возможности работы с ними.
Кроме привычных:
INTEGER
VARCHAR
TEXT
DATE
TIMESTAMP
есть, например:
массивы;
JSONB;
диапазоны;
UUID;
геометрические типы;
полнотекстовый поиск;
пользовательские типы;
расширения.
Например, массив можно хранить непосредственно в колонке:
CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, name TEXT, roles TEXT[] ); INSERT INTO users (name, roles) VALUES ('John', ARRAY['admin', 'manager']);
Конечно, массивы не заменяют нормальную реляционную модель. Но для некоторых задач это очень удобный инструмент.
2. JSONB — одна из самых приятных возможностей
С JSON я раньше тоже работал в MySQL, но JSONB в PostgreSQL мне показался гораздо более интересным инструментом.
Например, у товара могут быть динамические характеристики:
CREATE TABLE products ( id BIGSERIAL PRIMARY KEY, name TEXT, attributes JSONB );
Записываем:
INSERT INTO products (name, attributes) VALUES ( 'MacBook Pro', '{ "brand": "Apple", "ram": 32, "storage": "1TB", "cpu": "M4" }' );
Теперь можно обращаться непосредственно к данным внутри JSON:
SELECT attributes->>'cpu' FROM products;
Получим:
M4
Можно искать товары по содержимому JSON:
SELECT * FROM products WHERE attributes @> '{"brand": "Apple"}';
А для больших объёмов данных можно создать GIN-индекс:
CREATE INDEX idx_products_attributes ON products USING GIN (attributes);
Для моего AI-проекта это особенно актуально, потому что характеристики товаров могут отличаться от магазина к магазину.
3. Full-Text Search
Ещё одна вещь, которая сильно заинтересовала меня в PostgreSQL, — встроенный полнотекстовый поиск.
Можно превратить текст в tsvector:
SELECT to_tsvector( 'simple', 'Apple MacBook Pro с процессором M4' );
А пользовательский запрос — в tsquery:
SELECT to_tsquery( 'simple', 'MacBook & M4' );
После этого можно использовать оператор @@:
SELECT * FROM products WHERE search_vector @@ to_tsquery('simple', 'MacBook & M4');
И создать GIN-индекс:
CREATE INDEX idx_products_search ON products USING GIN (search_vector);
Это уже полноценный поисковый механизм прямо внутри PostgreSQL.
Для AI-проекта это особенно интересно, потому что можно объединить обычный текстовый поиск с векторным поиском.
4. А потом я обнаружил pgvector
Вот здесь PostgreSQL окончательно перестал выглядеть для меня как просто SQL-база.
С помощью расширения pgvector можно хранить embeddings:
CREATE EXTENSION vector;
Например:
CREATE TABLE documents ( id BIGSERIAL PRIMARY KEY, content TEXT, embedding vector(1536) );
После этого можно искать не только по словам, но и по смысловой близости текстов:
SELECT id, content FROM documents ORDER BY embedding <=> :query_embedding LIMIT 10;
<=> — cosine distance.
То есть PostgreSQL начинает использоваться не только как обычная реляционная БД, но и как хранилище для vector search.
Для моего AI-ассистента это одна из основных причин, почему я вообще начал активно изучать PostgreSQL.
5. Индексы гораздо интереснее, чем я привык
В MySQL основной рабочий инструмент — B-Tree. Конечно, существуют и другие варианты, но в обычной разработке именно B-Tree встречается постоянно.
В PostgreSQL набор возможностей гораздо шире.
Например, можно создать частичный индекс:
CREATE INDEX idx_active_products ON products (tenant_id) WHERE status = 'active';
Индекс будет содержать только активные товары.
Или индекс по выражению:
CREATE INDEX idx_products_lower_name ON products (LOWER(name));
После этого запрос:
SELECT * FROM products WHERE LOWER(name) = 'iphone';
может использовать этот индекс.
Есть также:
B-Tree;
GIN;
GiST;
BRIN;
Hash;
HNSW;
IVFFlat.
Последние два особенно интересны для pgvector.
Получается, что в PostgreSQL индекс — это не просто «индекс на колонку», а инструмент, который можно подобрать под конкретный тип данных и конкретную задачу.
6. Очень удобный RETURNING
Ещё одна небольшая, но очень приятная возможность — RETURNING.
Например:
INSERT INTO products (name, price) VALUES ('MacBook Pro', 1999) RETURNING id;
База сразу вернёт созданный id.
То же самое можно делать после UPDATE или DELETE:
UPDATE products SET price = 1899 WHERE id = 10 RETURNING id, price;
Это позволяет получать изменённые данные непосредственно из SQL-запроса, не выполняя дополнительный SELECT.
7. CTE и оконные функции
PostgreSQL очень хорошо подходит для сложных SQL-запросов.
Например, CTE:
WITH expensive_products AS ( SELECT * FROM products WHERE price > 1000 ) SELECT * FROM expensive_products;
Или оконные функции:
SELECT
name,
price,
ROW_NUMBER() OVER (
ORDER BY price DESC
) AS position
FROM products;
Конечно, CTE и оконные функции есть и в современных версиях MySQL.
Но при работе с PostgreSQL у меня сложилось впечатление, что база вообще рассчитана на то, что разработчик будет использовать SQL как мощный инструмент обработки данных, а не только как язык для простых CRUD-запросов.
8. PostgreSQL сильнее ощущается как «платформа»
Наверное, именно это главное отличие, которое я пока почувствовал после перехода с MySQL.
PostgreSQL позволяет расширять саму базу.
Например:
CREATE EXTENSION vector;
И база получает новый тип данных и возможности для работы с ним.
Есть расширения для различных задач: геоданных, полнотекстового поиска, векторов и т.д.
Получается довольно интересная модель:
PostgreSQL
│
├── обычные SQL-данные
├── JSONB
├── Full-Text Search
├── геоданные
├── vector search
└── другие расширения
И всё это находится внутри одной СУБД.
А где здесь MySQL?
При этом я бы не делал вывод:
«PostgreSQL хороший, а MySQL плохой».
Это было бы неправильно.
MySQL — отличная СУБД, особенно для классических веб-приложений. Если приложение представляет собой в основном:
PHP/Laravel
↓
CRUD
↓
MySQL
то MySQL прекрасно справляется со своей задачей.
И после 13 лет работы с OpenCart я прекрасно понимаю, почему MySQL настолько популярен в веб-разработке.
Но когда появляются более сложные задачи — полнотекстовый поиск, сложные SQL-операции, JSONB, специализированные индексы, vector search — PostgreSQL начинает выглядеть очень привлекательно.
Итог
После многих лет с MySQL мой первый вывод такой:
PostgreSQL не столько «лучше MySQL», сколько заметно шире по своим возможностям.
MySQL я долго воспринимал прежде всего как надёжную реляционную БД для веб-приложений.
PostgreSQL у меня постепенно начинает восприниматься как целая платформа для работы с данными, где SQL, JSON, полнотекстовый поиск, специализированные индексы и vector search могут жить рядом.
Я пока только в начале изучения PostgreSQL и уверен, что впереди ещё много интересного.
А самое забавное — чтобы начать использовать PostgreSQL в этом проекте, мне пришлось сначала привыкнуть к тому, что здесь очень многое можно сделать непосредственно на уровне базы, не пытаясь реализовать всё в PHP.
