воскресенье, 29 мая 2016 г.

MUMPS: Индексация уникального атрибута

Одной из интереснейших и спорных тем в индексации является тема индексации уникального атрибута. Индексы в данном случае используются по меньшей мере в двух различных задачах:
  • Для поиска нужной записи по заданному значению атрибута.
  • Для поддержания условия уникальности значения атрибута среди всех имеющихся записей.
Сам факт использования уникальных значений атрибутов вызывает споры, подобные религиозным - использовать ли их в качестве естественных ключей или нет, и на каком уровне реализации системы должна происходить поддержка уникальности - на уровне сервера приложения (прикладная логика) или на уровне сервера базы данных (нижний уровень хранения). Чтобы не вызывать не относящихся к теме вопроса противоречий, выберем условный пример, с которым могут согласиться сторонники различных подходов. Положим, что у нас есть учетная система, в которой сохраняются сведения о пользователях и нам предстоит сохранить в ней атрибуты "номер паспорта" и "логин".

Оба атрибута всегда должны быть уникальны среди всех записей, никак не связаны друг с другом, и номер паспорта может со временем меняться. Кажется очевидным, что при удалении записи пользователя из системы его логин впоследствии также не может быть использован повторно, и что у одного пользователя могут быть два или более паспортов, с единственным ограничением, что только один из них является применимым для совершения новой сделки. Назовем его текущим активным. Кроме того, пользователь системы может перестать в ней существовать в том смысле, что с одной стороны он может быть как-бы удален, с другой стороны имеющиеся на него ссылки должны остаться действующими для расшифровки имевшихся на какой-то предыдущий момент времени в системе взаимосвязей.

Чтобы не возникло желания использовать логин в качестве естественного ключа (догматический подход на практике обычно не работает). Мы наложим еще одно условие - логин также может со временем меняться, также как номер паспорта, логин не может быть впоследствии повторен и всегда должен быть уникален среди всех логинов, известных системе. Приведенный пример выглядит вполне разумным для того, чтобы согласиться с мыслью о правомерности существования уникальных атрибутов.

Чтобы жизнь медом не казалась, придумаем еще один уникальный атрибут - номер служебного мобильного телефона, выдаваемого фирмой своему сотруднику. Номер может со временем быть передан другому сотруднику, он может отсутствовать, и одновременно не может принадлежать двум сотрудникам. В качестве значения такого атрибута нам без разницы что использовать - сам номер или идентификатор записи об отдельном объекте учета. В любом случае среди всех записей о пользователях заданный номер телефона может или не быть ни у кого, или быть только у одного сотрудника.

В примере номер телефона, наверное, наиболее типичный пример уникального атрибута. Часть схемы данных о пользователе будет такой:
Запись о сотруднике:  ^D(iduser)=$lb(phone)
Индексная запись:     ^I(phone,iduser)=""
На каком уровне будет проводиться проверка уникальности атрибута, на уровне логики или на уровне хранения, видимо, не принципиально, поскольку действия в принципе должны быть выполнены одни и те же.

Рассмотрим, какие операции могут привести к модификации записи и какие из них к нарушению уникальности атрибута:

Вставка новой записи

При вставке может возникнуть конфликт уникальности, если такое значение уже было. Если не было, то вставка безопасна.

Удаление имеющейся записи

Если запись была, то ее удаление гарантированно оставляет условие "либо один либо ноль" истинным, поэтому удаление записи всегда безопасно с точки зрения уникальности атрибута.

Изменение атрибута

При изменении атрибута может произойти конфликт, если новое значение уже существует. Если такого не было, то изменение безопасно.

Откат транзакции

При откате транзакции сервер базы данных восстанавливает предыдущее значение. В случае, если оно было (операции удаления и изменения), то сервер базы данных самостоятельно выставит значения данным, не согласуясь с поддерживаемым нами ограничением уникальности. Для того, чтобы обезопасить систему от нарушения уникальности при откате транзакции с изменением значения, необходимо применять блокировки.

В целом, уникальность значения атрибута есть лишь один из очень простых видов ограничений целостности базы данных - они могут быть объявлены гораздо более комплексно и затрагивать большое количество сущностей в весьма сложной взаимосвязи.

Для того, чтобы гарантировать, что значение всегда одно, может быть использован индекс вида
^Index(IndexName,Value)=id
В этом случае в индексе физически не может одновременно существовать две записи с разным id.

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

Имя блокировки не обязано соответствовать имени глобала индекса, это может быть в целом любое имя, главное чтобы система именования отображала блокируемое условие. Зачастую строение индексного глобала достаточно близко к имени блокировки, и именно его разработчики и используют в типовых задачах.

Поддержание уникальности значения атрибута есть частный случай наложения условий на взаимные значения различных записей. В частности, при традиционной трактовке уникальность означает существование записи с данным значением атрибута в количестве от 0 до 1. Значение 1 может быть лишь частным случаем, одним из значений для более общего параметра уникальности N. При замене N на, например, 7, получаем условие чтобы указанное значение присутствовало в записях числом от 0 до 7.

При выполнении таких более общих условий уникальности в других, не MUMPS системах, необходимо приводить условие к условию простой уникальности. Например, завести отдельный справочник допустимых значений, и ссылаться на записи из этого справочника, но с ограничением что на каждую запись справочника может сослаться лишь одна запись. Например, если необходимо выполнить условие "не более 7 синих одновременно", то придется завести 7 записей в справочнике с значением "синий" и ссылаться на такие записи, поддерживая особую дисциплину добавления и удаления записей в справочнике административно. Кроме того, понадобится реализовать стратегию монопольного захвата одной из свободных записей справочника, например с применением опций
SELECT ... FOR UPDATE


Подробнее о книге "MUMPS СУБД"

Комментариев нет:

Отправить комментарий