Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Одновременные запросы к БД  [new]
kingPin
Member

Откуда:
Сообщений: 6
При обращении к БД (SQL Server 2005) с клиентов (Турбо Бухгалтер 6.9) с разницей в 10-100мс не действуют блокировки. Или по крайней мере не успевают срабатывать. Вот кусок скрипта:

INSERT INTO [SHARED04]..[TEMP]
with (XLOCK, TABLOCK) (CreateTime,Ukey,Номер)

select GetDate(),
isnull((select top 1 Ukey from [SHARED04]..[TEMP] order by Ukey DESC),0)+1,
isnull((select top 1 Номер from [SHARED04]..[TEMP] where Опер=4 order by Номер DESC),0)+1

Проблема со столбцом Номер. В таблице повторяются его значения при одновременном обращении к БД. Как я понял ситуацию, два или более клиента одновременно считывают селектом данные и инкрементируют на 1, а должны считывать поочереди, в итоге получаются одинаковые номера.
Ставил хинты вплоть до holdlock на селекты, ограничивал транзакцию serializable`ом, не помогло. Может посоветуете выход? (автоинкремент не подойдет)
25 май 09, 13:05    [7222514]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
Glory
Member

Откуда:
Сообщений: 104760
kingPin
При обращении к БД (SQL Server 2005) с клиентов (Турбо Бухгалтер 6.9) с разницей в 10-100мс не действуют блокировки. Или по крайней мере не успевают срабатывать. Вот кусок скрипта:

А почему хинты блокировки, указанные для INSERT INTO [SHARED04]..[TEMP], должны начать действовать для select from [SHARED04]..[TEMP] ???
25 май 09, 13:07    [7222534]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
kingPin
Member

Откуда:
Сообщений: 6
Glory
kingPin
При обращении к БД (SQL Server 2005) с клиентов (Турбо Бухгалтер 6.9) с разницей в 10-100мс не действуют блокировки. Или по крайней мере не успевают срабатывать. Вот кусок скрипта:

А почему хинты блокировки, указанные для INSERT INTO [SHARED04]..[TEMP], должны начать действовать для select from [SHARED04]..[TEMP] ???

Это начальный вариант, ставил хинты на селекты и на инсерт. В т.ч. ставил на всю транзакцию, все равно одновременно не работает=( Вот крайний случай, и все равно получается что два селекта разных запросов этой транзакции считали значения и потом только инсерты вставили.

INSERT INTO [SHARED04]..[TEMP]
with (HOLDLOCK) (CreateTime,Ukey,Номер)

select GetDate(),
isnull((select top 1 Ukey from [SHARED04]..[TEMP] with (HOLDLOCK) order by Ukey DESC),0)+1,
isnull((select top 1 Номер from [SHARED04]..[TEMP] with (HOLDLOCK) where Опер=4 order by Номер DESC),0)+1
25 май 09, 13:15    [7222591]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
Glory
Member

Откуда:
Сообщений: 104760
HOLDLOCK - это не тип блокировки. Это указание удерживать блокировку до конца транзакции
25 май 09, 13:18    [7222619]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
kingPin
Member

Откуда:
Сообщений: 6
Glory,
Как тогда можно заблокировать таблицу, чтобы только один селект смог прочитать запись, а не 2 и более единовременно? Использовать уровень serializable с holdlock`ом на селектах?
25 май 09, 13:27    [7222693]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31227
kingPin
INSERT INTO [SHARED04]..[TEMP] 
with (HOLDLOCK) (CreateTime,Ukey,Номер)

select GetDate(),
isnull((select top 1 Ukey from [SHARED04]..[TEMP] with (HOLDLOCK, UPDLOCK) order by Ukey DESC),0)+1,
isnull((select top 1 Номер from [SHARED04]..[TEMP] with (HOLDLOCK, UPDLOCK) where Опер=4 order by Номер DESC),0)+1
25 май 09, 13:37    [7222780]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
Glory
Member

