光标内的SQL更新速度慢

Dom*_*aut 3 sql t-sql sql-server performance

我在packageNo表格中添加了一个新列:

 create table Packages(
  id varchar(20) primary key,  -- ok, I know :)
  orderNo uniqueIdentifier not null,
  orderlineNo int not null, 
  packageNo int not null default(0)
)
Run Code Online (Sandbox Code Playgroud)

现在我想packageNo用以下规则生成:

    为每个订单重置它
    上升为订单,订单

我的问题是我写的脚本在我的testServer上使用了15分钟的26500行.这里是:

set NoCount ON
declare @Counter int
declare @handledCounter int
declare @currentorder uniqueIdentifier
declare @fetchedOrder uniqueIdentifier
declare @fetchedId varchar(20) -- will using PK speed up things?

declare PackageNo_Cursor cursor  for 
  select orderNo, id from packages order by orderNo, orderlineNo for update of packageNo

open PackageNo_Cursor
fetch next from PackageNo_Cursor into @fetchedOrder, @fetchedId 

set @currentOrder = @fetchedOrder
set @counter = 0
set @handledCounter = 0
while @@fetch_status = 0
 begin 
     if (@currentOrder <> @fetchedOrder)
       begin  -- reset counter for each order
        set @currentOrder = @fetchedOrder
        set @counter = 0
       end
     set @counter = @counter + 1
     set @handledCounter = @handledCounter +1
     if (@handledCounter % 50 = 0)
      begin
        print 'handled = ' + cast(@handledCounter as varchar) 
      end
   update packages set packageNo = @counter where current of PackageNo_Cursor    
     fetch next from PackageNo_Cursor into @fetchedOrder, @fetchedId 
  end

close PackageNo_Cursor
deallocate PackageNo_Cursor
Run Code Online (Sandbox Code Playgroud)

这应该导致:

id   - orderno - lineNo - packageNo (what I need to set)  
ean1 - guid1   - 1      - 1  
ean2 - guid1   - 2      - 2   
ean3 - guid2   - 1      - 1  
ean15- guid2   - 3      - 2  
ean15- guid2   - 4      - 3
Run Code Online (Sandbox Code Playgroud)

我可以更快地运行吗?

Eri*_*ric 8

您不想使用游标,您希望将其作为一个集合执行,如下所示:

update p set
    packageNo = r.packageNo
from
    packages p
    inner join 
      (select orderNo, orderLineNo, 
       ROW_NUMBER() OVER(PARTITION BY orderNo ORDER BY orderLineNo) as packageNo
       from packages) r on
        p.orderNo = r.orderNo
        and p.orderLineNo = r.orderLineNo
Run Code Online (Sandbox Code Playgroud)

这将利用SQL Server的ROW_NUMBER功能为每行提供正确的计数.使用UPDATE...FROM,我们可以创建一个inner join更新.这比光标更有效.

请参阅游标,为过程和基于集合的语言(SQL)添加迭代功能.这两个人在一起打得不好.update正在为每一行调用该语句(并打开/提交事务,以引导).如果您在一个语句中完成所有操作,SQL可以将其并行化以使其更快.

标准规则是:尽可能少地使用游标.有一些边缘情况需要它们,但是如果你每天都没有进行大量的SQL管理,你会遇到这些情况是值得怀疑的.