【问题标题】:How much overhead does 'Update Check' have for LINQ UPDATESLINQ 更新的“更新检查”有多少开销
【发布时间】:2008-12-01 04:34:14
【问题描述】:

我有一个使用 LINQ 编辑的简单行。它有大约 30 列,包括一个主键数字序列。

当通过 LINQ 执行 UPDATE 时,UPDATE 语句包括表的所有列(用于并发检查)。

我想知道这是多么低效 - 如果不是 negligibiel。由于主键上有一个索引,我假设该列用于初始行搜索,然后另外检查其他字段。我没想到这需要的时间可以忽略不计。

我问的原因是,在某些情况下,我已经看到这个 UPDATE 需要一秒钟,这似乎不正确。可能还有其他长期运营的事情正在进行,但这让我很好奇我是否应该担心。

我知道我可以将所有其他字段的“UpdateCheck”设置为从不,但这很痛苦。

有没有办法为单个 SubmitChanges() 关闭“更新检查”,或者我必须通过更改每个字段的“更新检查”来做到这一点。

任何建议将不胜感激。

这里是 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

【问题讨论】:

    标签: sql-server linq updatecheck


    【解决方案1】:

    我们很早就在 Stack Overflow 上遇到过这个问题。每个 LINQ to SQL 更新都会在编写更新之前验证基础字段是否未更改。换句话说,每次更新都是“仅当此字段等于,此字段等于,且此字段等于时才更新记录”..

    我们决定大部分时间都不关心悲观更新,更新需要检查的唯一字段是 Id 字段。

    所以,我们所做的是为 dbml 映射文件中除 Id 之外的每个字段设置 UpdateCheck="never",如下所示:

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

    我不知道是否有办法以编程方式或即时执行此操作。

    【讨论】:

    • 对 stackoverflowy 类型问题的一个非常 stackoverflowy 的解决方案 :-) 我选择了时间戳解决方案,因为我不想每次更新架构时都必须更改每一列
    • 有一种编程方式:通过反射修改内部结构。一旦模型开始有 100 个表,这就是有意义的。
    【解决方案2】:

    您关于更新检查的开销可以忽略不计的断言是正确的。如果 where 子句的任何部分都满足索引(或主键),则将使用该索引(或主键)。检查其他列的成本可以忽略不计。您可以通过在 SQL 管理工作室(或旧版本 SQL Server 的查询分析器)中启用执行计划显示来确认这一点并运行您的更新。

    执行时间过长很可能是由其他原因造成的。锁定是一个不错的选择。如果您可以重现它,请使用 SQL Profiler 找出发生了什么。

    【讨论】:

      【解决方案3】:

      就个人而言,我喜欢单个时间戳/行版本列的简单性;将此设置为唯一要检查的列(IIRC,timestamp 自动发生),然后您已排序 - 然后您应该得到 TSQL,如下所示:

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

      这依赖于它们不是对同一记录的并发(非冲突)更新;使用时间戳/行版本等,任何冲突更新将导致第二个中止,即使它们更新了不同的列等。

      【讨论】:

        【解决方案4】:

        Timestamp 字段似乎是最优雅的方式。我讨厌必须弄乱单个字段的属性 - 主要是这样我就可以安全地删除表并将其重新添加到我的 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
        

        它执行更新,然后检索新的时间戳发送回我的客户端。我不确定我是否完全理解 @@ROWCOUNT > 0 的含义,但现在我并不关心 :)

        【讨论】:

        • @Simon: (@@ROWCOUNT) > 0) 返回上一个查询中受影响的行数。在这种情况下,您的查询将仅在行实际更新时返回更新的时间戳(否则,@ROWCOUNT 将等于 0)。这样,如果您没有在应用中恢复时间戳,您就知道更新失败了。
        • 为链接点赞!效果很好!
        【解决方案5】:

        如果您可以修改架构,请添加 rowversion 类型的列。最新的 LINQ to SQL 将所有列的更新检查设置为从不。如果您有时间戳,它将使用它作为乐观锁检查,并且每次有更新时系统都会碰撞它。

        注意:这曾经是 SQL '92 定义的 Timestamp 数据类型,但在没有任何时间信息的情况下实现它,因此它与任何其他标准系统都不兼容。也许这是故意的,谁知道呢。

        【讨论】:

        • 有“最新”版本吗? .NET 3.5 SP1 ?我没有意识到这一点
        • 我相信最新的版本叫做Linq to Entities??
        • Linq-to-Sql != Linq-to-Entities
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-14
        • 1970-01-01
        • 2018-06-04
        • 2018-05-26
        相关资源
        最近更新 更多