Откуда:
Сообщений: 104760
kingPin
Glory,
Как тогда можно заблокировать таблицу, чтобы только один селект смог прочитать запись, а не 2 и более единовременно? Использовать уровень serializable с holdlock`ом на селектах?

Опять вы путаете тип блокировки с ее продолжительностью
serializable - это и есть holdlock, т.е. указание как долго держать блокировку
25 май 09, 13:37    [7222783]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
kingPin
Member

Откуда:
Сообщений: 6
alexeyvg,

а зачем на инсерт holdlock? holdlock на селекте не удержит блокировку до конца транзакции?
И еще, можете пояснить зачем HOLDLOCK с UPDLOCKом использовать?
25 май 09, 13:42    [7222816]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
iljy
Guest
kingPin,

озвучьте пожалуйста требования к нумерации, вынуждающие делать такие сложные вещи. а то может вместо проработки технологии чесания пяткой за ухом проще воспользоваться рукой?
25 май 09, 14:11    [7223069]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
kingPin
Member

Откуда:
Сообщений: 6
iljy,

Товары выписываются из двух супермаркетов с более 20 терминалов. "Номер" - это номер выписки товара. Он должен быть уникальным для одной выписки, но товаров в выписке может быть несколько => уникальным в таблице "Выписка" его не сделать. Случаи одновременных виписок товаров происходят примерно 3-5 раз в день, с интервалом 10-100мс.
Проблема собственно в том, что при одновременных запросах номер формируется одинаковый...
25 май 09, 14:19    [7223129]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
iljy
Guest
если на все обращения к таблице поставить хинт
with (XLOCK, TABLOCK)
- у меня все работает:
begin tran
INSERT INTO t1
with (updlock) (date, i1, i2)

select GetDate(),
isnull((select top 1 i1 from t1 with (holdlock, updlock) order by i1 DESC),0)+1,
isnull((select top 1 i2 from t1 with (holdlock, updlock) order by i2 DESC),0)+1
--commit tran
в одном окне, в другом
select top 1 i1 from t1 with (XLOCK, TABLOCK) order by i1 DESC
зависает, пока в первом не выполнить commit tran. но мне все рано не понятно зачем такие ухищрения...
25 май 09, 14:20    [7223136]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
Iljy
Guest
kingPin
iljy,

Товары выписываются из двух супермаркетов с более 20 терминалов. "Номер" - это номер выписки товара. Он должен быть уникальным для одной выписки, но товаров в выписке может быть несколько => уникальным в таблице "Выписка" его не сделать. Случаи одновременных виписок товаров происходят примерно 3-5 раз в день, с интервалом 10-100мс.
Проблема собственно в том, что при одновременных запросах номер формируется одинаковый...

существует способ симуляции именованных последовательностей из постгреса на sql. Примерно такой:
Делаем таблицу:
CREATE TABLE Number_Seq(
	id INT IDENTITY(0,1)
)
далее при необходимости получения уникального номера:
declare @UniqId int
insert into NumberSeq values default
set @UniqId = scope_identity()
delete from NumberSeq
вуаля - у нас есть уникальный номер, который можно вносить в базу. Соответственно из разных транзакций мы всегда получим разные номера.
25 май 09, 14:28    [7223206]     Ответить | Цитировать Сообщить модератору
 Re: Одновременные запросы к БД  [new]
iljy
Guest
kingPin
iljy,

Товары выписываются из двух супермаркетов с более 20 терминалов. "Номер" - это номер выписки товара. Он должен быть уникальным для одной выписки, но товаров в выписке может быть несколько => уникальным в таблице "Выписка" его не сделать. Случаи одновременных виписок товаров происходят примерно 3-5 раз в день, с интервалом 10-100мс.
Проблема собственно в том, что при одновременных запросах номер формируется одинаковый...

но вообще обычно такие вещи делаются разбиением таблицы (требования 3й нормальной формы). Т.е. делается таблица "Выписка", у которой ID оформляется как identity, и подчиненная таблица "Товары", у которой поле ID_Vypiska является внешним ключем.
25 май 09, 14:32    [7223227]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить