Все, кто работает с базами данных, знают, что такое AUTO_INCREMENT. Про него много всего написано, в том числе и на хабре. В этой статье я хочу изложить свои мысли на эту тему, потому что ранее я не встречал рассуждений именно в таком плане. Но сначала давайте определимся, зачем нам вообще база данных.
Действительно, будем все хранить в оперативной памяти. Хотя, нет, ее маловато будет. Да и при неожиданном выключении все данные пропадут. Поставим ИБП. Нет, лучше 2. А еще лучше представим, что память у нас бесконечная и данные при выключении не теряет.
Теперь можно писать что-то типа такого:
Order order = new Order();
User user = new User();
order.creator = user;
И насоздавать хоть 10 таких заказов, хоть 20, хоть 100… Хм, что-то много я насоздавал, надо бы коллекцию какую-нибудь. А к ней поиск по полям. И язык запросов, чтобы все универсально было. Плюс индексы по этим полям для ускорения поиска.
Что у нас получилось? Получилась практически обычная база данных. За одним исключением – у объектов нет первичного ключа. Все объекты идентифицируются по адресу в адресном пространстве.
Теперь можно вспомнить, что у оперативной памяти есть свои ограничения, программы закрываются, компьютеры выключаются, данные могут быть нужны нескольким программам сразу. Значит, нужно сделать некоторую абстракцию над оперативной памятью, чтобы адреса у всех были всегда одни и те же. Примерно как виртуальная адресация в защищенном режиме процессора. И хранить это в файлах на диске. И сделать систему управления.
Это подводит к мысли, почему целочисленные ключи удобны в использовании. Причины не только в реализации систем управления БД. База данных – это адресное пространство для размещения объектов. А целочисленный ключ (ID) – это ссылка на объект.
Из этого следует, что auto_increment в пределах одной таблицы — это не совсем правильно. Каждая запись в БД должна иметь уникальный адрес. Получается как бы двухмерное адресное пространство – адреса растут в одном направлении, сами объекты в другом; размер одного объекта не влияет на адреса соседних объектов. При этом неважно, распределенная БД или нет, сколько в ней серверов, баз и таблиц. Это одно адресное пространство, и адресация должна быть однозначной.
Получается, теоретически запись можно найти по ключу без указания таблицы; или наоборот, можно найти саму таблицу, в которой находится запись с таким ключом. Можно даже разбить адресное пространство на диапазоны: например, до 1000000 системные таблицы, настройки, справочники; после 1000000 реальные данные. При переполнении можно добавлять к диапазону заранее определенную достаточно большую константу, или заранее настроить карту диапазонов.
Однако, ID не нужно относить к атрибутам самого объекта как элемента модели данных. Например:
int x = 2;
У переменной x есть значение 2 и адрес 0x123456. Но нельзя сказать, что адрес – это атрибут целочисленных значений. Также нельзя сказать, что ID – это атрибут объектов типа User и Order. Он служит просто для связи абстрактной модели и технической реализации.
Все ограничения естественного ключа нужно делать дополнительными техническими средствами, на уровне самой БД или приложения. На самом деле, я даже не могу представить ситуацию, в которой естественный первичный ключ является «естественным». Все варианты типа номер паспорта, телефона, ИНН – это искусственно введенная нумерация объектов, именно потому что нельзя выделить у них или их владельцев уникальный набор признаков. И использовать ее можно только для идентификации именно этих объектов – выданных паспортов, узлов телефонной сети, экономического субъекта, платящего налоги. В реальности всегда есть возможность существования дубликатов с одинаковыми свойствами, и набора разных свойств в разное время у одной сущности.
P.S.: Мои рассуждения носят теоретический характер, я не работал с базами с подобной структурой. Технически это сделать несложно – одна sequence на все таблицы. Если у кого-то есть такой опыт, просьба поделиться информацией в комментариях – плюсы, минусы, подводные камни.
Автор: michael_vostrikov