Как формируется GUID?
Разработка - Механизмы платформы 1С
Начнем издалека../
Что такое GUID или уникальный идентификатор объекта?
GUID (Globally Unique Identifier) - статический уникальный 128-битный идентификатор. Его главная особенность - уникальность, которая позволяет создавать расширяемые сервисы и приложения без опасения конфликтов, вызванных совпадением идентификаторов. Хотя уникальность каждого отдельного GUID не гарантируется, общее количество уникальных ключей настолько велико (2^128 или 3,4028*10^38), что вероятность того, что в мире будут независимо сгенерированы два совпадающих ключа, крайне мала.
GUID состоит из четырех частей разделенных символом тире и содержащих в сумме 32 символа, которые являются шестнадцатеричным представлением 16 байт (128 бит). Т.е. два символа в GUID (октет) – это один байт в шестнадцатеричном виде. Пример GUID: b0d4ce5d-2757-4699-948c-cfa72ba94f86
[1]
Почему используется guid, а не простой auto-increment(indentity)?
Для использования гуидов есть 2 причины:
- хотим чтобы база данных или какой-нибудь другой сервер(кластер) не имел централизованного управления генерацией ключей
- нужно избавиться от проблемы создания одинакового идентификатора на разных рабочих серверах
Такие проблемы обычно возникают в распределенной среде исполнения, а кластер серверов позиционируется как распределенный и желательно полностью избежать единой точки выдачи уникальных ключей.
Если ваша система не имеет таких требований, вам не нужен UUID.
[1] [2]
В чем разница между uuid и guid?
UUID это термин из стандарта rfc4122, который опубликует всемирная организация стандартизации eitf.
Грубо говоря GUID это то что получилось на практике у Microsoft. Теория различается с практикой так же, как и XML с HTML.
[1] [2]
В бд гуиды имеют тип binary(16) и сравниваются (сортируются) побитово как бинарные данные: binary bit-for-bit comparison behavior
upd: Как преобразовывать binary(16) в GUID1C и обратно?
-- GUID1C --> binary(16)
declare @GUIDasStr char(36),@GUID1С char(36);
SET @GUID1С = '80AB7036-5D4A-11E6-9903-0050569977A1'
SET @GUIDasStr ='0x'+SUBSTRING(@GUID1С,20,4)+SUBSTRING(@GUID1С,25,13)+SUBSTRING(@GUID1С,15,4)+SUBSTRING(@GUID1С,10,4)+SUBSTRING(@GUID1С,1,8)
SELECT CONVERT(binary(16),@GUIDasStr,1) as BinaryGUID
-- то же хранимкой
CREATE function [dbo].[sp_getbinary] (@GUID1С char(36))
returns binary(16)
as
begin
declare @GUIDasStr char(36)
select @GUIDasStr ='0x'+SUBSTRING(@GUID1С,20,4)+SUBSTRING(@GUID1С,25,13)+SUBSTRING(@GUID1С,15,4)+SUBSTRING(@GUID1С,10,4)+SUBSTRING(@GUID1С,1,8)
return ( CONVERT(binary(16),@GUIDasStr,1) )
end;
-- и обратно binary(16) --> GUID1C (хранимая процедура)
CREATE function [dbo].[sp_getid] (@id binary(16))
returns char(36)
as
begin
declare @unidentifier char(36)
declare @charvalue char(36)
select @unidentifier = CONVERT(char(36),CAST(@id as uniqueidentifier))
select @charvalue =
right(@unidentifier, 8)
+ substring(@unidentifier,24,5)
+ substring(@unidentifier,19,5)
+ '-'
+ substring(@unidentifier,7,2)
+ substring(@unidentifier,5,2)
+ '-'
+ substring(@unidentifier,3,2)
+ left(@unidentifier,2)
+ substring(@unidentifier,12,2)
+ substring(@unidentifier,10,2)
+ substring(@unidentifier,17,2)
+ substring(@unidentifier,15,2)
return ( @charvalue )
end;
-- более медленный вариант
CREATE FUNCTION dbo.Convert_IDRRefToGUID(@_IDRRef binary(16))
RETURNS VARCHAR(36)
AS
BEGIN
RETURN
substring(substring(sys.fn_varbintohexstr(@_IDRRef),3, len(sys.fn_varbintohexstr(@_IDRRef))),25,8) + ‘-‘ +
substring(substring(sys.fn_varbintohexstr(@_IDRRef),3, len(sys.fn_varbintohexstr(@_IDRRef))),21,4) + ‘-‘ +
substring(substring(sys.fn_varbintohexstr(@_IDRRef),3, len(sys.fn_varbintohexstr(@_IDRRef))),17,4) + ‘-‘ +
substring(substring(sys.fn_varbintohexstr(@_IDRRef),3, len(sys.fn_varbintohexstr(@_IDRRef))),1,4) + ‘-‘ +
substring(substring(sys.fn_varbintohexstr(@_IDRRef),3, len(sys.fn_varbintohexstr(@_IDRRef))),5,12);
END;
--Пример работы функции:
SELECT TOP (5) [_Period], [_Fld517RRef], dbo.sp_getid([_Fld517RRef]) AS GUID
FROM [dbo].[_InfoRg516]
where [_Fld518RRef]= 0x99030050569977A111E65D4A80AB7036
and [_Period]<CONVERT(datetime2, '01.01.4019')
--Результат выполнения:
_Period _Fld517RRef GUID
4016-08-08 12:40:16 0x8B6F0050569977A111E60D1B75078E17 75078E17-0D1B-11E6-8B6F-0050569977A1
4016-08-08 12:40:16 0x8B6F0050569977A111E610D3CDF12109 CDF12109-10D3-11E6-8B6F-0050569977A1
4016-08-08 12:40:16 0x8B6F0050569977A111E615F5ED3103B6 ED3103B6-15F5-11E6-8B6F-0050569977A1
4016-08-08 12:40:16 0x8B6F0050569977A111E618FEEC1C9706 EC1C9706-18FE-11E6-8B6F-0050569977A1
4016-08-08 12:40:16 0x8B6F0050569977A111E61C801F611143 1F611143-1C80-11E6-8B6F-0050569977A1
-- или так
declare @BinaryGUID binary(16);
SET @BinaryGUID = 0x99030050569977A111E65D4A80AB7036
SELECT dbo.sp_getid(@BinaryGUID) AS GUID
--Результат выполнения:
GUID
80AB7036-5D4A-11E6-9903-0050569977A1
// преобразовывает гуид 1c в формат mssql
Функция ПолучитьBinaryGUIDПоУникальномуИдентификатору(UUID1)
UUID=ВРЕГ(UUID1);
ч1 = Сред(UUID,20,4);
ч2 = Сред(UUID,25,12);
ч3 = Сред(UUID,15,4);
ч4 = Сред(UUID,10,4);
ч5 = Сред(UUID,1,8);
Возврат "0x" + ч1 + ч2 + ч3 + ч4 + ч5;
КонецФункции
// или так
Функция ПолучитьВнутрСсылку(Ссылка)
Если лСсылка = Неопределено Тогда
Возврат "";
КонецЕсли;
Зн = ЗначениеВСтрокуВнутр(Ссылка);
Зн = "0x" + Лев(Прав(Зн, 33), 32);
Возврат Зн;
КонецФункции
// и обратно (c) //infostart.ru/public/99109/
Функция UUIDToGUID(UUID) Экспорт
Возврат Прав(UUID, 8) + "-" + Сред(UUID, 21, 4) + "-" + Сред(UUID, 17, 4) + "-" + Лев(UUID, 4) + "-" + Сред(UUID, 5, 12);
КонецФункции
Из чего состоит guid?
Определяется типом:
- Random: Just use the system’s random-number generator to create a 128-bit number.
- Time-based: Create a GUID based on the current time.
- Hardware-based: Make a GUID with certain portions based on hardware features, such as the MAC address of a network card.
- Content-based (MD5 or SHA-1 hash of data): Create a GUID based on a hash of the file contents. Files with the same contents will get the same GUID.
[1]
Как определить версию GUID?
Версия гуида определяется в старшем байте 7 октета.
b0:d4:ce:5d-27:57-46:99-94:8c-cf:a7:2b:a9:4f:86
4 - random, 1 - Time-based
[1]
Почему нельзя упорядочить по ссылке, если в ней содержится дата создания?
Как уже было описано, guid изначально был придуман для РАСПРЕДЕЛЕННЫХ систем, в которых ПРОБЛЕМА УНИКАЛЬНОСТИ идентификаторов решена полным ОТКАЗОМ ОТ АВТОИНКРЕМЕНТА в пользу СЛУЧАЙНЫХ чисел и специальных техник. GUIDы случайны и неповторяемы по определению и в этом его достоинство и недостаток. Например, в предопределенных элементах и произвольных идентификаторах используется Random GUIDs (Version 4). В "типизированных" же Time-Based GUIDs (Version 1).
Используются разные стандарты?
Да, но когда индексам БД приходится работать со случайными значениями ключей(см. B-Tree Insertion) возникают проблемы.
[1] [2]
То есть для ссылок может создаваться Random GUID?
Только для предопределенных элементов и вручную созданных гуидов.
ГУИДВидНоменклатуры = Новый УникальныйИдентификатор();
ВидНоменклатурыСсылка = Справочники.ВидыНоменклатуры.ПолучитьСсылку(ГУИДВидНоменклатуры);
ВидНоменклатурыОбъект = Справочники.ВидыНоменклатуры.СоздатьЭлемент();
ВидНоменклатурыОбъект.УстановитьСсылкуНового(ВидНоменклатурыСсылка);
ВидНоменклатурыОбъект.Наименование = "тест";
ВидНоменклатурыОбъект.Записать();
Результат:
Ссылка Код Предопределенный Наименование
4ad76228-517f-4496-aa6c-eef36d3de35a 000000001 истина Товар <-- Random UUID (version 3)
01d3ff0d-cc37-4863-adef-72d3b0dbf08a 000000002 истина Продукция
623bca27-dffd-4391-b233-20ca170549d4 000000010 ложь тест
769e3f33-50d7-11e7-bcda-94de807c3939 000000005 ложь 1 <-- Time-based UUID (version 1)
769e3f34-50d7-11e7-bcda-94de807c3939 000000006 ложь 2
769e3f35-50d7-11e7-bcda-94de807c3939 000000007 ложь 3
Первые три - random based, вторые три - time-based.
И все-таки?
Random UUIDs вызывают деградацию операций вставки. У таких гуидов индексы получаются плохо кластеризованы, дерево поиска максимально широкое. Для обхода этого недостатка был придуман COMB Guid - Combined Guid for the combination of a timestamp. Поэтому когда используюся Time-Based GUIDs для первичных ключей, они получаются более сгруппированными, но никак не последовательными. "Механизм генерации ссылок обеспечивает только их уникальность. Возрастающая последовательность при их генерации не обеспечивается." (c) БГ
[1]
Но у гуидов есть же последовательность? Что-то там про МоментВремени?
Да сколько можно? Нет у гуидов последовательности! Кто первый запросил - тому и выдается пул. А когда уж сеанс его исчерпает - зависит от него самого. Читаем подробнее про эксперимент с МоментомВремени.
//infostart.ru/public/84177/
Можно ли вытащить время из гуида?
Можно. Но не нужно.
bdb62d89-cede-11e4-b12b-d4ae52b5e909
Алгоритм:
дата содержится в первых символах, bdb62d89-cede-11e4 которые нужно переставить задом наперед: 11e4-cede-bdb62d89
первый символ отбрасываем, убираем "лишние" знаки "-"(тире)
интервал в десятых долях микросекунд (HEX) получается равным: интервал16= 1E4CEDEBDB62D89
переводим его в десяничный интервал интервал10 = HexToDec(интервал16);
в результате получаем: интервал10 = 136 461 344 788 852 105
находим интервал в секундах: интервалСек = интервал10 / 10 000 000;
Делаем сдвиг даты от 15.10.1582 г. + 13 646 134 478 + сдвиг на часовой пояс (Московское время) от "мирового времени" (GMT) = 20.03.2015 16:54:38
[1] [2] [3]
Почему части времени идут "задом-наперед"?
"Так сложилось" ;)
Например потому что guid'ы появились задолго до того, как до них добрались руки ietf и баз данных.
Или потому что платформа написана на C, а не на Java, а как мы знаем из асемблера архитектура x86 имеет little-endian byte order.
Или, как говорит википедия, использовалось 2 варианта: для передачи по сети "on-wire" "network" (big-endian) byte order, а для хранения "native" (little-endian) byte order.
В любом случая я не знаю как там было и можно только догадываться.
[1] [2] [3] [4]
А последние две части что значат?
bdb62d89-cede-11e4-b12b-d4ae52b5e909
Счетчик "уникальности" и физический MAC-адрес.
Почему нельзя использовать время из GUID?
Во-первых, гуид может быть случайным, а не основаным на времени.
Во-вторых, гуиды выдаются пулом по 32 штуки для каждого сеанса.
В-третьих, гуид случаен по своему стандарту и время в нем это лишь способ сгруппировать первичные ключи для уменьшения ширины В-дерева и ускорения операций вставки в кластерный индекс!
[1] [2] [3]
Если отчет из одной конфигурации копипастой тащу в другую - ID сохранится его?(в моей его не было) (c) 2michael
Ответ: При копировании объекта из одной конфы в другую _копипастом_ внутренний гуид меняется!
НО: при сравнении объединении этого не видно!, так как происходит сопоставление по имени.
НО: это не касается и предопределённых данных! Если добавлять их вручную, а потом конфу разработки сравнить-объединить с боевой - возникнут дубли в справочнике!
В edt же есть режим сравнения только по guid.
Именно поэтому создание нового объекта желательно делать через сравнение-объединение, иначе будет замедление на больших конфигурациях. Подробнее в ИТС: https://its.1c.ru/db/metod8dev/content/2299/hdoc
При замене отчета в дереве конфигурации командой "Заменить на внешнюю обработку, отчет..." меняется ли внутренний идентификатор объекта (отчета)? (с) Pandoch upd:02.07.20
Ответ: Нет, гуид при замене из файла остаётся прежним
Другая вариация вопроса: Есть две разные конфы. Но в них есть одинаковый объект метаданных например документ "Покупка". Как можно получить внутренний идентификатор этого объекта в обеих базах, используемый в сравнении и объединении, чтобы удостовериться, что этот объект, не зависимо от имени, замениться, а не дублируется ? Как я понял ЗначениеВСтрокуВнутр() дает не тот ID который нужен мне.
Вообще, внутренний идентификатор объекта программно узнать нельзя, а увидеть его можно в выгрузке конфигурации в файлы, строка <Report uuid="1ce0ffe7-2218-4d9d-88d5-d3eec204bfff">:
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" ... version="2.6">
<!--это внутренний гуид отчета:-->
<Report uuid="98b2e87d-e5cc-449a-aeab-e4ca51d5c46a">
<InternalInfo>
<!--это гуид типа объекта:-->
<xr:GeneratedType name="ReportObject.ДебиторскаяЗадолжность" category="Object">
<xr:TypeId>6737b9b2-732d-4051-8166-59d1d4209295</xr:TypeId>
<xr:ValueId>b93b9dff-ff02-4fd6-860b-ce98ef64df97</xr:ValueId>
</xr:GeneratedType>
<!--это гуид типа менеджера:-->
<xr:GeneratedType name="ReportManager.ДебиторскаяЗадолжность" category="Manager">
<xr:TypeId>b0291e09-dae8-47bb-b380-9c25be22fab3</xr:TypeId>
<xr:ValueId>4bfb0318-b989-43c3-937d-b32ac8b80385</xr:ValueId>
</xr:GeneratedType>
При каждой выгрузке во внешний отчет/обработку guid генерируется заного. При загрузке из файла - востанавливается. Это позволяет хоть 10 раз выгрузить отчет/обработу во внешний файл, и каждый из этих файлов можно будет открыть параллельно в клиенте.
ЗначениеВСтрокуВнутр() выдает идентификатор прикладного типа, а не внутреннего объекта метаданных. Помимо внутреннего идентификатора у каждого объекта метаданных есть идентификаторы типов. Например ОтчетМенеджер.<Имя отчета> и ОтчетОбъект.<ИмяОтчета>:
МенеджерОтчета = Отчеты.ДебиторскаяЗадолжность;
Сообщить(ТипЗнч(МенеджерОтчета)); // Отчет менеджер: Дебиторская задолжность
Сообщить(ЗначениеВСтрокуВнутр(МенеджерОтчета)); // {"#",b0291e09-dae8-47bb-b380-9c25be22fab3,
ОбъектОтчета = Отчеты.ДебиторскаяЗадолжность.Создать();
Сообщить(ТипЗнч(ОбъектОтчета)); // Отчет объект: Дебиторская задолжность
Сообщить(ЗначениеВСтрокуВнутр(ОбъектОтчета)); // {"#",6737b9b2-732d-4051-8166-59d1d4209295}
МетаданныеОтчета = Метаданные.Отчеты.ДебиторскаяЗадолжность;
Сообщить(ТипЗнч(МетаданныеОтчета)); // Объект метаданных
Сообщить(ЗначениеВСтрокуВнутр(МетаданныеОтчета)); // {"#",9fb58eea-17f2-4200-b105-b288d62f4303}
МетаданныеЯзыка = Метаданные.Языки.Русский;
Сообщить(ТипЗнч(МетаданныеЯзыка)); // Объект метаданных
Сообщить(ЗначениеВСтрокуВнутр(МетаданныеЯзыка)); // {"#",9fb58eea-17f2-4200-b105-b288d62f4303}
// выводит тоже самое, так как это гуид типа встроенного в платформу
Все типы имеют свои идентификаторы, но при загрузке через "Заменить на внешнюю обработку, отчет..." они, так же как и идентификатор метаданных, заменяются на текущие.
Например - загрузка в отчет ABCАнализПокупателей внешнего отчета ДебиторскаяЗадолжность.epf вызовет лишь добавление суффикса (такой отчет уже есть в конфигурации), а все идентификаторы остаются прежними.
Скрин до загрузки - после загрузки:

