none
SQLSERVER内存表非常慢 RRS feed

  • 问题

  • 最近测试sqlserver的内存表发现一个问题,如下:

    create   table product55(code int not null ,stock_total int  not null,stock_now int  not null,create_time smalldatetime not null,
    primary key nonclustered hash(code) with(bucket_count=10000))
    WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)


     create  proc porc_execute55 
     WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER 
    as
    BEGIN ATOMIC   
     WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')--本机编译的存储过程不支持begin tran显示的事务提交,所以遇到问题不能rollback,而只能反向写SQL了

      declare @id2 int
     declare @id int=1  
     
    while @id<=10000
    begin

    set @id2=5

    update dbo.product55
    set stock_now-=1
    where code=@id2
      
    set @id+=1

    end

    end

    运行存储过程发现一个问题:

    存储过程里面是循环执行10000次,按道理来说应该是瞬间完成,但是速度却非常的慢,最快一次也用了两秒钟,

    最后找到一个特点:

    set @id2=5
    update dbo.product55
    set stock_now-=1
    where code=@id2

    即:每次更新的都是同一行数据

    如果修改为

    set @id2=5+@id
    update dbo.product55
    set stock_now-=1
    where code=@id2

    即:每次修改都是不同的行,则就达到效果了,即:瞬间完成

    难道,不能反复更新同一行数据么,性能如此低下,还不如不用本地编译的存储过程,速度还快很多很多

    2016年6月14日 9:23

答案

全部回复

  • Hi,

    >>难道,不能反复更新同一行数据么,性能如此低下,还不如不用本地编译的存储过程,速度还快很多很多

    首先你要弄清楚,不是效率问题,当你在进行修改行记录的操作同时,此条记录会被锁定,等他完成以后才能进行第二次同行记录的修改。

    更新不同行就没这个问题了。

    参考资料:

    SQL SERVER 中如何使用行锁?

    Regards,

    Moonlight


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.



    2016年6月15日 7:58
  • 同一条记录是排队更新的,想想最简单的 set id=id+1, 如果不排队,这个结果无法预料

    本地编译存储过程测试我的本本上可以到8-900毫秒,直接执行循环,要2秒多

    2016年6月16日 2:58
  • 再次进行了测试,set nocount on 以及开启了数据库的 延迟持久化

    利用普通的存储过程,更新同一行数据10000次,几乎0.5秒不到,而用本地编译的存储过程都是需要5秒左右

    对于同一个会话循环更新同一行数据来说,应该不存在所谓的 ”改行被阻塞”的问题,除非是多个会话更新同一行数据,那么会产生严重的lck阻塞

    2016年6月16日 6:26
  • 单个循环中确实不用考虑阻塞的问题,本来就是排队的

    0.5秒做不到的吧?你用的是 DURABILITY = SCHEMA_AND_DATA, 也就是数据写磁盘的,除非开启延迟事务,或者在一个事务中操作

    否则每一次更新都会写一次磁盘,1万次更新至少写1万次磁盘,一般的机器0.5秒多半是搞不定的

    2016年6月16日 9:58
  • 对,开启了延迟事务的,只需要0.5秒

    所以测试的结果是:本地编译的存储过程还没有普通的存储过程+延迟事务 快,所以肯定是哪里有问题的

    2016年6月16日 14:31
  • 测试发现本地编译存储过程首次执行接近1秒,但之后的执行按近3秒,这是个怪问题

    本地编译和普通存储过程的UPDATE 操作执行计划不一样

    2016年6月17日 5:47
  • 对呀(而且我在SQL2014 2016两个版本都测试了的) ,其实我对Reids也进行过类似测试,Redis就不会存在这个问题


    2016年6月17日 6:23