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

Откуда:
Сообщений: 1066
CREATE PROCEDURE SP_BARCODE_IDENTITY
@BARCODE INT OUT 
AS


	SET DATEFORMAT DMY
	
	BEGIN TRAN
		IF (SELECT MONTH(GDATE) FROM M_IDENTITY_BARCODE) <> MONTH(GETDATE())
			UPDATE M_IDENTITY_BARCODE SET @BARCODE = 100, VAL = 101, GDATE = GETDATE() WHERE ID = 1
		ELSE
			UPDATE M_IDENTITY_BARCODE SET @BARCODE = VAL, VAL = VAL + 1, GDATE = GETDATE() WHERE ID = 1
 	COMMIT TRAN
GO

процедура которую дергают куча пользователей и которая возвращает некое число...
печальная ситуация в том что попадаются ситуации когда двум разным пользователям выдается одно и тоже число..(
1 авг 11, 18:45    [11055187]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
marvel
процедура которую дергают куча пользователей и которая возвращает некое число...
печальная ситуация в том что попадаются ситуации когда двум разным пользователям выдается одно и тоже число..(
Сомневаюсь, что она возвращает некое число. Нету там селекта.
1 авг 11, 18:51    [11055214]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
marvel
Member

Откуда:
Сообщений: 1066
alexeyvg
marvel
процедура которую дергают куча пользователей и которая возвращает некое число...
печальная ситуация в том что попадаются ситуации когда двум разным пользователям выдается одно и тоже число..(
Сомневаюсь, что она возвращает некое число. Нету там селекта.



почему нет???
проверьте сами...
1 авг 11, 18:51    [11055217]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
marvel
почему нет???
проверьте сами...
А, в параметре...

А в M_IDENTITY_BARCODE много записей?

А то я смотрю проверка для любой
SELECT MONTH(GDATE) FROM M_IDENTITY_BARCODE) <> MONTH(GETDATE()

а апдэйт записи с ID = 1
1 авг 11, 19:05    [11055258]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
aleks2
Guest
Тредстартеру следует читать до просветления про sp_getapplock... и будет ему щастье в тернистом деле изобретения самопального identity.
1 авг 11, 19:21    [11055326]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
aleks2
Тредстартеру следует читать до просветления про sp_getapplock... и будет ему щастье в тернистом деле изобретения самопального identity.
Странное решение.

Это по сути не блокировка от приложения, а обычная атомарная операция. Её можно сделать либо просто одним апдэйтом, либо правильно применить блокировочные хинты (в зависимости от требований к логике).

А sp_getapplock будет затратнее минимум раз в 10, если не в 100
1 авг 11, 20:48    [11055545]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
gds
Member

Откуда: Железнодорожный
Сообщений: 1842
Блог
marvel
CREATE PROCEDURE SP_BARCODE_IDENTITY
@BARCODE INT OUT 
AS


	SET DATEFORMAT DMY
	
	BEGIN TRAN
		IF (SELECT MONTH(GDATE) FROM M_IDENTITY_BARCODE) <> MONTH(GETDATE())
			UPDATE M_IDENTITY_BARCODE SET @BARCODE = 100, VAL = 101, GDATE = GETDATE() WHERE ID = 1
		ELSE
			UPDATE M_IDENTITY_BARCODE SET @BARCODE = VAL, VAL = VAL + 1, GDATE = GETDATE() WHERE ID = 1
 	COMMIT TRAN
GO

процедура которую дергают куча пользователей и которая возвращает некое число...
печальная ситуация в том что попадаются ситуации когда двум разным пользователям выдается одно и тоже число..(


--блокируется таблица
update tb with (tablock)
set @par1 = a = a + 1
where b = 1
или
--блокируется строка
update tb with (rowlock)
set @par1 = a = a + 1
where b = 1
Попробуй.
2 авг 11, 11:33    [11057424]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
gds
Попробуй.
У него не в этом проблема.

При апдэйте блокировать не надо, там и так всё заблокировано.
2 авг 11, 11:38    [11057482]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
gds
Member

Откуда: Железнодорожный
Сообщений: 1842
Блог
alexeyvg
gds
Попробуй.
У него не в этом проблема.

При апдэйте блокировать не надо, там и так всё заблокировано.

Ну тогда топикастеру надо менять уровень транзакции.
2 авг 11, 11:43    [11057548]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
gds
alexeyvg
У него не в этом проблема.

При апдэйте блокировать не надо, там и так всё заблокировано.

Ну тогда топикастеру надо менять уровень транзакции.
Абсурд какой то.

То есть вы предлагаете включать разные опции и нажимать всякие кнопки, пока не пропадёт ошибка? :-)

Нужно для начала понять бизнес-логику (тот вопрос, который я задал по поводу записей в M_IDENTITY_BARCODE), а потом уже искать решение.

Исходя из предположений о логике могу спрогнозировать, что нужно просто 3 исходных запроса переписать в один. Кроме того, что исчезнет ошибка, будет работать в 2 раза быстрее.
2 авг 11, 11:50    [11057627]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
gds
Member

Откуда: Железнодорожный
Сообщений: 1842
Блог
alexeyvg
Абсурд какой то.

То есть вы предлагаете включать разные опции и нажимать всякие кнопки, пока не пропадёт ошибка? :-)

Нужно для начала понять бизнес-логику (тот вопрос, который я задал по поводу записей в M_IDENTITY_BARCODE), а потом уже искать решение.

Исходя из предположений о логике могу спрогнозировать, что нужно просто 3 исходных запроса переписать в один. Кроме того, что исчезнет ошибка, будет работать в 2 раза быстрее.

Исходя из кода процедуры. Двум разным пользователем может выдаваться одно и тоже число, только в случае если они оба выполнили команду селект до обновления данных одним из пользователем. Т.к. селект накладывает s блокировку, то соответственно читать они могут оба. А обновят, тот кто раньше, ну или тот у кого на это потребуется меньше операций (как решит сервер).
В идеале я просто хотел сказать что при текущих условиях серверу необходимо сначала наложить блокировку на таблицу а потом уж делать с ней все что хочется. В идеале, да, согласен надо смотреть логику и оптимизировать запрос. Возможно и переписать в один.
2 авг 11, 12:00    [11057712]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
gds
Member

Откуда: Железнодорожный
Сообщений: 1842
Блог
alexeyvg,

По существу тут даже не надо транзакцию начинать. т.к. читать можно, а при обновлении все равно блокировка накладывается.

в одном коннекте.
create table t(i int)
insert into t values (1)
go

begin tran
select * from t


а а потом на дой же бд в другом коннекте.
select * from t
2 авг 11, 12:07    [11057781]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
Shlippenbaranus
Member

Откуда:
Сообщений: 241
marvel
печальная ситуация в том что попадаются ситуации когда двум разным пользователям выдается одно и тоже число..(


gds
Двум разным пользователем может выдаваться одно и тоже число, только в случае если они оба выполнили команду селект до обновления данных одним из пользователем. Т.к. селект накладывает s блокировку, то соответственно читать они могут оба. А обновят, тот кто раньше, ну или тот у кого на это потребуется меньше операций (как решит сервер).
В идеале я просто хотел сказать что при текущих условиях серверу необходимо сначала наложить блокировку на таблицу а потом уж делать с ней все что хочется. В идеале, да, согласен надо смотреть логику и оптимизировать запрос. Возможно и переписать в один.


Думаю, тут можно обойтись без блокировки. Можно просто отказаться от select и использовать только update с клаузой output. Как нибудь так, например:
UPDATE
  M_IDENTITY_BARCODE
SET
  VAL = (CASE WHEN MONTH(GDATE)= MONTH(GETDATE()) THEN 100 ELSE VAL + 1 END), 
  GDATE = GETDATE() 
OUTPUT
  DELETED.VAL 
INTO
  @BARCODE
WHERE
  ID = 1
2 авг 11, 13:06    [11058313]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
aleks2
Guest
Робятки, вы толкете воду в ступе.

Осознайте в конструкции
UPDATE M_IDENTITY_BARCODE SET @BARCODE = VAL, VAL = VAL + 1, GDATE = GETDATE() WHERE ID = 1
шоб выполнить SET @BARCODE = VAL таблицу иль запись блокировать не нада. Сервер, ее и не блокирует.

ЗЫ. Атомарность инструкции MS SQL - это тока светлая мечта.

ЗЗЫ. Ну нафег это мучение? IDENTITY rulezzzzzzzzzzzzzzzzzzz.
2 авг 11, 13:10    [11058344]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
Shlippenbaranus
Member

Откуда:
Сообщений: 241
aleks2
Робятки, вы толкете воду в ступе.

Осознайте в конструкции
UPDATE M_IDENTITY_BARCODE SET @BARCODE = VAL, VAL = VAL + 1, GDATE = GETDATE() WHERE ID = 1
шоб выполнить SET @BARCODE = VAL таблицу иль запись блокировать не нада. Сервер, ее и не блокирует.


А чтобы выполнить VAL = VAL + 1? Запись блокируется, это факт. А @BARCODE можно выкинуть вообще. Не в нем тут суть.

Поправка к моему предыдущему варианту:
UPDATE
  M_IDENTITY_BARCODE
SET
  VAL = (CASE WHEN MONTH(GDATE)= MONTH(GETDATE()) THEN 101 ELSE VAL + 1 END), 
  GDATE = GETDATE() 
OUTPUT
  INSERTED.VAL-1
WHERE
  ID = 1
- и процедура тут не обязательна. Можно вызывать только этот update. Если окружение сумеет принять результат.
2 авг 11, 13:16    [11058386]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
Shlippenbaranus
А чтобы выполнить VAL = VAL + 1? Запись блокируется, это факт. А @BARCODE можно выкинуть вообще. Не в нем тут суть.

Поправка к моему предыдущему варианту:
UPDATE
  M_IDENTITY_BARCODE
SET
  VAL = (CASE WHEN MONTH(GDATE)= MONTH(GETDATE()) THEN 101 ELSE VAL + 1 END), 
  GDATE = GETDATE() 
OUTPUT
  INSERTED.VAL-1
WHERE
  ID = 1
- и процедура тут не обязательна. Можно вызывать только этот update. Если окружение сумеет принять результат.
Я такое хотел предложить, но это может быть неправильно, ТС же так и не рассказал, что ему надо.

Дело в том, что у вас логика зависит от поля GDATE обновляемой записи, а у ТС другой записи.

А так правильно, даже можно и без OUTPUT сделать.
2 авг 11, 14:35    [11059031]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
Shlippenbaranus
и процедура тут не обязательна
Ага, и когда возникнет такой вопрос, можно будет бвстренько поменять код в 1000 местах :-)
2 авг 11, 14:36    [11059043]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
Shlippenbaranus
Member

Откуда:
Сообщений: 241
alexeyvg
Я такое хотел предложить, но это может быть неправильно, ТС же так и не рассказал, что ему надо.

Дело в том, что у вас логика зависит от поля GDATE обновляемой записи, а у ТС другой записи.


Как Вам сказать, если ТС написал
IF (SELECT MONTH(GDATE) FROM M_IDENTITY_BARCODE) <> MONTH(GETDATE()) ...
, то это как бы уже значит, что в M_IDENTITY_BARCODE у него только одна запись - иначе в этом месте он получит "Subquery returned more than 1 value". А тогда предложенный мной вариант должен работать, строго сказать, даже без WHERE-клаузы. Или же это значит, что пример у ТС чисто условный - а тогда и моему варианту не грех :). В общем-то, я хотел продемонстрировать принцип.

alexeyvg
А так правильно, даже можно и без OUTPUT сделать.


А как именно?
2 авг 11, 15:07    [11059324]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
Shlippenbaranus
то это как бы уже значит, что в M_IDENTITY_BARCODE у него только одна запись - иначе в этом месте он получит "Subquery returned more than 1 value"
Да, одна, но какой ID у этой записи? :-)
Shlippenbaranus
А как именно?
Как нибуть так:
UPDATE
  M_IDENTITY_BARCODE
