Add new comment

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.

CAPTCHA
Spam protection
Target Image