2008-12-01 6 views
11

J'ai une simple ligne que j'édite en utilisant LINQ. Il a environ 30 colonnes, y compris une séquence numérique de clé primaire.Combien de frais généraux 'Update Check' a pour LINQ UPDATES

Lorsqu'une mise à jour est effectuée via LINQ, l'instruction UPDATE inclut toutes les colonnes de la table (pour la vérification de la simultanéité).

Je me demande comment cela est inefficace - si ce n'est pas négligeable. Comme il y a un index sur la clé primaire, je suppose que cette colonne est utilisée pour la recherche de ligne initiale, puis les autres champs sont vérifiés en plus. Je n'aurais pas pensé que cela prendrait plus qu'une quantité négligeable de temps.

La raison pour laquelle je demande est que j'ai vu cette mise à jour prendre plus d'une seconde dans certains cas, ce qui ne semble pas juste. Il se peut qu'il y ait d'autres opérations de longue durée, mais cela m'a rendu curieux de savoir si je devrais être inquiet ou non. Je sais que je peux mettre 'UpdateCheck' à jamais pour tous les autres champs, mais c'est douloureux.

Existe-t-il un moyen de désactiver 'Update Check' pour un seul SubmitChanges(), ou dois-je le faire en changeant 'UpdateCheck' pour chaque champ.

Tout conseil serait apprécié.

Voici la mise à jour 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 

Répondre

5

Votre affirmation que la surcharge pour la vérification de mise à jour est négligeable est correcte. S'il existe un index (ou une clé primaire) satisfait par une partie de la clause where, alors cela sera utilisé. Le coût de vérification des autres colonnes est négligeable. Vous pouvez le confirmer en activant l'affichage du plan d'exécution dans SQL Management Studio (ou l'analyseur de requêtes pour les anciennes versions de SQL Server) et exécuter votre mise à jour.

Les temps d'exécution longs sont probablement causés par autre chose. Le verrouillage est un bon candidat. Si vous pouvez le reproduire, utilisez SQL Profiler pour savoir ce qui se passe.

21

Nous avons couru dans cette première débordement de la pile. Chaque mise à jour LINQ to SQL vérifie que les champs sous-jacents n'ont pas été modifiés avant d'écrire une mise à jour. En d'autres termes, chaque mise à jour est « à jour l'enregistrement que si ce champ est égal, et ce champ est égal, et ce champ est égal à » ..

Nous avons décidé la plupart du temps nous ne tenions pas mises à jour pessimistes, et le seul champ que la mise à jour doit vérifier est le champ Id.

Alors, ce que nous avons fait a été mis UpdateCheck="never" pour tous les domaines, sauf l'ID dans le fichier de mappage de dbml, comme ceci:

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

Je ne sais pas s'il y a un moyen de le faire par programme ou à la volée.

+0

une solution très stackoverflowy à un type de problème stackoverflowy :-) je suis allé avec la solution d'horodatage parce que je ne voulais pas avoir à changer chaque colonne chaque fois que je met à jour mon schéma –

+0

Il existe un moyen programmatique: Modifier les structures internes par réflexion . Une fois que le modèle commence à avoir des centaines de tables, cela a du sens. – usr

4

Personnellement, j'aime la simplicité d'une seule colonne timestamp/row-version; Définissez ce que la seule colonne à vérifier (IIRC, se fait automatiquement pour timestamp), et vous êtes triée - vous devriez alors obtenir TSQL comme:

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

Cela repose sur leur pas être concurrente (sans conflit) mises à jour du même enregistrement; Avec une mise à jour en conflit toute mise à jour en conflit entraînera l'abandon de la seconde, même si elles ont mis à jour différentes colonnes, etc.

4

Timestamp champ semble certainement être la façon la plus élégante de le faire. Je déteste avoir à jouer avec les propriétés de chaque champ - principalement afin que je puisse supprimer et rajouter en toute sécurité une table à mon fichier DBML sans avoir à m'inquiéter des conséquences.

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

Le SQL maintenant généré pour une mise à jour:

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

et dans la même transaction:

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 

Il fait un UPDATE et récupère ensuite la nouvelle horodatage renvoyer à mon client. Je ne suis pas sûr de bien comprendre ce que signifie @@ ROWCOUNT> 0, mais pour l'instant je ne m'en soucie pas vraiment :)

+1

@Simon: (@@ ROWCOUNT)> 0) renvoie le nombre de lignes affectées à partir de la requête précédente. Dans ce cas, votre requête renverra uniquement l'horodatage mis à jour si une ligne a été réellement mise à jour (sinon, @ROWCOUNT sera égal à 0). Ainsi, si vous ne récupérez pas l'horodatage dans votre application, vous savez que la mise à jour a échoué. –

+0

Pouce en l'air pour le lien! Fonctionne très bien! – SharpAffair

1

Si vous pouvez modifier le schéma, ajoutez une colonne de type rowversion. La dernière version de LINQ to SQL définit la vérification des mises à jour sur Jamais pour toutes les colonnes. Si vous avez un horodatage, il l'utilisera comme un contrôle de verrouillage optimiste, et le système le remplacera chaque fois qu'il y aura une mise à jour. REMARQUE: il s'agissait du type de données Timestamp tel que défini par SQL '92, mais il a été implémenté sans aucune information temporelle, il n'était donc pas compatible avec les autres systèmes standard. Peut-être que c'était intentionnel, qui sait.

+0

il y a une «dernière version»? .NET 3.5 SP1? Je ne savais pas de cela –

+0

Je crois que la dernière version est appelée Linq aux entités ?? – Jeff

+0

Linq-to-Sql! = Linq-to-Entities –

Questions connexes