SET
  VAL = (CASE WHEN MONTH(GDATE)= MONTH(GETDATE()) THEN 101 ELSE VAL + 1 END),
  @BARCODE = (CASE WHEN MONTH(GDATE)= MONTH(GETDATE()) THEN 100 ELSE VAL END),
  GDATE = GETDATE() 
WHERE
  ID = 1
2 авг 11, 15:15    [11059386]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
Shlippenbaranus
Member

Откуда:
Сообщений: 241
alexeyvg
Shlippenbaranus
то это как бы уже значит, что в M_IDENTITY_BARCODE у него только одна запись - иначе в этом месте он получит "Subquery returned more than 1 value"
Да, одна, но какой ID у этой записи? :-)


Э.... Да, действительно :).

alexeyvg
Shlippenbaranus
А как именно?
Как нибуть так:
UPDATE
  M_IDENTITY_BARCODE
SET
  VAL = (CASE WHEN MONTH(GDATE)= MONTH(GETDATE()) THEN 101 ELSE VAL + 1 END),
  @BARCODE = (CASE WHEN MONTH(GDATE)= MONTH(GETDATE()) THEN 100 ELSE VAL END),
  GDATE = GETDATE() 
WHERE
  ID = 1


Спасибо, работает. Хотя для меня - необычно.
2 авг 11, 15:39    [11059616]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
marvel
Member

