тупик на одной таблице SQL Server - PullRequest
3 голосов
/ 19 июня 2010

Я использую SQL Server 2008 Enterprise.И используя ADO.Net + C # + .Net 3.5 + ASP.Net в качестве клиента для доступа к базе данных.Когда я обращаюсь к таблицам SQL Server 2008, я всегда вызываю хранимую процедуру из своего кода C # + ADO.Net.

У меня есть 3 операции над таблицей FooTable.И множественные соединения будут выполнять их одновременно в последовательностях, то есть выполняет удаление, выполнение вставки и затем выполнение выбора. Каждый оператор (удаление / вставка / выбор) представляет собой отдельную отдельную транзакцию в процедуре единого хранилища.

Мой вопрос заключается в том, возможно ли возникновение тупика в операторе удаления? Я полагаю, возможно ли возникновение взаимоблокировки, если несколько подключений работают с одним и тем же значением Param1?

Кстати: для приведенных ниже инструкций 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

Вот как выглядит таблица монитора активности:

ProcessID System Process Login Database Status Opened transaction Command Application Wait Time Wait Type CPU 
52 No   Foo suspended 0 DELETE .Net SqlClient Data Provider 4882 LCK_M_U 0 
53 No George Foo suspended 2 DELETE .Net SqlClient Data Provider 12332 LCK_M_U 0 
54 No George Foo suspended 2 DELETE .Net SqlClient Data Provider 6505 LCK_M_U 0 
(a lot of rows like the row for process ID 54)  

Ответы [ 2 ]

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

Я бы добавил индекс на Param1 в FooTable; без него DELETE выполняет полное сканирование таблицы, и это создает проблемы с тупиками.

EDIT

Судя по деталям вашей активности, не похоже, что у вас есть взаимоблокировки, у вас есть блокировки, много удалений стоят в очереди, пока происходит одно удаление. Опять же, индексация на Param1 облегчила бы это, без этого каждое удаление будет выполнять полное сканирование таблицы, чтобы найти записи для удаления, в то время как это происходит, другие удаления должны ждать. Если у вас есть индекс для Param1, он будет обрабатываться намного быстрее, и вы не увидите блокировку, которой вы сейчас являетесь.

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

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

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

Два одновременных вызова процедуры выполняются со значением Param1, равным 5, оба удаляются, а затем оба вставляют, поэтому теперь у вас есть две записи со значением Param1, равным 5. В зависимости от ваших требований к согласованности данных это может или не может быть проблемой вы.

Альтернативой для вас может быть фактическое выполнение обновления, и, если строки не затрагиваются (check @@ rowcount), тогда, конечно, выполните вставку всех в транзакцию. Или еще лучше, взгляните на Слияние , чтобы выполнить операцию вставки / обновления в одном операторе.

...