TGViewer
Spring АйО Spring АйО @spring_aio · 10.9K subscribers
Post #257 4.33K
🧩 Исключение строк из уникальных индексов

Представьте, что вам нужно поддерживать уникальность данных, например, адресов электронной почты в таблице базы данных. Но что делать, если в таблице есть строки, помеченные как удаленные, например, с помощью дополнительного поля deleted_at? При этом важно учитывать, что удаленные данные тоже находятся в таблице, поэтому в поле с почтой будут дубли, сделать уникальный индекс не получится. Здесь на помощь приходят partial индексы.

Partial индекс позволяет задать условие (например, WHERE deleted_at IS NULL), чтобы включать только нужные строки и игнорировать удаленные. Эта функция доступна в PostgreSQL, где можно исключать строки с soft delete, сохраняя требуемую уникальность и оптимизируя размер индекса.

⚠️ Советуем сделать бэкап своей БД перед выполнением запросов во избежании потери данных

Реализация
В PostgreSQL добавление уникального индекса для активных пользователей выглядит так:

CREATE UNIQUE INDEX users_email_uniq ON users (
email
) WHERE deleted_at IS NULL;

В этом случае строки, у которых deleted_at не задан, включаются в индекс, а остальные игнорируются, что делает индекс более компактным и эффективным.

Для MySQL требуется обходной путь, так как partial индексы в нем не поддерживаются. С использованием конструкции IF(deleted_at, NULL, 1) можно эмулировать аналогичное поведение. Пример индекса:


CREATE UNIQUE INDEX users_email_uniq ON users (
email,
(IF(deleted_at, NULL, 1))
);


Здесь NULL используется чтобы исключить удаленные строки из индекса: строки, помеченные как удаленные, получают значение NULL и не конфликтуют с другими значениями.

Как это работает?
Есть некое свойство базы данных, что значения NULL не рекомендуется сравнивать ни с чем, используя ANSI SQL стандартные операторы (=, !=, <> и т.д.), т.к. сравнение приведёт к unknown. Получится так, что два значения (example@example.com, null) в индексе могут спокойно существовать, в то время как два значения (example@example.com, 1) будут конфликтовать. Это свойство позволяет обойти ограничение MySQL и реализовать функциональность partial индекса. Например, строка с адресом foo@example.com, если пользователь помечен как удаленный, получит значение индекса (foo@example.com, NULL) и не создаст конфликта, даже если аналогичная строка существует. Такая стратегия помогает соблюсти уникальность данных, сохраняя логическую целостность таблицы и избегая лишних конфликтов в MySQL.

Преимущества частичных индексов
Кроме того, partial индексы сокращают объем данных, включаемых в индекс, тем самым экономя место и ускоряя операции поиска. PostgreSQL предлагает удобный и простой способ реализации частичных индексов, в то время как MySQL требует определенных обходных решений.
  • 👍 35
  • 🔥 13
  • ❤ 6
  • 🤩 1
More from @spring_aio
  1. Oct 11, 2026🎬 Записи докладов с JPoint 2026 уже в открытом доступе JUG Ru Group выложили записи с про…
  2. Oct 9, 2026👩‍💻 Kotlin получил почти настоящие статики Начиная с Kotlin 2.5.0-Beta1 можно эксперимен…
  3. Oct 8, 2026🍃 Spring Boot ломает совместимость, G1 тормозит микросервисы, Java долго релизит фичи | S…
  4. Oct 6, 2026👩‍💻 Spring Config Import без магии У наших друзей из Axelix вышла статья о том, как Spri…
  5. Oct 5, 2026🥲 В Java 27 TLS научился переживать квантовую атаку При установке HTTPS-соединения клиент…
  6. Oct 3, 2026⚡️⚡️Строки кода стремятся подешеветь до цены токена. Что остается ценным? Про это — трек «…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →