Сколько накладных расходов "Update Check" имеет для LINQ UPDATES

У меня есть простая строка, которую я редактирую с помощью LINQ. Он содержит около 30 столбцов, включая числовую последовательность первичного ключа.

Когда UPDATE выполняется через LINQ, оператор UPDATE включает все столбцы таблицы (для проверки concurrency).

Мне интересно, насколько это неэффективно - если не negligibiel. Поскольку в первичном ключе есть индекс, я предполагаю, что столбец используется для поиска исходной строки, а затем другие поля проверяются дополнительно. Я бы не подумал, что это займет больше, чем незначительное количество времени.

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

Я знаю, что я могу установить "UpdateCheck" никогда не для всех остальных полей, но это боль.

Есть ли способ отключить 'Update Check' для одного SubmitChanges(), или мне нужно сделать это, изменив "UpdateCheck" для каждого поля.

Любые советы будут оценены.

Вот обновление SQL:

exec sp_executesql N'UPDATE [dbo].[SiteVisit]
SET [TotalTimeOnSite] = @p12, [ContentActivatedTime] = @p13
WHERE ([SiteVisitId] = @p0) AND ([SiteUserId] IS NULL) AND ([ClientGUID] = @p1) AND ([ServerGUID] IS NULL) AND ([UserGUID] = @p2) AND ([SiteId] = @p3) AND ([EntryURL] = @p4) AND ([CampaignId] = @p5) AND ([Date] = @p6) AND ([Cookie] IS NULL) AND ([UserAgent] = @p7) AND ([Platform] IS NULL) AND ([Referer] = @p8) AND ([KnownRefererId] = @p9) AND ([FlashVersion] IS NULL) AND ([SiteURL] IS NULL) AND ([Email] IS NULL) AND ([FlexSWZVersion] IS NULL) AND ([HostAddress] IS NULL) AND ([HostName] IS NULL) AND ([InitialStageSize] IS NULL) AND ([OrderId] IS NULL) AND ([ScreenResolution] IS NULL) AND ([TotalTimeOnSite] IS NULL) AND ([CumulativeVisitCount] = @p10) AND ([ContentActivatedTime] IS NULL) AND ([ContentCompleteTime] IS NULL) AND ([MasterVersion] = @p11) AND ([VisitedHome] IS NULL) AND ([VisitedStore] IS NULL) AND ([VisitedVideoDemos] IS NULL) AND ([VisitedProducts] IS NULL) AND ([VisitedAdvantages] IS NULL) AND ([VisitedGallery] IS NULL) AND ([VisitedTestimonials] IS NULL) AND ([VisitedEvolution] IS NULL) AND ([VisitedFAQ] IS NULL)',N'@p0 int,@p1 uniqueidentifier,@p2 uniqueidentifier,@p3 int,@p4 varchar(46),@p5 varchar(3),@p6 datetime,@p7 varchar(164),@p8 varchar(36),@p9 int,@p10 int,@p11 int,@p12 int,@p13 int',@p0=1009772,@p1='039A0614-31EE-4DD9-9E1A-8A0F947E1719',@p2='C83C0E68-142A-47CB-B7F9-BAF462E79429',@p3=1,@p4='http://www.example.com/default.aspx?c=183',@p5='183',@p6='2008-11-30 18:22:59:047',@p7='Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SIMBAR={85B62341-3F6B-4645-A473-53A2D2BB66DC}; FunWebProducts; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727)',@p8='http://apps.facebook.com/inthemafia/',@p9=1,@p10=1,@p11=30,@p12=6,@p13=6

Ответ 1

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

Длительное время выполнения, скорее всего, вызвано чем-то другим. Блокировка - хороший кандидат. Если вы можете воспроизвести его, используйте SQL Profiler, чтобы узнать, что происходит.

Ответ 2

Мы столкнулись с этим в начале. Каждое обновление LINQ to SQL проверяет, что базовые поля не изменились перед записью обновления. Другими словами, каждое обновление "обновляет запись только в том случае, если это поле равно, и это поле равно, и это поле равно"..

Мы решили, что большую часть времени нам не нравились пессимистические обновления, и единственным полем, которое необходимо проверить, является поле Id.

Итак, что мы сделали, было установлено UpdateCheck="never" для каждого поля, кроме Id в файле сопоставления dbml, например:

<Type Name="Badge">
  <Column Name="Id" Type="System.Int32" DbType="Int NOT NULL IDENTITY"
      IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
  <Column Name="Class" Type="System.Byte" DbType="TinyInt NOT NULL"
      CanBeNull="false" UpdateCheck="Never" />
  <Column Name="Name" Type="System.String" DbType="VarChar(50) NOT NULL" 
      CanBeNull="false" UpdateCheck="Never" />

Я не знаю, есть ли способ сделать это программно или "на лету".

Ответ 3

Лично мне нравится простота одного столбца timestamp/row-version; установите это как единственный столбец, который нужно проверить (IIRC, произойдет автоматически для timestamp), и вы отсортированы - вы должны получить TSQL:

exec sp_executesql N'UPDATE [dbo].[SiteVisit]
SET [TotalTimeOnSite] = @p2, [ContentActivatedTime] = @p3
WHERE ([SiteVisitId] = @p0) AND ([Timestamp] = @p1)

Это зависит от того, что они не являются параллельными (не конфликтующими) обновлениями для одной и той же записи; с timestamp/row-version и т.д., любое противоречивое обновление приведет к тому, что второй будет прерван, даже если они обновят разные столбцы и т.д.

Ответ 4

Поле timestamp, несомненно, казалось самым элегантным способом сделать это. Я НЕНАВИЖУ, что нужно возиться с отдельными свойствами поля - в основном, поэтому я могу безопасно удалить и повторно добавить таблицу в свой файл DBML, не беспокоясь о последствиях.

http://msdn.microsoft.com/en-us/library/bb470449.aspx

SQL, сгенерированный для UPDATE:

exec sp_executesql N'UPDATE [dbo].[SiteVisit]
SET [TotalTimeOnSite] = @p2
WHERE ([SiteVisitId] = @p0) AND ([timestamp] = @p1)

и в той же транзакции:

SELECT [t1].[timestamp]
FROM [dbo].[SiteVisit] AS [t1]
WHERE ((@@ROWCOUNT) > 0) AND ([t1].[SiteVisitId] = @p3)',N'@p0 int,@p1 timestamp,@p2 int,@p3 int',@p0=814109,@p1=0x0000000000269CB8,@p2=1199920,@p3=814109

Он выполняет UPDATE, а затем возвращает новую временную метку для отправки обратно моему клиенту. Я не уверен, что полностью понимаю, что означает @@ROWCOUNT > 0, но сейчас мне не очень-то интересно:)

Ответ 5

Если вы можете изменить схему, добавьте столбец типа rowversion. Последний LINQ to SQL устанавливает проверку обновлений на "Никогда" для всех столбцов. Если у вас есть временная метка, она будет использовать это как оптимистичную проверку блокировки, и система ударяет ее каждый раз, когда происходит обновление.

ПРИМЕЧАНИЕ. Это был тип данных Timestamp, определенный в SQL '92, но реализованный без какой-либо информации времени, поэтому он не был совместим с какой-либо другой стандартной системой. Может быть, это было намеренно, кто знает.