Почему один оператор удаления SQL приведет к тупику? - PullRequest
1 голос
/ 05 июня 2010

Я использую SQL Server 2008 Enterprise. Мне интересно, почему даже один оператор удаления этой хранимой процедуры вызовет взаимоблокировку, если выполняется несколькими потоками одновременно?

Для оператора delete Param1 - это столбец таблицы FooTable, Param1 - это внешний ключ другой таблицы (относится к другому столбцу кластерного индекса первичного ключа другой таблицы). Для самой таблицы Param1 нет индекса для таблицы FooTable. FooTable имеет другой столбец, который используется в качестве кластерного первичного ключа, но не столбец Param1.

create PROCEDURE [dbo].[FooProc]    
(  
 @Param1 int 
 ,@Param2 int  
 ,@Param3 int  
)    
AS    

DELETE FooTable WHERE  Param1 = @Param1     

INSERT INTO FooTable    
 (  
 Param1  
 ,Param2  
 ,Param3  
  )    
 VALUES    
 (  
 @Param1  
 ,@Param2  
 ,@Param3  
  )    

DECLARE @ID bigint    
 SET @ID = ISNULL(@@Identity,-1)    
 IF @ID > 0    
 BEGIN    
      SELECT IdentityStr FROM FooTable WHERE ID = @ID 
 END  

спасибо заранее, George

Ответы [ 3 ]

2 голосов
/ 05 июня 2010

У меня нет опыта работы с параллелизмом, но в вашей процедуре есть две вещи, которые я бы изменил (и, возможно, исправил бы ваш тупик):

  • Оберните всю процедуру в транзакцию. Это сделано для предотвращения вызова сценария, подобного FooProc 1 и собирается выполнить оператор SELECT, в то время как FooProc 2 только что выполнил оператор DELETE, имеющий оба одинаковых @ Param1.
  • Не используйте @@ Identity, вместо этого используйте SCOPE_IDENTITY.

Интересная ссылка о @@ Identity vs SCOPE_IDENTITY () против IDENT_CURRENT ()

1 голос
/ 05 июня 2010

Обычный ответ: это зависит! : -)

В основном о том, сколько трафика у вас в вашей системе, и какой уровень изоляции транзакций вы используете.

Уровень изоляции контролирует, как вы получаете ваши данные, и сколько происходит блокировка. Если вы никогда не слышали об уровнях изоляции транзакций, вы, вероятно, используете значение по умолчанию - READ COMMITTED, что не должно быть слишком плохим выбором.

Однако, если по каким-либо причинам вы используете что-то вроде SERIALIZABLE, вы можете столкнуться не с тупиками, а с задержками. Таблица может быть заблокирована на некоторое время, пока ваша транзакция не будет завершена. Если все операции работают в этом порядке (сначала удалите, затем вставьте, а затем выберите), я не вижу, как на самом деле вы должны встретить какие-либо тупики.

Ознакомьтесь с уровнями изоляции транзакций SQL здесь на www.sql-server-performance.com .

0 голосов
/ 18 мая 2014

Если у большой таблицы BarTable есть ограничение внешнего ключа, ссылающееся на FooTable, то удаление одной отдельной строки в FooTable должно проверять все строки BarTables на наличие ссылок на эту строку.

Мало того, что это слишком медленно, но и усугубляется: при выполнении этой проверки два одновременных удаления двух отдельных строк в FooTable могут заблокироваться на первичном ключе BarTable (!)

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

Итак:

Убедитесь, что ограничения внешнего ключа поддерживаются индексами.

...