Оператор
&& проверяет пересечение диапазонов — как числовых, так и диапазонов дат/времени. Чтобы запретить пересекающиеся интервалы, используется EXCLUDE constraint: например, можно запретить пересечения периодов с одинаковым user_id. В результате один пользователь (или комната, смена, машина — в зависимости от конфигурации) не сможет быть забронирован дважды на одно и то же время.Для производительности используйте
GiST-индекс. А поскольку здесь комбинируется оператор равенства с range-сравнением, понадобится расширение btree_gist.Почему именно
GiST?B-tree работает только с <, =, > и их комбинациями. Понятия пересечения диапазонов у него нет. GiST (Generalized Search Tree) изначально проектировался для диапазонов, геометрии, full-text поиска и других более сложных типов данных.Расширение
btree_gist позволяет смешивать операторы равенства и range-операторы в одном constraint’е.На что стоит обратить внимание:
•
GiST тяжелее по записи, чем B-tree. Для средних и крупных таблиц с умеренной нагрузкой это обычно простое и практичное решение. Но при большом количестве UPDATE/INSERT нужно учитывать дополнительные расходы на обслуживание индекса.• Создание такого constraint’а потребует блокировки таблицы на время построения.
• Если используются partitioned tables, заранее проверьте, как constraint взаимодействует с вашей схемой партиционирования.
Однажды я сам того не ожидая построил календарь…
Календари сложнее, чем кажутся. Это одновременно задача хранения дат, работы с часовыми поясами, отображения данных и взаимодействия с человеческими привычками.
Один из наших клиентов регулярно перемещался между часовыми поясами — между домом и рабочими поездками — и хотел, чтобы календарь вел себя строго определённым образом. Проблема была в том, что система всегда отображала время согласно настройкам организации. Это лишь один пример того, как календари быстро превращают seemingly simple trade-offs в реальные архитектурные проблемы.
Если проверка конфликтов находится только в application logic, вы фактически полагаетесь на один или несколько codebase’ов, которые должны синхронно предотвращать double-booking.
Когда это правило переносится в базу данных, оно становится жёстким и обязательным.
И здесь важно решить: действительно ли вам нужна такая строгость?
Большинство персональных календарных приложений допускают пересечения и оставляют пользователю право самому управлять конфликтами.
Но представьте сервисный выезд: техник физически не может находиться в двух местах одновременно.
В таких сценариях данные должны быть строгими. ПО обязано предотвращать двойное бронирование ресурсов, которые невозможно использовать параллельно.
Когда реализуете защиту от double-booking, внимательно продумывайте уровни ограничений и архитектурные trade-offs, чтобы понять, должна ли именно база данных быть источником этого правила.
Календари и так достаточно хаотичны.
Там, где это возможно — пусть хаос ограничивает PostgreSQL.
👉 @SQLPortal
