SQL Server - проблема дизайна

User avatar
Strannik223
Уже с Приветом
Posts: 569
Joined: 14 Dec 2003 04:06
Location: Львов->Киев->Торонто

Post by Strannik223 »

Полностью в код не въехал, было бы неплохо еще привести определения таблиц которые учавствуют, поэтому покритикую по мелочам :mrgreen:

Code: Select all

AND   SrcTranKey IN (SELECT DISTINCT SOL.SOKey 


По моему distinct здесь излишен если не вреден. IN сам решит как ему отсеять данные и стоит ли это вообще делать.

Code: Select all

SELECT 1 FROM twlRFPickLock


Это уже придирки, но если я не ошибаюсь более распространено where exists( select *....
Оптимизатор сам разберет как это эффективней сделать.
Никакой разрухи нет. (с) Проф. Преображенский.
User avatar
Strannik223
Уже с Приветом
Posts: 569
Joined: 14 Dec 2003 04:06
Location: Львов->Киев->Торонто

Post by Strannik223 »

Ой!!! 8O

Code: Select all

 IF NOT EXISTS(SELECT 1 FROM twlRFPickLock
...
...
      BEGIN
         UPDATE    twlRFPickLock


Так у вас же действия с блокировочной таблицей не атомарны!!!
Если 2 потока ломанутся одновременно проверять блокировку и получат успешный результат то они оба залочат один и тот же ресурс.
Никакой разрухи нет. (с) Проф. Преображенский.
User avatar
katit
Уже с Приветом
Posts: 23804
Joined: 05 Jul 2003 22:34
Location: Брест -> St. Louis, MO

Post by katit »

Т.е. если завернуть последнюю часть в транзакцию то будет путем?

Так и сделаю. Уже сейчас практически нереально будет залочить.
Вообще мы прикалывались с того менеджера. Они нашу систему испытывают:
Ставит 25 человек со сканерами в колонну и говорит типа "Шагом марш!"
они дружно включают сканеры и поперли :mrgreen:
User avatar
Strannik223
Уже с Приветом
Posts: 569
Joined: 14 Dec 2003 04:06
Location: Львов->Киев->Торонто

Post by Strannik223 »

katit wrote:У меня немного по другому..
А именно - отдельная таблица хранит данные об упаковщике. Т.е. я и INSERT и UPDATE

Не понимаю смысл WITH (UPDLOCK) в вашем примере?
Или это как-то с транзакцией работает?

Думаю что моей главной проблемой было то что у меня 3 и 4 местами поменяны. Я переставил и думаю что проблема должна уйти


Я бы отдал предпочтение варианту Виктора. Он более DB way что ли.

Смысл следующий. Между проверкой или выборкой первого свободного заказа (select) и update проходит некоторое количество времени, или квантов процессора. За это время планировщик задач операционки может отдать управление другому потоку, который может выполнить те же действия проверки ресурса. Так как ни один поток еще не добрался до update, но оба уже выполнили select они оба решат что ресурс свободен и оба выполнят update. Чем это чревато понятно.

Дело в том что DB обеспечивает атомарность одного sql statement но не обеспечивает по умалчанию что последовательность statements будет атомарной. Транзакции именно для того и применяются что бы обеспечить атомарность последовательности операторов. Далее в целях улучшения производительности применяются различные уровни изоляции транзакций.
Гуглить: transaction isolation level.
Далее. Можно еще повысить производительность если вы четко знаете места потенциальных конфликтов (как в вашем случае). Можно ручками указать какие таблицы лочить и с каким уровнем изоляции. А остльные таблицы будут лочится с уровнем по умолчанием.

Смысл WITH (UPDLOCK) в том что прочитав значение - кандидат вы лочите эту строчку уже тем фактом что вы ее прочитали. И далее вы можете безопасно производить update зная что строка залочена и никто на нее уже не позарится. Эта ситуация является классикой DB и больше вариантов граболей вы найдете опять же в serialization isolation levels.
Никакой разрухи нет. (с) Проф. Преображенский.
User avatar
Strannik223
Уже с Приветом
Posts: 569
Joined: 14 Dec 2003 04:06
Location: Львов->Киев->Торонто

Post by Strannik223 »

katit wrote:Т.е. если завернуть последнюю часть в транзакцию то будет путем?

Так и сделаю. Уже сейчас практически нереально будет залочить.
Вообще мы прикалывались с того менеджера. Они нашу систему испытывают:
Ставит 25 человек со сканерами в колонну и говорит типа "Шагом марш!"
они дружно включают сканеры и поперли :mrgreen:


Это условие необходимое но недостаточное.
Надо либо ставить
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
либо ручками в select-e лочить.
Никакой разрухи нет. (с) Проф. Преображенский.
User avatar
Dmitry67
Уже с Приветом
Posts: 28294
Joined: 29 Aug 2000 09:01
Location: SPB --> Gloucester, MA, US --> SPB --> Paris

Post by Dmitry67 »

Поэтому для атомарности я и предложил делать один update в режиме set rowcount 1

'Заворачивание' if exists ... update
в транзакцию НИКАК само по себе не гарантирует атомрности
Важно поставить правильные locking Hints у select
Зарегистрированный нацпредатель, удостоверение N 19719876044787 от 22.09.2014
Victor
Уже с Приветом
Posts: 2107
Joined: 04 Mar 1999 10:01
Location: Gaithersburg, MD

Post by Victor »

Dmitry67
...Я понял что Вы хотите...
Второй вариант чем-то лучше или это просто для внесения ясности?
Там вроде минус в том, что встает задача идентификации записи с которой работаете, например в случае если упаковшику будет выдано больше одного задания и @@spid будет одинаков.

katit
Суть в связке BEGIN/END TRAN + WITH (UPDLOCK) ? Верно?
Да, верно
Просто я здесь не использую транзакцию.
Это вы напрасно :)

Return to “Вопросы и новости IT”