Откуда:
Сообщений: 1066
alexeyvg
Shlippenbaranus
А чтобы выполнить VAL = VAL + 1? Запись блокируется, это факт. А @BARCODE можно выкинуть вообще. Не в нем тут суть.

Поправка к моему предыдущему варианту:
UPDATE
  M_IDENTITY_BARCODE
SET
  VAL = (CASE WHEN MONTH(GDATE)= MONTH(GETDATE()) THEN 101 ELSE VAL + 1 END), 
  GDATE = GETDATE() 
OUTPUT
  INSERTED.VAL-1
WHERE
  ID = 1
- и процедура тут не обязательна. Можно вызывать только этот update. Если окружение сумеет принять результат.
Я такое хотел предложить, но это может быть неправильно, ТС же так и не рассказал, что ему надо.

Дело в том, что у вас логика зависит от поля GDATE обновляемой записи, а у ТС другой записи.

А так правильно, даже можно и без OUTPUT сделать.



мне надо сделать так чтобы при многопользовательском режиме работы, пока данная
процедура не отработала, другой клиент не мог выполнить эту процедуру и получить такое же число штрихкода...
Да логика зависит от от поля GDATE (счетчик сбрасывается каждый меяц)
4 авг 11, 18:46    [11072981]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
marvel
Member

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