Идентификаторы не изменились.
Почему используется "перевернутый" формат UUID внутри 1с?
<Объект не найден> (26:80f408002771598b11e7a3f0a3a64c3b)
Не знаю. Знаю только что первая цифра соответствует имени таблицы в sql: Reference26 -> ВидыНоменклатуры
Есть же спецификация?
Есть.
bdb62d89-cede-11e4-b12b-d4ae52b5e909
Layout
0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | time_hi_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Bit mask
FFFFFFFF-0000-0000-0000-000000000000 time_low
00000000-FFFF-0000-0000-000000000000 time_mid
00000000-0000-F000-0000-000000000000 version
00000000-0000-0FFF-0000-000000000000 time_hi
00000000-0000-0000-C000-000000000000 variant
00000000-0000-0000-3FFF-000000000000 clock_seq
00000000-0000-0000-0000-FFFFFFFFFFFF node
Byte order
Field Data Type Octet Note
#
time_low unsigned 32 0-3 The low field of the
bit integer timestamp
time_mid unsigned 16 4-5 The middle field of the
bit integer timestamp
time_hi_and_version unsigned 16 6-7 The high field of the
bit integer timestamp multiplexed
with the version number
clock_seq_hi_and_rese unsigned 8 8 The high field of the
rved bit integer clock sequence
multiplexed with the
variant
clock_seq_low unsigned 8 9 The low field of the
bit integer clock sequence
node unsigned 48 10-15 The spatially unique
bit integer node identifier
Расшифровываю:
Timestamp - это 60-битное число, содержащее количество 100-наносекундных интервалов с 15 октября 1582 г.
Часть low обнуляется каждые 2^32 / 10^7 / 60 ~ 7 минут, часть mid через 1 год, часть hi сами представляете.
Version - старшие 4 бита в седьмом октете, содержат тип гуида.
0x0001 1 time-based version
0x0010 2 DCE Security version (POSIX UIDs)
0x0011 3 name-based version (MD5 hashing)
0x0100 4 randomly generated version
0x0101 5 name-based version (SHA-1 hashing)
Clock Sequence - используется чтобы избежать появления дубликатов, когда часы переводятся назад или меняется идентификатор узла. Если предыдущее значение счетчика известно - то увеличивается на единицу, иначе берется случайное число.
Node - содержит физический MAC-адрес сервера. Дада, проверьте ipconfig /all ;)
Примеры? Есть их у меня.
Мы же "программисты", накодим функции:
// Возвращает время создания GUID'а
//
Функция UUID_Timestamp(ГУИД)
// Например ГУИД равен: bdb62d89-cede-11e4-b12b-d4ae52b5e909
// Дата содержится в первых символах, bdb62d89-cede-11e4 которые нужно переставить задом наперед: 11e4-cede-bdb62d89
Строка16 = Сред(ГУИД, 15, 4) + Сред(ГУИД, 10, 4) + Сред(ГУИД, 1, 8);
// Убираем "лишние" знаки "-"(тире).
Строка16 = СтрЗаменить(Строка16, "-", "");
// Убираем первый символ, так как в нем содержится версия стандарта (зашит в седьмой октет)
Строка15 = Сред(Строка16, 2);
// Получаем timestamp в 60 бит : 1E4 CEDE BDB6 2D89
ЧислоСек = 0;
Для Позиция = 1 По СтрДлина(Строка15) Цикл
ЧислоСек = ЧислоСек + Найти("123456789abcdef",Сред(Строка15,Позиция,1))*Pow(16,СтрДлина(Строка15) - Позиция);
КонецЦикла;
ЧислоСек = ЧислоСек / 10000000;
// Прибавляем к дате начала Григореанского календаря
Возврат Дата(1582, 10, 15, 00, 00, 00) + ЧислоСек + СмещениеСтандартногоВремени() + СмещениеЛетнегоВремени();;
КонецФункции
// Возвращает версию GUID'а
//
Функция UUID_Version(ГУИД)
// Пусть ГУИД равен: bdb62d89-cede-11e4-b12b-d4ae52b5e909
// Тогда номер версии содержится в старшем байте седьмого октета
Версия = Сред(ГУИД, 15, 1)*1;
СтрокаВерсий = "Version 1. Time-based
| Version 2. DCE Security (POSIX)
| Version 3. Name-based (MD5 hashing)
| Version 4. Random
| Version 5. Name-based (SHA-1 hashing)
| Unknown version";
Возврат СтрПолучитьСтроку(СтрокаВерсий, Мин(СтрЧислоСтрок(СтрокаВерсий), Версия));
КонецФункции
// Возвращает mac-адрес сервера
//
Функция UUID_Node(ГУИД)
// Пусть ГУИД равен: bdb62d89-cede-11e4-b12b-d4ae52b5e909
// Тогда MAC-адрес в последней части
Строка12 = Сред(ГУИД, 25);
// Разделим на октеты
Результат = "";
Для Позиция = 1 По СтрДлина(Строка12) Цикл
Если Позиция % 2 = 1 Тогда
Результат = Результат + " ";
КонецЕсли;
Результат = Результат + ВРЕГ(Сред(Строка12,Позиция,1));
КонецЦикла;
Результат = СтрЗаменить(СокрЛП(Результат), " ", ":");
Возврат Результат;
КонецФункции
Проверим ссылку обычного документа:
// Вытащим информацию из ссылки, созданной системой
Выборка = Документы.ПоступлениеТоваровУслуг.Выбрать( , , , "Дата УБЫВ");
Если Выборка.Следующий() Тогда
ГУИД = Выборка.Ссылка.УникальныйИдентификатор();
Сообщить("Ссылка: " + Выборка.Ссылка);
Сообщить("GUID: " + ГУИД);
Сообщить("Дата создания: " + UUID_Timestamp(ГУИД));
Сообщить("Версия: " + UUID_Version(ГУИД));
Сообщить("MAC-адрес хоста: " + UUID_Node(ГУИД));
КонецЕсли;
// Получим:
//Ссылка: Поступление товаров и услуг ВА000000560 от 06.06.2017 0:00:01
//GUID: a7de1f17-4a83-11e7-9e20-0021918e8333
//Дата создания: 06.06.2017 10:44:57
//Версия: Version 1. Time-based
//MAC-адрес хоста: 00:21:91:8E:83:33
Проверим ссылку, сформированную вручную:
// Вытащим информацию из ссылки, созданной &НаКлиенте
ДокСсылка = Документы.ПоступлениеТоваровУслуг.ПолучитьСсылку(Новый УникальныйИдентификатор());
ГУИД2= ДокСсылка.УникальныйИдентификатор();
Сообщить("Ссылка нового: " + ДокСсылка);
Сообщить("GUID нового: " + ГУИД2);
Сообщить("Версия нового: "+ UUID_Version(ГУИД2));
//Ссылка нового: <Объект не найден> (152:936654ac78639f43411ad7a77db94d48)
//GUID нового: 7db94d48-d7a7-411a-9366-54ac78639f43
//Версия нового: Version 4. Random
Проверим работу счетчика "уникальности":
// Проверим работу clock_seq
Для й=1 по 32 Цикл
НачатьТранзакцию();
ВидНоменклатураОбъект = Справочники.НоменклатураТест.СоздатьЭлемент();
ВидНоменклатураОбъект.наименование = "тест1";
ВидНоменклатураОбъект.Записать();
ГУИД = ВидНоменклатураОбъект.Ссылка.УникальныйИдентификатор();
Сообщить(ГУИД);
ОтменитьТранзакцию();
КонецЦикла;
// переведем время на минуту назад
КомандаСистемы("time "+Формат(ТекущаяДата()-60, "ДФ='hh:mm:ss tt'"));
// Выберем весь старый пул
Для й=1 по 32 Цикл
НачатьТранзакцию();
ВидНоменклатураОбъект = Справочники.НоменклатураТест.СоздатьЭлемент();
ВидНоменклатураОбъект.наименование = "тест2";
ВидНоменклатураОбъект.Записать();
ГУИД = ВидНоменклатураОбъект.Ссылка.УникальныйИдентификатор();
Сообщить(ГУИД);
ОтменитьТранзакцию();
КонецЦикла;
// Получим:
//...
//81c42878-526c-11e7-80f0-08002771598b
//81c42879-526c-11e7-80f0-08002771598b
//81c4287a-526c-11e7-80f0-08002771598b
//723dee43-526c-11e7-80f1-08002771598b
//723dee44-526c-11e7-80f1-08002771598b
//...
Можно даже так:
НачатьТранзакцию();
ГУИД = Новый УникальныйИдентификатор("deadbeef-d7a7-411a-9366-defaced0babe");
НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
НовыйОбъект.УстановитьСсылкуНового(Справочники.Номенклатура.ПолучитьСсылку(ГУИД));
НовыйОбъект.ВидНоменклатуры = Справочники.ВидыНоменклатуры.ПолучитьСсылку(ГУИД);
НовыйОбъект.Наименование = "Свежее мясо";
НовыйОбъект.ОбменДанными.Загрузка = Истина;
НовыйОбъект.Записать();
Сообщить("GUID нового: " + НовыйОбъект.Ссылка.УникальныйИдентификатор());
Сообщить("Реквизит нового: " + НовыйОбъект.ВидНоменклатуры);
ОтменитьТранзакцию();
//GUID нового: deadbeef-d7a7-411a-9366-defaced0babe
//Реквизит нового: <Объект не найден> (5433:9366defaced0babe411ad7a7deadbeef)
Какой мак-адрес у меня, вы уже знаете ;)
ps: под "упорядочить по ссылке" везде имеется ввиду сортировка в порядке создания ссылок и вообще в каком-либо порядке, отличном от сравнения в побитовом бинарном формате хранения бд.
Ну вот и все.
Надеюсь, теперь мысль о том, чтобы "упорядочить по ссылке", я из вас вытряхнул окончательно.
;-P
ТОП-6 инструментов для разработчика 1С
Подборка лучших инструментов для разработчика 1С включает Toolkit, DCT, OneDebugger, PrintWizard, DataFormWizard и Infostart MCP. Любой инструмент со скидкой 20% при покупке от двух решений.
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
Механизмы платформы 1С Разработчик Бесплатно (free)
Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?
16.07.2025 45726 TitanLuchs 109
Работа с интерфейсом WEB-интеграция Механизмы платформы 1С Бесплатно (free)
Веб-интерфейсы повышают качество внешнего вида приложений 1С, предсказуемы с точки зрения верстки, позволяют организовать удобные и высокопроизводительные рабочие места для пользователей. Расскажем об особенностях разработки веб-интерфейсов на React внутри 1С, двустороннем взаимодействии 1С и JavaScript, а также сборке веб-приложения в одностраничный файл.
19.06.2025 18732 zeegin 15
Механизмы платформы 1С Работа с интерфейсом Разработчик Стажер 1С:Предприятие 8 Бесплатно (free)
Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).
03.02.2025 26067 bayselonarrend 127
Механизмы платформы 1С Разработчик 1С:Предприятие 8 Бесплатно (free)
В этой статье подробно рассматривается работа с JSON в XDTO в 1С:Предприятие. Вы узнаете, как сериализовать и десериализовать объекты XDTO в JSON, интегрировать 1С с веб-сервисами и API, а также корректно обрабатывать данные при обмене. Разбираются особенности работы с коллекциями, использование функций восстановления и частые ошибки при работе с JSON и XDTO.
30.01.2025 33360 user2122906 10
Механизмы платформы 1С Файловый обмен (TXT, XML, DBF), FTP Разработчик 1С:Предприятие 8 Бесплатно (free)
Этот материал познакомит вас с механизмом XDTO (XML Data Transfer Objects) в 1С и научит эффективно использовать его возможности. Мы разберёмся, как работать с XML-схемами, создавать модели данных, манипулировать объектами XDTO, а также сериализовать и десериализовать их в XML. Вы узнаете, как использовать XDTO для интеграции с внешними системами, избегать типичных ошибок и оптимизировать код. К концу вы будете уверенно применять XDTO для решения сложных задач обмена данными и автоматизации процессов.
17.01.2025 55927 user2122906 13
Механизмы платформы 1С WEB-интеграция Разработчик 1С:Предприятие 8 Бесплатно (free)
В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.
14.01.2025 46894 dsdred 110
Механизмы платформы 1С Разработчик 1С:Предприятие 8 Бесплатно (free)
Особенности "Знач" и разбор документации к нему.
10.01.2025 26501 VAAngelov 60
Механизмы платформы 1С Разработчик Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)
Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.
23.06.2024 40511 bayselonarrend 24
Ну или ставить галку "Автоупорядочивание" ))
Записывай как строку и вперёд.
Поэтому и спрашиваю - почему отсутствует нативный способ выбора типа "уникальный идентификатор", в регистре сведений он же присутствует. Может причина в нежелательности его использования.
Поправьте опечатку.
Есть вопрос. MAC адрес берется клиента или сервера?
Упорядочивать по времени не будем, а вот отсечь какие-нибудь элементы справочника на основе времени полученного из UUIDA все-таки можно.
И если вы напишете код который для вашей организации будет создавать GUID для нового документа с типом Документ.МойКрутойАвансовыйОтчет то далеко не факт что на такой же аналогичной конфигурации в другой базе вашей компании этот код даст работоспособный GUID, придется перепроверять.
Всё несколько печальнее. Гуид МОЖЕТ быть уникален не в пределах одной базы. Практически же в одной базе может существовать несколько объектов с одинаковым гуид. В разных таблицах.
Я столкнулся с этим, когда пользовал конвертацию данных. Конвертация данных сохраняет идентификатор объекта при передаче его в другую базу. Если одному источнику соответствует несколько получателей, то мы получим в одной базе несколько объектов с одинаковы гуид.
Например, при переходе с УТ10 на УТ11 справочник контрагенты передаётся в справочники контрагенты и партнёры. При этом гуиды у контрагента и партнёра получаются одинаковыми.
_а1 = значениевстрокувнутр(Тип("Массив"));
_а2 = значениевстрокувнутр(новый("Массив"));
//{"T",51e7a0d2-530b-11d4-b98a-008048da3034}
//{"#",51e7a0d2-530b-11d4-b98a-008048da3034,{0}}
_б1 = значениевстрокувнутр(Тип("ТекстовыйДокумент"));
_б2 = значениевстрокувнутр(новый("ТекстовыйДокумент"));
//{"T",ebf766b1-f32c-11d3-9851-008048da1252}
//{"#",ebf766b1-f32c-11d3-9851-008048da1252,{0,{#base64:77u/}}}
_в1 = значениевстрокувнутр(Тип("СправочникСсылка.Справочник1"));
_в2 = значениевстрокувнутр(справочники.справочник1.пустаяссылка());
_в3 = значениевстрокувнутр(справочники.справочник1.первый);
//{"T",03f456d1-078b-47bd-821e-1d16c25cdd8d}
//{"#",03f456d1-078b-47bd-821e-1d16c25cdd8d,10:00000000000000000000000000000000}
//{"#",03f456d1-078b-47bd-821e-1d16c25cdd8d,10:9db766f0d06c0eb24ef19d0bbdc5c7af} Показать_Все_ внутренние типы данных имеют идентификатор, в том числе и объекты типа ссылка. Любая ссылка состоит из идентификатора типа, и, собственно, самой ссылки.
Идентификатор же объекта метаданных программно получить нельзя, только выгрузкой конфигурации в файлы.
typedef struct _GUID {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[ 8 ];
} GUID;
В ссылке данные переставлены следующим образом:
- Data4 - 8 байт
- 1-й байт Data3
- 0-й байт Data3
- 1-й байт Data2
- 0-й байт Data2
- 3-й байт Data3
- 2-й байт Data3
- 1-й байт Data3
- 0-й байт Data3
При автоматической генерации ссылок, UUID'ы, используемые для получения ссылок, генерируются в Windows с помощью функции Win32 API UuidCreateSequential(). В результате ссылки, полученные по последовательно сгенерированным UUID'ам отличаются в байтах с максимальными индексами. То есть две последовательно сгенерированные ссылки будут отличаться значениями байтов с индексом 15 (0-базированный индекс).
Такая дисциплина генерации ссылок дает очень компактные индексы по ссылкам в файловой базе данных, так как в терминальных страницах индекса (листьях дерева) для упаковки ключей используется общий префикс. Другими словами, на терминальной странице индекса целиком обязательно записывается только первый ключ. Если последующий ключ имеет общий префикс с предыдущим, то для последующего ключа записываются только отличающиеся хвостовые байты.
Еще одной особенностью является то, для автоматической генерации ссылок, соединение с базой данных получает сразу пакет из последовательно сгенерированных UUID'ов. Размер пакета равен 64. При необходимости генерации новой ссылки используется очередной UUID из этого пакета. Как только пакет заканчивается соединение запрашивает новый пакет и т. д. Пакеты были введены для борьбы с неприятными последствия KeyRange блокировок, используемых MS SQL Server в режиме изоляции транзакций SERIALIZABLE. Не вдаваясь в излишние подробности, рассмотрим простой пример. Если в режиме SERIALIZABLE в рамках транзакции выполнить SELECT с WHERE <ссылка>=<значение ссылки>, то для индекса, построенного по ссылке, до конца транзакции окажется заблокированным диапазон ключей от ближайшего меньшего, чем <значение ссылки> до ближайшего большего, чем <значение ссылки>. (Если ближайшего меньшего или ближайшего большего нет, то блокируется все начало или весь хвост индекса.) Соответственно, внесение другими транзакциями новых записей с ключами попадающими в этот диапазон будет заблокировано до завершения транзакции, заблокировавшей диапазон.
Пакеты ссылок позволяют возможное пространство ключей разделить на диапазоны, каждый из которых "принадлежит" определенному соединению. Диапазоны непостоянны и меняются со временем. Но в идеальном случае такой диапазон с одной стороны ограничен максимальной использованной ссылкой из пакета, принадлежащего данному соединению, а с другой стороны - минимальной ссылкой из пакета, принадлежащего другому соединению.
В режиме управляемых блокировок режим SERIALIZABLE не используется и использование пакетов в значительной мере утратило свой смысл.
Источник:
Битая ссылка имеет вид <Объект не найден> (77:805f000c291e652311e0ad237dea6181). Здесь 77 - это номер таблицы, т.е. тип объекта, об этом уже говорили выше. А строка после двоеточия - это и есть ссылка.
Если получить ссылку в УФ-базе по кнопке "Получить ссылку", то она будет вот такой:
e1cib/data/Справочник.Контрагенты?ref=80c574d43512a57311e5ffc8937f5c0f
Здесь тип указан строкой, а ссылка идет после "ref="
Вот код, который получает GUID из ссылки (писал очень давно и для себя :) )
Поз = Найти(СсылкаУИД, "ref=");
Если Поз=0 Тогда
Поз = Найти(СсылкаУИД, ":");
Поз = ?(Поз=0, 0, Поз+1);
Иначе
Поз = Поз+4;
КонецЕсли;
Если Поз=0 Тогда
Предупреждение("Ссылка имеет неизвестный формат");
Иначе
Стр = Сред(СсылкаУИД, Поз, 32);
УИД = Прав(Стр,8)+"-"+Сред(Стр,21,4)+"-"+Сред(Стр,17,4)+"-"+Лев(Стр,4)+"-"+Сред(Стр,5,12);
КонецЕсли;
ПоказатьОдинаковые ссылки с разными типами встречаются не так уж редко даже в одной базе.
Ссылка - это идентификатор объекта в информационной базе. Как ФИО для человека. Какой смысл выяснять, кто больше, Иванов Иван Иванович или Сидоров Сидор Сидорович?
Так же и в языке запросов, только сначала сравнивается номер таблицы.
Упорядочивание по ссылке - есть упорядочивание по бинарному представлению GUID.
1. Если надо упорядочить по моменту времени, то я использую дату + ссылку (ГУИД).
2. Если надо получить стабильный порядок ссылок, то я сделаю упорядочивание по ссылке (ГУИД).
В БСП есть механизм регламентного удаления помеченных на удаление объектов.
В обработке идет вызов стандартной функции НайтиПомеченныеНаУдаление(), которая возвращает массив ссылок.
Проход по этому массиву идет с обратным индексом, с конца к началу. Ваша функция получения времени из ссылки помогла определить как именно распределяются объекты в этом массиве по дате создания. И я пришел к выводу, что ссылки в этом массиве располагаются в последовательности прохождения по дереву метаданных, т.к. типы ссылок сгруппированы. Соответственно объекты в этом массиве разбросаны по датам создания и вот чем это плохо:
- У меня больше 50 000 помеченных на удаление объектов, большая часть из которых Ключи Аналитики Учета Номенклатуры.
При каждом запуске удаления до "свежепомеченных" объектов дело почти никогда не доходит, т.к. регламентое задание может выполняться больше недели в поисках всех ссылок на эти ключи и это ненормально
- Регламентное задание каждый раз перелопачивает одни и те же данные снова и снова, хотя заранее и так понятно, что объекты эти не будут удалены никогда, период закрыт. Некоторые объекты полуинформативные, и к сожалению заменить их тоже не чем.
В общем есть мысль пересортировать массив помеченных таким образом, чтобы объекты помеченные в последнее время удалялись первыми, а старье и объекты с программно установленным Уникальным Идентификатором без даты оказывались в конце списка.
К выбору из списка отношения не имеет, как и к теме статьи.
А описанный кейс легко решается в любой нетиповой обработке удаления, которая умеет автоматически помечать на удаление выбранные типы объектов метаданных, чтобы они не блокировали удаление, а удалялись вместе со ссылающимися на них объектами.
Неужели вы там у себя заранее держите ключи помеченными на удаление ради пользователей, которые что-то удаляют через типовую обработку удаления?
// Преобразует ГУИД из формата 1С в формат SQL
Функция ГУИДдляSQL(Строка) Экспорт
Если ПустаяСтрока(Строка) Тогда
Возврат Строка;
КонецЕсли;
Результат = "";
Строка = СтрЗаменить(СтрЗаменить(СтрЗаменить(Строка, "-",""), "{", ""), "}", "");
СтрокаПозиций = "23211917272531291315091101030507";
Для к = 0 По 15 Цикл
ИсхПозиция = Число(Сред(СтрокаПозиций, к*2+1,2));
Результат = Результат + Сред(Строка, ИсхПозиция, 2);
КонецЦикла;
Возврат Врег(Сред(Результат, 1, 8)+"-"+Сред(Результат, 9, 4)+"-"+Сред(Результат, 13, 4)+"-"+Сред(Результат, 17, 4)+"-"+Сред(Результат, 21, 12));
КонецФункции // ГУИДдляSQL() Показать// Преобразует ГУИД из формата SQL в формат 1С
Функция ГУИДдля1С(Строка) Экспорт
Если ПустаяСтрока(Строка) Тогда
Возврат Строка;
КонецЕсли;
Результат = "";
Строка = СтрЗаменить(СтрЗаменить(СтрЗаменить(Строка, "-",""), "{", ""), "}", "");
СтрокаПозиций = "25272931212317190705030111091513";
Для к = 0 По 15 Цикл
ИсхПозиция = Число(Сред(СтрокаПозиций, к*2+1,2));
Результат = Результат + Сред(Строка, ИсхПозиция, 2);
КонецЦикла;
Возврат Врег(Сред(Результат, 1, 8)+"-"+Сред(Результат, 9, 4)+"-"+Сред(Результат, 13, 4)+"-"+Сред(Результат, 17, 4)+"-"+Сред(Результат, 21, 12));
КонецФункции Показать г = Справочники.Валюты.ПолучитьСсылку();
р=ГУИДдляSQL(XMLСтрока(г));
а="80B7001517A39B3511E0F63522D8E339";
п=ГУИДдля1С(а);ИМХО, это спорно. Т.к. УИД ссылки упаковывается в бинарник, то это почти нивелирует этот эфффект. Я сам как то думал, что рандомные УИД'ы - зло для ссылок в 1С, спорил по этому поводу на форуме. Делал опыт, программно создавал несколько сот элементов справочника Номенклатура в УТ, как вручную назначая УИД ("random"), так и нет (чтобы УИД'ы брались из пула сеанса, псевдоупорядочивание).
Запускал dm_db_index_physical_stats в SQL и никакой разницы не было, индекс не фрагментировался от "рандомных" УИД'ов. Не знаю, может на миллионах записей это имеет значение.
Функция ДатаСозданияСсылки(Ссылка)
//Ссылка- любая ссылка конфигурации на документ или справочник
ГУИД = Ссылка.УникальныйИдентификатор();
Строка16 = Сред(ГУИД, 16, 3) + Сред(ГУИД, 10, 4) + Сред(ГУИД, 1, 8);
Разрядность = СтрДлина(Строка16);
ЧислоСек = 0;
Для Позиция = 1 По Разрядность Цикл
ЧислоСек = ЧислоСек + Найти("123456789abcdef",Сред(Строка16,Позиция,1))*Pow(16,Разрядность - Позиция);
КонецЦикла;
ЧислоСек = ЧислоСек / 10000000;
Возврат Дата(1582, 10, 15, 00, 00, 00) + ЧислоСек + СмещениеСтандартногоВремени() + СмещениеЛетнегоВремени();
КонецФункции ПоказатьВ 1с, есть время в миллисекундах ТекущаяУниверсальнаяДатаВМиллисекундах, никто не делал v7, не хотелось бы накосячить, в том, в чём не понимаю?
Вы можете заказать платную консультацию или разработку у автора. Будет создан приватный заказ на «Бирже заказов» для автора.
№ 635159
Создание 16.06.17 13:09
Обновление 27.08.20 09:27
Просмотры 213570
Загрузки 0
Рейтинг
665
Комментарии 84
Код открыт Да
Рубрики Механизмы платформы 1С
Кому Разработчик
Тип файла Нет файла
Платформа 1С:Предприятие 8
Конфигурация Универсальные
Операционная система Не имеет значения
Страна Не имеет значения
Отрасль Не имеет значения
Налоги Не имеет значения
Вид учета Не имеет значения
Доступ к файлу Бесплатно (free)
