Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Искусственная уникальность в . [MSSQL]


Александр Спелицин ©   (2002-09-10 18:59:00) 

Здравствуйте.
Ситуация с искусственной уникальностью в MSSQL.
Есть таблица: document (doc_id int identity, doc_type int, doc_number int, department_id int, year int, ...).
Номер документа (doc_number) должен быть уникален в пределах заданного отдела (department_id), данного типа (doc_type) и указанного года. Механизм - автоинкремент: максимум + 1.
Т.е. добавление нового документа происходит так:

create procdure CreateFirstTypeDocument @department_id int, @year int, ... какие-то параметры...
as
begin
Declare @doc_nb int
Begin Transaction

-- Точка A

Select @doc_nb = max (doc_number) + 1
From document
Where department_id = @department_id
and year = @year
and doc_type = 1
if @doc_nb Is Null
Select @doc_nb = 1

-- Точка B

Insert document (doc_type, doc_number, department_id, year, ...)
Values (1, @doc_nb, @department_id, @year, ...)

-- Точка C

...
Commit Transaction
end


В таблице одна запись, у которой doc_number = 1. Сервер сильно загружен. Процедуры выполняются медленно.
Теперь из двух сессий одновременно вызывается CreateFirstTypeDocument.
В точке B у для каждой сессии значение @doc_nb будет равно 2. Первая сессия добавляет запись нормально, а вторая своей вставкой нарушает уникальность номеров.

Как обеспечить уникальность?

Заранее спасибо.


doomin   (2002-09-11 10:59:00) [1]

Если для каждого типа и департамента должна быть своя нумерация, то тут без отдельной таблицы с номерами не обойтись, все равно нужно сбрасывать вначале года. Там и сбрасывать. И написать процедуру, которой передается тип и отдел, а она возвращает новый номер (читает из таблицы, инкрементирует и перезаписывает в рамках транзакции). На время работы процедуры (это будет недолго, так как табличка маленькая) лочить табличку для всех. Если другая сессия не смогла получить из-за лока номер, то возвращать -1 например и в основной процедуре вставки документа в цикле ждать номера больше 0. Мне кажется так...


Zelius   (2002-09-11 10:25:00) [2]

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


sniknik   (2002-09-11 10:19:00) [3]

Проще хранить начало счетчика года, индетификатор иметь сквозной, а нумерацию делать разницей (чтобы 1 получить в начале года).


Виталий Панасенко   (2002-09-11 09:53:00) [4]

По-моему (хотя это тут и критикуют :-))) лучше хранить ИД в отдельной таблице. При этом брать оттуда значение и его же увеличивать на 1. Т.к. начата транзакция, все остальные будут ждать ее окончания и только тогда смогут обновить данные.


Александр Спелицин   (2002-09-10 20:59:00) [5]

2 wicked:
В том то и дело, что нужен. У каждого подразделения своя нумерация документов. Кроме того, с нового года нумерация вновь начинается с 1.


wicked   (2002-09-10 20:49:00) [6]

если коротко, то код от точки а до точки b просто не нужен...
если тебе нужен id только что вставленной записи, используй системную переменную @@identity...


Наверх

Титульная страница Поиск, карта сайта Написать письмо