спасибо за пример, написал так:
	SET DATEFORMAT DMY	
	BEGIN TRAN
	
		UPDATE
  			M_IDENTITY_BARCODE
		SET
  			VAL = (CASE WHEN MONTH(GDATE) <> MONTH(GETDATE()) THEN 101 ELSE VAL + 1 END),
  			@BARCODE = (CASE WHEN MONTH(GDATE) <> MONTH(GETDATE()) THEN 100 ELSE VAL END),
  			GDATE = GETDATE() 
		WHERE
 		ID = 1
		
 	COMMIT TRAN

если опять будет ситуация добавлю (tablock), хотя честно очень не хотелось бы, потому что коннектов активных у нас около 20 и боюсь блокировок.
4 авг 11, 18:52    [11073000]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31987
marvel
если опять будет ситуация добавлю (tablock), хотя честно очень не хотелось бы, потому что коннектов активных у нас около 20 и боюсь блокировок.
Я думаю, можно и даже нужно не только не ставить tablock, но и убрать BEGIN TRAN - COMMIT TRAN.
4 авг 11, 19:34    [11073160]     Ответить | Цитировать Сообщить модератору
 Re: как правильно заблокировать таблицу?  [new]
marvel
Member

Откуда:
Сообщений: 1066
alexeyvg
marvel
если опять будет ситуация добавлю (tablock), хотя честно очень не хотелось бы, потому что коннектов активных у нас около 20 и боюсь блокировок.
Я думаю, можно и даже нужно не только не ставить tablock, но и убрать BEGIN TRAN - COMMIT TRAN.


почему убрать BEGIN TRAN - COMMIT TRAN?
5 авг 11, 10:17    [11074565]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить