Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Господа, может что посоветуете. Есть ПО работающее с SQL базой, причем очень активно (постоянные обновлени таблиц с 70 тыс записями), ПО работает через BDE и ODBC. Первоначально были блокировки - постоянные, причем даже на два запроса SELECT ! Затем программеры не долго думая поставили в запросы UPDATE TABLOCKX, что все замедлило, но тогда решили и так пойдет, теперь они добавили новые функции очень ресурсоемкие и время ответа на запрос резко возросло, средний запрос 30-50 сек !!! Сервер не плохой, RAID контроллер, необходимые индексы есть... можно ли еще что "подкрутить" в настройках SQL или это все же ПО кривое, а может все дело в BDE? Спасибо всем ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.02.2002, 12:55 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Не думаю, что дело в BDE или в настройках SQL Serverа (раз раньше всё работало нормально). Нельзя также сказать нужна там или нет эта монопольная(эксклюзивная) блокировка, но то что она всё "тормозит" - это 100% А что говорят сами разработчики по поводу "улучшения" производительности? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.02.2002, 13:42 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Похоже, мало, что можно сделать. Так уж написано приложение. Так как используются громадные транзакции, то должно полегчать, если файл журнала транзакций вынести на отдельный физический диск (лучше зеркало, RAID для него не нужен). Также можно существенно облегчить ситуацию (щас меня ChA запинает за такое предложение ), если переорганизовать работу таким образом: изменения производить в одной базе, а читать из другой. Между ними, есно, периодическая синхронизация. Если у вас размер страйпа на raid-массиве 4-8кб, то увеличив этот размер до 64кб, производительность может увеличиться на порядок (а может и не увеличиться совсем в вашей конкретной ситуации) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.02.2002, 13:50 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Все некритичные SELECT переписал WITH(NOLOCK), а все INSERT, UPDATE WITH(ROWLOCK). Проблему deadlock сняло. Ещё использую вот такой код: unit mtoADOSupport; interface uses Classes, ADODB; type (* * These components based on Tolik Tentser code pie (tt@katren.ru) * This code fixes multithreading deadlock issue. *) TttADOQuery = class(TADOQuery) protected procedure InternalOpen; override; public constructor Create(AOwner: TComponent); override; end; TttADODataSet = class(TADODataSet) protected procedure InternalOpen; override; public constructor Create(AOwner: TComponent); override; end; implementation uses SysUtils; { TttADOQuery } constructor TttADOQuery.Create(AOwner: TComponent); begin inherited Create(AOwner); end; procedure TttADOQuery.InternalOpen; var I, Attempt: Integer; DeadLock: Boolean; Err: Errors; begin Attempt := 0; while TRUE do begin try inherited; except on E: Exception do begin DeadLock := FALSE; Err := Connection.Errors; for I := Err.Count-1 downto 0 do // Åñëè îøèáêà 1205 - Deadlock - ïîâòîðÿåì îïåðàöèþ if Err .NativeError = 1205 then begin DeadLock := TRUE; Inc(Attempt); Break; end; if DeadLock and (Attempt < 3) then Continue else raise; end; end; Break; end; end; { TttADODataSet } constructor TttADODataSet.Create(AOwner: TComponent); begin inherited Create(AOwner); end; procedure TttADODataSet.InternalOpen; var I, Attempt: Integer; DeadLock: Boolean; Err: Errors; begin Attempt := 0; while TRUE do begin try inherited; except on E: Exception do begin DeadLock := FALSE; Err := Connection.Errors; for I := Err.Count-1 downto 0 do // Åñëè îøèáêà 1205 - Deadlock - ïîâòîðÿåì îïåðàöèþ if Err.NativeError = 1205 then begin DeadLock := TRUE; Inc(Attempt); Break; end; if DeadLock and (Attempt < 3) then Continue else raise; end; end; Break; end; end; end. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.02.2002, 15:31 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Естественно, всё вышесказанное следуюет применять вкупе с иными техниками. Так, практически все вставки и обновления бизнес-объектов у меня работают через хранимые процедуры. Соответственно, минимизировано количество триггеров. Также надо с умом пользоваться ограничениями (constraints). а блокировки типа tablock - практически смертельно для рабочего oltp-сервера. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.02.2002, 15:48 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Как я понимаю, проблема проистекает от не очень удачного применения не очень удачного метода разрешения дедлоков. Когда объектов очень много, скрипты сложные, вероятность дедлоков возрастает. Происходят дедлоки обычно потому, что: а) Транзакции блокируют ресурсы не одномоментно, а последовательно б) Последовательность блокировок ресурсов в разных транзакциях может привести к блокировке разных ресурсов одновременно несколькими транзакциями и запроса блокировки ресурсов, занятых другими транзакциями, которые в свою очередь запрашивают ресурсы, уже заблокированные в первой транзакции. Дедлок - это замкнутый круг, бороться с которым можно двумя способами: 1. Откатить одну из транзакций, вошедшую в этот замкнутый круг (что принудительно и делает встроенная в SQL сервер искалка дедлоков). 2. Не допустить замыкания круга и исключить саму вероятность выполнения последовательности блокировок в разных транзакциях, которые могут приветси к взаимным блокировкам. Способ 1 мало кому нравится по двум причинам. Во-первых, дедлок обнаруживается обычно не сразу. На его выявления может уйти довольно много времени. Все это время некоторая часть пользователей будет с недоумением смотреть на ваше приложение, впавшее в глубюокую задумчивость. Во-вторых, когда дедлок наконец будет выявлен, кто-то из юзеров получит соответствующее сообщение об ошибке, и будет пребывать в состоянии растерянности. С точки зрения его, юзверной логики, он не придпринял никаких предосудительных действий, и периодическое возникновение ошибки буквально на голом месте, да еще такой, с которой невозможно бороться никакими средствами, весьма сильно раздражает. Обычно разработчики выбирают способ 2 (и правильно делают). Однако, этот способ в свою очередь разбивается на два диаметрально противоположных решения, каждое из которых имеет свои положительные стороны и отрицательные: Решение 1. Заблокировать все что нужно и все что не нужно в самом начале транзакции, а потом предпринимать какие-то последовательные алгоритмические шевеления внутри транзакции уже на полностью заблокированных транзакцией ресурсах. Именно по этому пути пошли ваши разработчики. Плюсы данного решения: а) высокая степень изолированности транзакций позволяет гарантированно избежать побочных эффектов (вроде "грязного чтения"); б) простота реализации. Минусы: высокая конкуренция транзакций приводит к большим временным задержкам, потому что транзакции вынуждены ждать освобождения всех ресурсов, выстаивая в "очереди транзакций". Решение 2. Попытаться свести к минимуму блокировки. Это решение предлагает Аджан Абдулин (и мне оно тоже больше по душе). Плюсы этого решения - возможность одновременного выполнения нескольких транзакций приводит к устранению циклов ожидания в "очереди транзакций", что положительно сказывается на быстродействии. Минусы: а) требуется тщательное продумывание всех скриптов (сложность реализации, что может приводить к ошибкам); б) возможность проявления побочных эффектов вроде "грязного чтения" на некоторых комбинациях одновременно выполняемых транзакций из-за низкого уровня изолированности транзакций. Самый грамотный и одновременно самый трудный путь - это решение 2. Если Вам удастся уговорить ваших разработчиков по нему пойти, значит Вы родились под счастливой звездой. Базовые приемы названы Аджаном Абдулиным. По возможности во всех операциях SELECT, выполняемых по постоянным таблицам, во фразу FROM необходимо добавить хинт with (NoLock). При каждом добавлении этого хинта нужно помнить о том, что его использование может привести к "грязному чтению", и тщательно продумывать возможные влияния на другие транзакции. Во все фразы Insert, Update и Delete лучше всего поставить хинт With (RowLock). Эти операции неизбежно приводят к блокировкам, и наша задача избежать эсклации блокировок, которая может привести к дедлоку (обычно это происходит при повышении статуса блокировки до уровня страничной или табличной, что потенциально может привести к блокировке записей, расположенных по соседству с теми, над которыми выполняется операция - если другая транзакция в это время пытается получить к ним доступ, возникает опасность дедлока). Однако, следует помнить, что данный хинт можно использовать только в том случае, когда вы уверены, что эти операции всегда будут выполняться над небольшим числом записей. Если операции Insert, Update и Delete могут выполняться над большим массивом записей (сотни и тысячи), этот хинт использовать нельзя. При массовых операциях модификации записей с указанным хинтом на каждую модифицируемую запись будет занят отдельный ресурс, называемый "блокировка". Количество таких объектов при достижении критически больших величин может привести к исчерпанию ресурсов памяти SQL-сервера. Следует помнить, что даже повсеместное использование указанных хинтов не приводит гарантированно к устранению опасности возникновения дедлоков. Особое внимание следует обратить на последовательность выдачи команд UPDATE и DELETE по разным таблицам в разных скриптах. Если большая часть скриптов оперирует сразу множеством таблиц, желательно во всех скриптах придерживаться одной и той же последовательности модификации данных по нескольким таблицам. Следует учесть, что указание табличных хинтов во фразе FROM имеет смысл только для тех таблиц, которые существуют на момент создания скрипта. Хинты по временным таблицам и таблицам Inserted и Deleted в триггерах будут проигнорированы (см. BOL). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.02.2002, 16:50 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Спасибо всем за участие. Разработчики считают что просто необходимо что-то включить в SQL сервере и сразу все заработает... Но самое интересное, что все началось не так давно, и до этого нареканий не было... так что поиски продолжаются. Кстати, не в курсе, нельзя ли в SQL сервре задать единый способ обработки запросов, чтобы select всегда выполнялся как select with (nolock) и т.д.? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.02.2002, 14:15 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Если сохранилась связь с разработчиками, можно попросить их вставить в программы команды SET LOCK_TIMEOUT А ещё лучше не жёстко зашить timeout в программе, а вынести его во внешние настройки программы, чтобы пользователь мог сам изменять это значение без участия разработчика. Тогда по крайней мере будет понятно, висят программы из-за того, что ожидают освобождения заблокированного ресурса, или из-за чего-то другого. А блокировка всей таблицы в командах UPDATE - это просто хулиганство. Кто и какие проблемы надеялся это решить - непонятно. В многопользовательских базах данных это не решает проблемы, а только их порождает. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.02.2002, 16:12 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
select with(nolock) - это контролируется вызовом set transaction isolation level dirty read. но на самом деле правильнее по умолчанию использовать read committed, и проставлять with(nolock) где нужно. кстати, для массивных обновлений и вставок удобно правильно выставить PAGLOCK или даже TABLOCK. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.02.2002, 16:57 |
|
||
|
Ох уж эти блокировки
|
|||
|---|---|---|---|
|
#18+
Господа, у меня сразу еще один вопрос, теоретический Существует ли возможность переопределения стандартыных (родных) Update, Insert и пр.? Спасибо, за советы, сервер стал устойчивей и расторопнее ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 15.02.2002, 08:10 |
|
||
|
|

start [/forum/topic.php?fid=46&gotonew=1&tid=1823892]: |
0ms |
get settings: |
8ms |
get forum list: |
18ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
38ms |
get topic data: |
11ms |
get first new msg: |
7ms |
get forum data: |
3ms |
get page messages: |
55ms |
get tp. blocked users: |
1ms |
| others: | 234ms |
| total: | 383ms |

| 0 / 0 |
