13

LINQ を使用して編集する単純な行があります。主キーの数値シーケンスを含め、約 30 列あります。

LINQ を使用して UPDATE を実行すると、UPDATE ステートメントにはテーブルのすべての列が含まれます (同時実行性チェックのため)。

私はこれがどれほど非効率的であるか疑問に思っています.negligibielではないにしても. 主キーにインデックスがあるため、最初の行検索に列が使用され、さらに他のフィールドがチェックされていると仮定します。これが無視できるほどの時間を要するとは思いもしませんでした。

私が尋ねる理由は、この UPDATE が場合によっては 1 秒以上かかるのを見たことがありますが、これは正しくないようです。他にも長期にわたる操作が行われている可能性がありますが、心配する必要があるかどうかについて興味がありました.

他のすべてのフィールドに対して「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
4

5 に答える 5

23

スタック オーバーフローの早い段階でこれに遭遇しました。すべての LINQ to SQL 更新では、更新を書き込む前に、基になるフィールドが変更されていないことが確認されます。つまり、すべての更新は「このフィールドが等しく、このフィールドが等しく、このフィールドが等しい場合にのみレコードを更新する」ことです。

ほとんどの場合、悲観的な更新は気にしないことにしました。また、更新で確認する必要があるフィールドは Id フィールドだけです。

そのUpdateCheck="never"ため、dbml マッピング ファイルの Id を除くすべてのフィールドに次のように設定しました。

<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" />

これをプログラムまたはオンザフライで行う方法があるかどうかはわかりません。

于 2008-12-01T04:56:38.300 に答える
5

更新チェックのオーバーヘッドが無視できるというあなたの主張は正しいです。where 句のいずれかの部分で満たされるインデックス (または主キー) がある場合は、それが使用されます。他の列をチェックするためのコストはごくわずかです。これを確認するには、SQL 管理スタジオ (または古いバージョンの SQL Server のクエリ アナライザー) で実行計画の表示を有効にし、更新を実行します。

実行時間が長いのは、他の原因が原因である可能性が最も高いです。ロックは良い候補です。再現できる場合は、SQL プロファイラーを使用して何が起こっているのかを調べてください。

于 2008-12-02T02:42:22.893 に答える
4

タイムスタンプフィールドは確かにこれを行うための最もエレガントな方法のようでした。個々のフィールドのプロパティをいじるのは嫌いです。主に、結果を心配することなく、テーブルを安全に削除してDBMLファイルに再追加できるようにするためです。

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

UPDATE用に生成された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

UPDATEを実行してから、新しいタイムスタンプを取得してクライアントに送り返します。@@ ROWCOUNT> 0の意味を完全に理解しているのかわかりませんが、今は気にしません:)

于 2008-12-02T02:15:27.657 に答える
4

個人的には、単一のタイムスタンプ/行バージョン列のシンプルさが気に入っています。これをチェックする唯一の列として設定し(IIRC、自動的に発生しますtimestamp)、ソートされます-TSQLを次のように取得する必要があります:

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

これは、同じレコードへの同時更新ではない (競合しない) ことに依存しています。タイムスタンプ/行バージョンなどを使用すると、異なる列などを更新したとしても、競合する更新により2番目が中止されます。

于 2008-12-01T05:29:16.457 に答える
1

スキーマを変更できる場合は、rowversion タイプの列を追加します。最新の LINQ to SQL では、すべての列に対して更新チェックが [なし] に設定されています。タイムスタンプがある場合、楽観的なロック チェックとしてそれを使用し、システムは更新があるたびにタイムスタンプを増やします。

注: これは、SQL '92 で定義された Timestamp データ型でしたが、時間情報なしで実装されたため、他の標準システムと互換性がありませんでした。多分それは意図的だった、誰が知っている.

于 2009-04-13T16:20:47.940 に答える