Домен базы данных¶
Домен базы данных — это семантическое ограничение, задающее множество допустимых значений для одного или нескольких атрибутов (столбцов) реляционной таблицы. Домен определяет не только тип данных (числовой, строковый, дата), но и конкретные правила проверки (constraints), которые гарантируют целостность и достоверность хранимой информации. В отличие от простого типа данных, домен включает в себя бизнес-логику: например, «возраст сотрудника» может быть целым числом от 18 до 100, а «код валюты» — трёхсимвольной строкой из списка (RUB, USD, EUR).
¶Определение и основные понятия
В реляционной модели данных, предложенной Эдгаром Коддом в 1970 году, домен является фундаментальным понятием наряду с отношением (таблицей) и кортежем (строкой). Формально домен — это именованное множество значений, из которого извлекаются фактические значения атрибута. Каждый атрибут таблицы обязательно привязан к некоторому домену, и все значения этого атрибута должны принадлежать данному домену.
Домен отличается от типа данных тем, что:
- Тип данных (например, INTEGER, VARCHAR) определяет только формат хранения и допустимые операции.
- Домен дополнительно задаёт семантику: диапазон, список разрешённых значений, формат, а также может включать проверки на NULL/ NOT NULL.
Например, тип данных INTEGER может использоваться для хранения возраста, количества товаров или индекса массива. Домен ВозрастСотрудника (INTEGER, CHECK (VALUE BETWEEN 18 AND 100)) уже явно указывает, что это возраст человека, и запрещает ввод некорректных значений.
¶История и развитие
Понятие домена было введено Эдгаром Коддом в его оригинальной статье «A Relational Model of Data for Large Shared Data Banks» (1970). Кодд рассматривал домен как «набор значений, из которых черпаются значения атрибутов». В первых реляционных СУБД (System R, Ingres) домены реализовывались через типы данных и простые проверки.
В 1986 году стандарт SQL-86 формально определил домен как объект схемы базы данных, но поддержка доменов в коммерческих СУБД долгое время оставалась ограниченной. В SQL-92 (1992) была введена команда CREATE DOMAIN, позволяющая создавать пользовательские домены с проверками и значениями по умолчанию. Однако многие СУБД (например, MySQL, SQLite) долгое время не поддерживали домены на уровне SQL, предоставляя лишь типы данных и ограничения CHECK.
В современных СУБД (PostgreSQL, Oracle, IBM Db2) домены реализованы в полном объёме. В PostgreSQL, начиная с версии 7.3 (2002), команда CREATE DOMAIN позволяет создавать домены с любыми проверками и значениями по умолчанию. В Microsoft SQL Server домены эмулируются через пользовательские типы данных (User-Defined Data Types) с правилами (rules), хотя полноценной поддержки доменов по стандарту нет.
¶Классификация доменов
¶По способу определения
- Стандартные (встроенные) домены — задаются типами данных, предоставляемыми СУБД (INTEGER, VARCHAR, DATE). Они не имеют дополнительных семантических ограничений.
- Пользовательские домены — создаются разработчиком базы данных с помощью команды
CREATE DOMAIN. Включают базовый тип, значение по умолчанию, ограничения CHECK и признак NULL/NOT NULL.
¶По характеру ограничений
- Домены с диапазоном — ограничивают значения числовым или временным интервалом (например,
CHECK (VALUE BETWEEN 1 AND 100)). - Домены с перечислением — задают конечный список допустимых значений (например,
CHECK (VALUE IN ('M', 'F'))). - Домены с шаблоном — проверяют соответствие строки регулярному выражению (например,
CHECK (VALUE ~ '^\d{3}-\d{2}-\d{4}$')для номера социального страхования). - Домены с составными условиями — комбинируют несколько проверок (например,
CHECK (VALUE > 0 AND VALUE < 1000 AND VALUE % 2 = 0)).
¶По области применения
- Атрибутные домены — привязаны к одному конкретному атрибуту (столбцу) таблицы.
- Многоатрибутные домены — теоретически могут охватывать несколько атрибутов, но на практике редко реализуются в СУБД. Вместо этого используются ограничения CHECK на уровне таблицы.
¶Устройство и реализация
¶Синтаксис SQL (стандарт ISO/IEC 9075)
Создание домена в стандартном SQL выглядит следующим образом:
``sql CREATE DOMAIN age_domain AS INTEGER DEFAULT 18 CHECK (VALUE >= 18 AND VALUE <= 100) NOT NULL; ``
После создания домен можно использовать как тип данных при определении столбца:
``sql CREATE TABLE employees ( id INTEGER PRIMARY KEY, name VARCHAR(100), age age_domain ); ``
¶Особенности в различных СУБД
- PostgreSQL — поддерживает
CREATE DOMAINс полным набором возможностей, включая проверки, значения по умолчанию и ограничения NULL. Домены могут быть изменены командойALTER DOMAIN. - Oracle — поддерживает
CREATE DOMAINначиная с версии 23c. В более ранних версиях используются подтипы (SUBTYPE) в PL/SQL или ограничения CHECK. - IBM Db2 — поддерживает
CREATE DOMAINс ограничениями CHECK и значениями по умолчанию. - Microsoft SQL Server — не имеет команды
CREATE DOMAIN. Вместо этого используются пользовательские типы данных (CREATE TYPE) и правила (CREATE RULE), но правила считаются устаревшей функцией. - MySQL — не поддерживает домены. Ограничения CHECK игнорируются до версии 8.0.16 (2019), после чего CHECK начал работать, но только на уровне таблицы.
- SQLite — не поддерживает домены. Типизация в SQLite является динамической (манифестной), и ограничения CHECK могут быть заданы только на уровне таблицы.
¶Внутреннее устройство
При создании домена СУБД сохраняет его определение в системном каталоге (например, в таблице pg_domain в PostgreSQL). При использовании домена в определении столбца СУБД автоматически применяет все проверки домена к каждому вставляемому или обновляемому значению. Если проверка не проходит, возникает ошибка нарушения ограничения (constraint violation).
Домены могут быть вложенными: один домен может быть определён на основе другого. Например:
```sql CREATE DOMAIN positive_integer AS INTEGER CHECK (VALUE > 0);
CREATE DOMAIN age_domain AS positive_integer CHECK (VALUE <= 120); ```
¶Применение и значение
¶Обеспечение целостности данных
Домены являются одним из механизмов поддержания целостности базы данных наряду с первичными и внешними ключами, уникальными ограничениями и триггерами. Они гарантируют, что в столбце не могут появиться значения, не имеющие смысла с точки зрения предметной области.
¶Упрощение разработки
Создание домена для часто используемого понятия (например, «телефонный номер», «почтовый индекс», «статус заказа») позволяет:
- Избежать дублирования кода проверок в разных таблицах.
- Централизованно изменить ограничение (например, увеличить максимальную длину номера телефона) — достаточно изменить определение домена, и все столбцы, использующие его, автоматически подхватят новое правило.
- Улучшить читаемость схемы базы данных: вместо абстрактного
VARCHAR(20)видно осмысленное имяphone_number.
¶Повышение производительности
В некоторых СУБД (например, PostgreSQL) домены могут использоваться оптимизатором запросов для выбора более эффективного плана выполнения. Если домен задаёт строгий диапазон, оптимизатор может использовать эту информацию для оценки селективности условий.
¶Примеры использования
- Банковская система: домен
account_number(VARCHAR(20), CHECK (VALUE ~ '^\d{20}$')) для номеров счетов. - Медицинская информационная система: домен
blood_type(VARCHAR(3), CHECK (VALUE IN ('A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', '0+', '0-'))). - Интернет-магазин: домен
price(NUMERIC(10,2), CHECK (VALUE >= 0.01 AND VALUE <= 999999.99)). - Система учёта кадров: домен
snils(VARCHAR(14), CHECK (VALUE ~ '^\d{3}-\d{3}-\d{3} \d{2}$')) для СНИЛС.
¶Критика и ограничения
- Неполная поддержка в популярных СУБД. MySQL и SQLite не поддерживают домены, что вынуждает разработчиков реализовывать проверки на уровне приложения или триггеров.
- Сложность миграции. При переносе базы данных между СУБД с разной поддержкой доменов может потребоваться переработка схемы.
- Ограниченная семантика. Домены не могут выражать сложные бизнес-правила, зависящие от нескольких столбцов или внешних данных. Для этого требуются CHECK на уровне таблицы или триггеры.
- Производительность. В некоторых СУБД проверки доменов могут замедлять операции вставки и обновления, особенно при большом количестве столбцов с доменами.
- Отсутствие наследования. Стандарт SQL не поддерживает наследование доменов (хотя в PostgreSQL можно создавать домены на основе других доменов, это не является полноценным наследованием).
¶Интересные факты
- В реляционной теории Кодда домены считаются независимыми от таблиц: один и тот же домен может использоваться в разных отношениях. Например, домен «Идентификатор сотрудника» может быть атрибутом как в таблице «Сотрудники», так и в таблице «Зарплатные ведомости».
- В некоторых СУБД (например, PostgreSQL) домены могут быть изменены без пересоздания таблиц, что упрощает администрирование.
- Существует концепция «доменного нормального вида» (Domain-Key Normal Form, DK/NF), предложенная Рональдом Фагином в 1981 году. Таблица находится в DK/NF, если все ограничения являются логическими следствиями ограничений доменов и ключей. DK/NF считается идеальной формой нормализации, но на практике достигается редко.
- В стандарте SQL:2023 (последняя версия на момент написания статьи) поддержка доменов остаётся без существенных изменений по сравнению с SQL:2016.
¶Источники
- Codd, E. F. (1970). "A Relational Model of Data for Large Shared Data Banks". Communications of the ACM, 13(6), 377–387.
- Date, C. J. (2003). "An Introduction to Database Systems" (8th ed.). Addison-Wesley.
- ISO/IEC 9075-1:2023 "Information technology — Database languages — SQL — Part 1: Framework (SQL/Framework)".
- PostgreSQL Documentation: Chapter 8. Data Types — Domain Types. (https://www.postgresql.org/docs/current/domains.html)
- Fagin, R. (1981). "A Normal Form for Relational Databases That Is Based on Domains and Keys". ACM Transactions on Database Systems, 6(3), 387–415.
- Microsoft SQL Server Documentation: User-Defined Types. (https://learn.microsoft.com/en-us/sql/relational-databases/user-defined-types/)
- Oracle Database 23c Documentation: CREATE DOMAIN Statement. (https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/CREATE-DOMAIN.html)
