Как сформировать уникальный идентификатор для нескольких потоков и сессий
От: .alex Ниоткуда  
Дата: 16.02.23 14:42
Оценка:
Добрый день.

Подскажите какие есть практики для формирования УИД при добавлении записей в БД одновременно из нескольких независимых потоков ну и в несколько сессий «заливки».
Постараюсь объяснить подробнее.
Есть, например, 100 xml файлов, моя программа читает их, например, одновременно в 10 потоков (1 поток – 1 файл) и соответственно каждый поток делает bulkinsert в общую таблицу в БД.
И нужно сделать УИД для каждой записи в формате bigint (составной УИД не подходит, т.к. в последствии этот УИД будет использоваться для построения полнотекстового индекса по данной таблице).

Я делал так: из 8 байт bigint я использовал 5 младших байт, как счетчик текущей записи в текущем файле (в одном файле записей может быть больше 2^32 но меньше 2^40),
а в 3 старших засовывал crc32, посчитанную по строке, которая состоит из имени файла + переведенный в строку размер фала (это на случай не уникальности имен файлов, комбинация имя + размер – уникально),
ну и из-за того, что у меня всего 3 байта для crc32 я два оставлял как есть а для 3 и 4 делал xor и добавлял в оставшийся байт bigint.

В принципе все работало, но если в загрузке участвует несколько тысяч файлов, то моей доморощенной crc32 стало не хватать, появились коллизии…
Так вот собственно вопрос, что можно придумать, притом без хранения информации о предыдущей сессии?
Если бы не было несколько сессий «заливки», то понятно перед заливкой каждому потоку даем свой ИД и льем, но как быть в второй и последующих сессиях заливки, от чего отталкиваться, время я тоже не придумал, как засунуть в 3 байта…
Re: Как сформировать уникальный идентификатор для нескольких потоков и сессий
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 16.02.23 14:51
Оценка: +1
Здравствуйте, .alex, Вы писали:

A>Есть, например, 100 xml файлов, моя программа читает их, например, одновременно в 10 потоков (1 поток – 1 файл) и соответственно каждый поток делает bulkinsert в общую таблицу в БД.

A>И нужно сделать УИД для каждой записи в формате bigint (составной УИД не подходит, т.к. в последствии этот УИД будет использоваться для построения полнотекстового индекса по данной таблице).
Автоинкремент? Или вы забыли упомянуть, что по этому ключу нужно найти нужный элемент в файле?
Делайте составной, потом добавляйте stored вычисляемую колонку и делайте по ней индекс.
Re: Как сформировать уникальный идентификатор для нескольких потоков и сессий
От: vmpire Россия  
Дата: 16.02.23 14:58
Оценка:
Здравствуйте, .alex, Вы писали:

A>Подскажите какие есть практики для формирования УИД при добавлении записей в БД одновременно из нескольких независимых потоков ну и в несколько сессий «заливки».

Использовать sequence предоставляемый базой?
При отсутствии можно эмулировать через автоинкремент.
Re: Как сформировать уникальный идентификатор для нескольких потоков и сессий
От: gyraboo  
Дата: 16.02.23 15:24
Оценка:
Здравствуйте, .alex, Вы писали:

A>В принципе все работало, но если в загрузке участвует несколько тысяч файлов, то моей доморощенной crc32 стало не хватать, появились коллизии…

A>Так вот собственно вопрос, что можно придумать, притом без хранения информации о предыдущей сессии?

Guid какой-нибудь последней версии, v4, он статистически исключает коллизии и не зависит от сессии или состояния. Поэтому его используют в распределенных системах для генерации ID сущностей.
Re: Как сформировать уникальный идентификатор для нескольких потоков и сессий
От: .alex Ниоткуда  
Дата: 16.02.23 15:37
Оценка:
Да, забыл упомянуть БД — MSSQL

Здравствуйте, gandjustas, Вы писали:
G>Автоинкремент? Или вы забыли упомянуть, что по этому ключу нужно найти нужный элемент в файле?
Автоинкремент имеете ввиду IDENTITY? Если да, то пробовал, не подходит — скорость загрузки падает на порядки (даже не в разы)...
G>Делайте составной, потом добавляйте stored вычисляемую колонку и делайте по ней индекс.
А можете пример для MSSQL привести, что-то не понял как это...

Здравствуйте, vmpire, Вы писали:
V>Использовать sequence предоставляемый базой?
Попробую, а пример небольшой можно?
V>При отсутствии можно эмулировать через автоинкремент.
Уже писал — не подходит из-за снижения скорости...

Здравствуйте, gyraboo, Вы писали:
G>Guid какой-нибудь последней версии, v4, он статистически исключает коллизии и не зависит от сессии или состояния. Поэтому его используют в распределенных системах для генерации ID сущностей.
Получается его нужно будет для каждой записи генерировать? Думаю будет значительная просадка в скорости импорта... А если один раз для потока, то не понятно как его в 3 байта засунуть...
Re: Как сформировать уникальный идентификатор для нескольких потоков и сессий
От: BlackEric http://black-eric.lj.ru
Дата: 16.02.23 15:50
Оценка:
Здравствуйте, .alex, Вы писали:

newId(), а из него уже можно брать часть данных для biginta потом, после вставки
https://github.com/BlackEric001
Re[2]: Как сформировать уникальный идентификатор для нескольких потоков и сессий
От: vmpire Россия  
Дата: 16.02.23 15:53
Оценка: 80 (1) +1
Здравствуйте, .alex, Вы писали:

V>>Использовать sequence предоставляемый базой?

A>Попробую, а пример небольшой можно?
https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2012/ff878058(v=sql.110)
Для Вашего случая имеет смысл получать номера пачками, например, с помощью sp_sequence_get_range

V>>При отсутствии можно эмулировать через автоинкремент.

A>Уже писал — не подходит из-за снижения скорости...
Если в лоб, то да. Но можно попробовать делать вставку для получения ID сразу пакетами.
Или получать ID сразу для пакета значений, например из 100 штук, а внутри неё уже нумеровать самостоятельно.
Re[2]: Как сформировать уникальный идентификатор для нескольких потоков и сессий
От: m2user  
Дата: 16.02.23 20:12
Оценка:
A>Автоинкремент имеете ввиду IDENTITY? Если да, то пробовал, не подходит — скорость загрузки падает на порядки (даже не в разы)...

Вот это странно.
Здесь не может быть эта проблема?
https://learn.microsoft.com/en-US/troubleshoot/sql/database-engine/performance/resolve-pagelatch-ex-contention

The most common scenario is a clustered primary key on an Identity column. Less frequently, this issue can be observed for nonclustered indexes.

 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.