(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Уникальные идентификаторы. В чём проблема ?

Смирнов Сергей Юрьевич

MS Access не предоставляет нам возможности выбора способа уникальной идентификации строк таблиц. 

Единственный вариант - счётчик. Правда, надо отдать ему должное - в подавляющем большинстве случаев этого достаточно.

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

Другой неприятной особенностью счётчика является то, что иногда значения всё же дублируются, особенно при отсутствии уникального индекса для такого поля.

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

Другим методом является выделение диапазонов счётчика для каждой из баз. Такой способ очень даже не плох. Если в базе хранятся сведения о людях, то диапазоны по 1 000 000 для таких баз вполне достаточны. Хотя... Недостатком можно считать необходимость заранее планировать количество и размер диапазонов. Именно планирования количества диапазонов, потому, что массив от 0 до 2 147 483 647 ну вряд ли какой-нибудь смертный может заполнить ;). Есть необходимость в 20 распределенных базах ?  Планируем диапазоны по 100 000 000 сто миллионов! на базу и еще один диапазончик оставляем на запас ;). В принципе проблема заполнения этих диапазонов решена надолго ;) и никакого дополнительного кода и потери быстродействия ! 

Если Вы планируете работать с большими объемами, то Вам просто нельзя использовать Access ;), серьезно говорю, даже с миллионом записей этой будет уже затруднительно. Присмотритесь с MS SQL Server.

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

Ниже подробно описаны два таких выражения: одно строкового, а другое числового типа.

Идентификатор типа String

Получение уникального значения в данном случае основано на генерации строки из 16-ти символов. Первым идёт самый левый из аргументов командной строки. Значение командной строки можно задать не только в параметре запуска /cmd, но и из программы:

Application.SetOption "Command-Line Arguments", "W"

За ним следуют шестнадцатеричные значения текущей даты и времени. Оставшиеся 7 символов занимает случайное число (также в шестнадцатеричном формате). В итоге получается следующее:

ID = Left(Command(), 1) & Hex(Now() Mod 2 ^ 16) & Hex((Now() - Int(Now())) * 65535) & Hex(Rnd() * (2 ^ 28-1))

Здесь:

Left(Command(), 1) любой подходящий символ (должен быть первым в аргументе командной строки)

Hex(Now() Mod 2 ^ 16) дата по модулю 65536 (чтобы было не более 4 символов)

Hex((Now() - Int(Now())) * 65535) время масштабированное до 65535 (чтобы было не более 4 символов)

Hex(Rnd() * (2 ^ 28-1)) случайное число в диапазоне от 0 до 2^28-1 (чтобы было не более 7 символов)

При таком способе, количество клиентов в системе ограничено числом допустимых символов для первого (левого) байта в строке. Определённо, таковых найдётся не менее сотни. Если нужно больше, то можно увеличить количество начальных символов. Размер идентификатора при этом, разумеется, тоже возрастёт. Дополнительным плюсом является то, что такой идентификатор можно без всяких переделок использовать в качестве ключа для TreeView.

Идентификатор типа Currency

Этот способ создания уникального идентификатора является развитием предыдущего. Он позволяет вдвое уменьшить размер поля и ускорить все операции с ним, так как работа с числами происходит быстрее, чем со строками. Функция получается, правда, более громоздкая:

ID = IIf(Val(Command()) > 63, 1, -1) * (CCur(Abs(Val(Command()) - 64) * (2 ^ 57) / 10000) + CCur(CCur((Int(Now()) Mod 2 ^ 15) * (2 ^ 42) / 10000) + CCur(((Now() - Int(Now())) * 65535) * (2 ^ 26) / 10000) + CCur(Rnd() * (2 ^ 26 - 1)) / 10000))

Аргумент командной строки (то, что стоит за /cmd) должен быть числом в диапазоне от 1 до 127. Именно столько клиентов может быть в системе, использующей данный способ генерации уникального идентификатора. Присвоить этому аргументу значение, например, 127 можно следующей командой:

Application.SetOption "Command-Line Arguments", "127"

Число типа Currency лежит в диапазоне от -(2^63)/10000 до (2^63-1)/10000. Поэтому всё время приходится делить на 10000 и преобразовывать промежуточные результаты к типу Currency, поскольку Access постоянно норовит использовать Double. Если представить значение типа Currency как целое число, то использование его разрядов выглядит следующим образом:

Биты Использование в идентификаторе

Старший 63-й Знак (из аргумента командной строки)

6 (с 57-го по 62-й) Номер (из аргумента командной строки)

15 (с 42-го по 56-й) Дата

16 (с 26-го по 41-й) Время

Младшие 26 (с 0-го по 25-й) Случайное число

Знак числа (большая или меньшая половина номеров)

IIf(Val(Command()) > 63, 1, -1)

Номер из меньшей (1...63) или большей (64...127) половин. Чтобы уместиться в тип Currency, номер не должен превышать 63. Из-за этого использована функция Abs.

CCur(Abs(Val(Command()) - 64) * (2 ^ 57) / 10000)

Дата. Деление по модулю 2 ^ 15 позволяет втиснуться в отведенные 15 бит, сохраняя уникальность при этом около 80 лет.

CCur(CCur((Int(Now()) Mod 2 ^ 15) * (2 ^ 42) / 10000)

Время с точностью до ~1,3 секунды. В промежутке от 00:00:00 до 23:59:59 принимает значение от 0 до 0,99999 и масштабируется до нужных 16 бит умножением на 65535.

CCur(((Now() - Int(Now())) * 65535) * (2 ^ 26) / 10000)

Случайное число в диапазоне от 0 до 2 ^ 26 - 1. Уменьшение диапазона приводит к возникновению повторов.

CCur(Rnd() * (2 ^ 26 - 1)) / 10000))

Второй способ, очевидно, является более предпочтительным, так как позволяет создавать более компактные идентификаторы. Кроме того, он позволяет относительно безболезненно перейти от использования счётчиков, так как работа со строками гораздо сильнее отличается от работы с типами Long или Currency, чем они отличаются друг от друга.

Однако, есть и недостатки. Прежде всего, это ограниченное количество клиентов в системе (не более 127), вызванное сложностью втиснуться в рамки 8-ми байтного числа. Также, нет полной гарантии, что случайные числа не повторятся в пределах тех 1,3 секунды, когда уникальность ключа определяется исключительно работой генератора случайных чисел. В случае такого повтора возникнет ошибка дублирования, которая потребует повтора всей операции добавления записей. Правда, надо отдать должное Access'совской функции Rnd(): она достаточно долго генерирует неповторяющийся поток значений.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 25.10.2007 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Microsoft Office для дома и учебы 2019 (лицензия ESD)
Microsoft Office 365 Профессиональный Плюс. Подписка на 1 рабочее место на 1 год
Microsoft Office 365 для Дома 32-bit/x64. 5 ПК/Mac + 5 Планшетов + 5 Телефонов. Подписка на 1 год.
Microsoft 365 Business Basic (corporate)
Microsoft Windows Professional 10, Электронный ключ
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
Реестр Windows. Секреты работы на компьютере
Мастерская программиста
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100