Work: Сказка про ID generation

Work Add comments

Жили были item-ы и было у них sequential numeric id.

То, что оно sequential - это тяжелое наследие царского режима, потом пришли большевики, но ничего сделать было уже нельзя.

#0

И вот, при Николае-батюшке, было это autoincrement поле в MS SQL, item-ы получали id при вставке и никто горя не знал. Очевидно для того, что бы узнать это id на клиенте надо вставлять item-ы один за другим.

#1

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

#2

Нагрузка возросла - сделали вставку item-ов сразу пачками, а генерацию соответсвенно тоже поменяли, что бы генерировать сразу на всю пачку за один запрос. Стандартная hi-lo процедура (см ниже). Скажем, если вставляется 10 записей - один запрос на генерацию 10 ids.

#3

Нагрузка возросла - сделали пре-генерацию id наперёд блоками и кеширование этого блока на клиенте. Скажем, если вставляется 10 записей - один запрос на генерацию 1000 ids. 10 используются сразу, а 990 ждут следующего раза.

При порядка 700 витках (threads), которые всё время пишут в базу, эффект поразительный.

Average wait time

А вот если бы сесть и подумать, можно было бы сразу с последнего пункта начать…

hi-lo cхема выглядит так:

Таблица в БД

CREATE TABLE IDTable(
TableName varchar(255) NOT NULL,
NextID bigint NOT NULL,
CONSTRAINT IDTable1_PK PRIMARY KEY CLUSTERED( TableName ASC)

SQL запрос на генерацию примерно так

DECLARE @LocalTempTable  table(id int)
DECLARE @NEXTID INT
DECLARE @CNT INT

BEGIN TRAN
SELECT @NEXTID = (SELECT NextID FROM IDTable WITH (UPDLOCK) WHERE TableName = @@TABLENAME)
SET @CNT = 0
WHILE(@CNT < @@COUNT)
BEGIN
INSERT INTO @LocalTempTable(id) VALUES(@NEXTID + @CNT)
SET @CNT = @CNT + 1
END
UPDATE IDTable WITH (UPDLOCK) SET NextID = @NEXTID+@CNT WHERE TableName = @@TABLENAME
COMMIT
SELECT id FROM @LocalTempTable

Где TABLENAME это имя последовательности, а COUNT это размер пачки.

Самый интересный фокус тут это SELECT … WITH (UPDLOCK). Клиенты делают запросы указывая размер пачки, а потом либо тратят ее всё как в случае #2 либо кешируют часть про запас, как в случае #3.

Некоторые размер пачки хранят прямо в таблице, отсюда и название. У этого подхода есть одно достоинство - можно централизованно управлять сколько ID создать. Но это же одновременно и недостаток - часто нужно здесь создать1000 штук, а тут только 10.

Вот тут есть не плохой обзор доступных способов получения ID

Похожие записи:

Leave a Reply

Entries RSS Comments RSS Log in Admin