Сколько накладных расходов занимает проверка обновлений для LINQ UPDATES - PullRequest
12 голосов
/ 01 декабря 2008

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

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

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

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

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

Есть ли способ отключить «Проверка обновлений» для одного 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

Ответы [ 5 ]

21 голосов
/ 01 декабря 2008

Мы столкнулись с этим в начале переполнения стека. Каждое обновление 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" />

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

5 голосов
/ 02 декабря 2008

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

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

4 голосов
/ 02 декабря 2008

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

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

SQL теперь генерируется для ОБНОВЛЕНИЯ:

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

Он выполняет ОБНОВЛЕНИЕ, а затем получает новую метку времени для отправки обратно моему клиенту. Я не уверен, что полностью понимаю, что означает @@ ROWCOUNT> 0, но сейчас мне все равно:)

4 голосов
/ 01 декабря 2008

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

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

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

1 голос
/ 13 апреля 2009

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

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

...