none
SQL Server update 执行为什么会越来越慢? RRS feed

  • 问题

  • 在一个大的事务中,需要 用 update 更新 大概100万条记录,每个更新的数据都要通过一堆计算规则处理,所以无法一批更新

    更新前面几条记录的时候非常快(不到1毫秒),但是随着时间的推移,update执行时间越来越长,最后竟然需要 100 毫秒

    这是什么原因?

    update更新用到了 primary key,更新了大概10个字段,整表只有15个字段,其余5个用作主键

    语句基本这样:

    update table set

        field1 = xxx,

        field2 = xxx,

    where key1 = ..., key2 = xxx ... key5 = xxx.

    SQL Server 是 2014的

    2017年7月4日 2:37

全部回复

  • 你是用 profile 做语句级跟踪判断的 update 慢

    还是循环的每一次时间越来越慢?

    2017年7月4日 6:00
  • 用 profile,可以看到 duration的时间从 1毫秒一直会增加到 100多毫秒

    当然实际的执行时间也是越来越慢,这个可以明显感受到

    2017年7月4日 6:28
  • Hi workwise-temp,

    可以查看一下你的查询计划吗,这个要分析查询计划才能判断具体原因。并且在执行update语句的时候监控一下CPU,内存和硬盘I/O的占用情况。

    Best Regards,
    Teige

    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2017年7月4日 6:46
    版主
  • profile 里面显示不了这句 update语句的 执行计划怎么办? (profile里面勾了  "Showplan  XML")

    这个语句在一个存储过程里面,只会更新一条数据,profile里面看到一reads一般是 30,writes一般是 0

    2017年7月4日 8:06
  • 可否将更新语句

    update table set

        field1 = xxx,

        field2 = xxx,

    where key1 = ..., key2 = xxx ... key5 = xxx. 

    改成

    update table set

        field1 = xxx,

        field2 = xxx,

    where key1 = ...

    update table set

        field1 = xxx,

        field2 = xxx,

    where  key2 = xxx

    update table set

        field1 = xxx,

        field2 = xxx,

    where   key5 = xxx.


    专注于.NET ERP/CRM开发框架,C/S架构,SQL Server + ORM(LLBL Gen Pro) + Infragistics WinForms

    2017年7月5日 0:42
  • 试试把存储过程的缓存清理掉,如果好了,说明存储过程的执行计划不适合用于多次执行

    USE 你的库名;

    SELECT plan_handle
    FROM sys.dm_exec_procedure_stats
    WHERE database_id = DB_ID() AND object_id = OBJECT_ID('你的存储过程名')
    ;
    -- 记录查出的这个值,用 DBCC FREEPROCCACHE(plan_handle) 释放缓存

    2017年7月5日 1:29
  • 这个不行,因为key1+key2+...key5才是一个主键
    2017年7月5日 2:36
  • 客户已经用别的方法绕过去了,等以后有机会试试

    不过这样也无法解释为什么执行会越来越慢,

    被更改的记录会影响新的更新语句吗?也就是说SQL server 会把更新的数据放到一个地方,这样当要更新记录时,会先要查看旧表中的数据,同时还要去查看已经被更新过的数据?

    2017年7月5日 2:41
  • 客户已经用别的方法绕过去了,等以后有机会试试

    不过这样也无法解释为什么执行会越来越慢,

    被更改的记录会影响新的更新语句吗?也就是说SQL server 会把更新的数据放到一个地方,这样当要更新记录时,会先要查看旧表中的数据,同时还要去查看已经被更新过的数据?

    如果没有snapshot/rowversion,不会的,内存页是实时更新的,磁盘不是实时更新,但是不会去读磁盘上的脏页。

    你看看语句的waits


    想不想时已是想,不如不想都不想。

    2017年7月5日 5:16
    版主
  • 能调整的情况,最好单独用一本单位作为主健,这样结构更稳定,条件5个列作为唯一约束去限制唯一性
    检查你的当前主健是不是碎片情况,碎片过多时重建一下索引,再试试你的语句

    Roy Wu(吳熹Blog)(微博)

    2017年7月5日 7:55
    版主
  • 啊,我们的表里刚好有 rowversion字段,能再详细说说么?

    但是整个更新过程不会对一条记录做重复的更新

    2017年7月6日 3:07
  • 碎片是指不按索引顺序插入数据造成split page,每页的数据填充率低,就形成了碎片。

    但是碎片不至于造成update单条数据100多ms。

    可以考虑用自动增量作为聚集索引,5个列作为主键。但未必会有根本性改善。


    想不想时已是想,不如不想都不想。

    2017年7月6日 7:15
    版主
  • 那你前面提到的 rowversion 是怎么回事?
    2017年7月6日 10:50
  • 那你前面提到的 rowversion 是怎么回事?

    我说的rowversion是放在tempdb里面的row versions,是具体的数据。你说的rowversion数据类型只是一个version stamping,是一个二进制的连续增量的戳,以前叫timestamp的。


    想不想时已是想,不如不想都不想。

    2017年7月10日 2:53
    版主