Использование представления datetime float в качестве первичного ключа

Из своего опыта я узнал, что использование столбца суррогатного типа данных INT в качестве первичного ключа особенно. столбец ключа IDENTITY обеспечивает лучшую производительность, чем использование столбца типа данных GUID или char / varchar в качестве первичного ключа. Я стараюсь использовать ключ IDENTITY в качестве первичного ключа везде, где это возможно. Но недавно я натолкнулся на схему, в которой таблицы были разделены по горизонтали и управлялись через разделенное представление. Таким образом, в таблицах не может быть столбца IDENTITY, поскольку это сделало бы разделенное представление необновляемым. Одним из способов решения этой проблемы было создание фиктивной таблицы «генератора ключей» со столбцом идентификаторов для генерации идентификаторов для первичного ключа. Но это означало бы наличие таблицы «генератора ключей» для каждого из секционированных представлений. Следующей моей мыслью было использовать float в качестве первичного ключа. Причина в следующем ключевом алгоритме, который я разработал.

DECLARE @KEY FLOAT

SET @KEY = CONVERT(FLOAT,GETDATE())/100000.0 

SET @KEY = @EMP_ID + @KEY

Heres how it works.

CONVERT(FLOAT,GETDATE()) 

дает представление текущей даты и времени с плавающей запятой, поскольку внутренне все значения даты и времени представлены SQL как значение с плавающей запятой.

CONVERT(FLOAT,GETDATE())/100000.0 

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

@KEY = @EMP_ID + @KEY

добавляет идентификатор сотрудника, который является целым числом, к этому десятичному значению.

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

В целом уникальный ключ для всех сессий сотрудников и во времени.

Итак, для идентификаторов Emp Ids 11 и 12 у меня есть ключевые значения, такие как 12.40046693321566357, 11.40046693542361111

Но меня беспокоит, предлагает ли тип данных float в качестве первичного ключа преимущества по сравнению с выбором GUID или char / varchar в качестве первичных ключей. Также важно то, что разделение столбца с плавающей запятой будет частью составного ключа.


person devanalyst    schedule 23.08.2009    source источник


Ответы (3)


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

Какие? Почему? Вы приложили немало усилий, пытаясь сделать это значение, основанное на сотруднике / времени, уникальным, что еще вам понадобится в первичном ключе? И, с другой стороны, являются ли другие компоненты вашего ключа уникальными? Если да, то почему бы просто не использовать их?

Ваша схема оставляет неприятный привкус во рту. Я не совсем уверен, почему, потому что чем больше я думаю об этом, тем более убедительным это кажется.

  • Сначала беспокоился о производительности. Но число с плавающей запятой составляет всего 8 байтов (при условии, что ваша СУБД использует IEEE 754 double), что не так уж и много. Это не хуже, чем использование 64-битного целого числа в качестве ключа или двух 32-битных целых чисел. Ваш процесс генерации ключей - единственное, что может замедлиться, но даже это ненамного.
  • I then worried about uniqueness. This scheme doesn't guarantee that you won't generate the same key twice. But given your assertion that the combination of user and datetime will be unique, then this might actually work:
    • An IEEE 754 double has 53 bits of precision.
    • The datetime will use 42 bits. Assumptions:
      • Resolution of datetime is 1/300 second (3.33... ms). This is true for MS SQL Server, at least.
      • потолок (бревно 2 (86400 * 300 * 100000)) = 42
    • Это оставляет 9 бит для вашего идентификатора сотрудника. Если идентификатор сотрудника больше 511, вы потеряете часть даты и времени, но это будет порядка миллисекунд. Ваш идентификатор сотрудника может достигнуть 131071, прежде чем вы потеряете точность более чем на секунду.
  • Затем меня беспокоили трудности с поиском ключевого значения позже. Учитывая проблему 0,2! = 0,1 + 0,1, всегда приходят на ум вопросы равенства чисел с плавающей запятой. Но нет причин, по которым вы будете выполнять какие-либо вычисления с этим значением ключа, и, предположительно, оно будет в двойном формате IEEE 754 в любой момент времени (будь то в таблице, в сохраненных переменных процесса или в переменных в вашем исполняемом файле), затем оно никогда не должно изменяться и может рассматриваться как уникальное 64-битное значение.

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

Я все еще сомневаюсь, что это лучший метод, или даже если он вообще необходим.

  • Могут ли другие компоненты составного ключа не использоваться сами по себе (т. Е. Как естественный ключ)?

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

  • Использование первичного ключа GUID или varchar не исключено. Многие люди делают это на разных столах. Это не убьет вашу производительность. И это могло бы быть более простым или, по крайней мере, более понятным, чем эта схема.

  • Если ваш составной ключ уже включает идентификатор сотрудника, вы можете просто добавить столбец datetime к ключу и назвать его днем. Или, если нет, вы можете добавить оба столбца. Нет причин смешивать их вместе.

HTH

person P Daddy    schedule 23.08.2009
comment
Я наконец решил использовать составной первичный ключ, как это было предложено PDaddy. Первоначально я думал, что использование составных ключей может снизить производительность, но в моем случае использование комбинации полей Int и datetime не имеет большого значения. Составной ключ не кластеризован, и я создал кластеризованный индекс в поле Int. - person devanalyst; 29.08.2009
comment
Забыл упомянуть, что кластеризованный индекс создается в поле Int, потому что он будет использоваться в соединениях - person devanalyst; 29.08.2009

Я бы не стал рассматривать такую ​​неортодоксальную схему генерации ключей - это плохой хакер. Почему бы вам просто не использовать целые числа? Существует множество способов и алгоритмов координации генерации распределенных ключей. От блокировки всей таблицы (таблиц) и поиска следующего свободного идентификатора в предварительно выделенных диапазонах идентификаторов для каждого клиента до получения его из конкретной информации о клиенте (аналогично предложению вашего сотрудника + время).

person Daniel Brückner    schedule 23.08.2009
comment
Блокировка всей таблицы и поиск следующего свободного идентификатора - этого метода я стараюсь избегать, поскольку блокировка таблицы с миллионами строк и сканирование ее для следующего доступного идентификатора может стать узким местом в производительности. Предварительное выделение диапазонов идентификаторов - я пытаюсь выяснить можно ли таким образом получить метод, позволяющий избежать сканирования таблиц - person devanalyst; 23.08.2009
comment
На самом деле нужно было бы только заблокировать индекс. И поиск по индексу миллион + не так уж и плох. В конце концов, они для этого. - person P Daddy; 23.08.2009
comment
Я только что упомянул блокировку таблицы для полноты, но на самом деле не рекомендую ее (в средах с высокой степенью параллелизма). - person Daniel Brückner; 24.08.2009

Поскольку вы не упомянули rdbms, я буду использовать SQL-сервер. При создании первичного ключа также создается кластеризованный индекс для этого ключа. Таблица сортируется в порядке этого ключа. При использовании Guids в качестве первичного ключа (с кластеризованным индексом) каждая вставка означает переупорядочение таблицы. Это также верно для вашего представления с плавающей запятой. Помимо других проблем, если вы хотите использовать эту схему, не создавайте кластеризованный индекс по этому первичному ключу.

person edosoft    schedule 23.08.2009