我在表格中添加了一个新列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)
)
现在我想使用以下规则生成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
这应该导致:
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
我可以更快地运行吗?
答案 0 :(得分: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
这将利用SQL Server的ROW_NUMBER
函数为每行提供正确的计数。使用UPDATE...FROM
,我们可以创建一个inner join
来更新。这比光标更有效率。
请参阅,游标为基于过程和基于集合的语言(SQL)添加迭代功能。这两个人在一起打得不好。正在为每一行调用update
语句(并打开/提交事务,以引导)。如果你在一个语句中完成所有操作,SQL可以将其并行化以使其更快。
标准规则是这样的:尽可能少地使用游标。有一些边缘情况需要它们,但如果你每天都没有进行大量的SQL管理,那就是怀疑你会遇到过这些案件。
答案 1 :(得分:1)
类似的东西,没有经过测试
update
p
set
packageNo = p2.Ranking
from
packages p
JOIN
(SELECT
orderNo, orderlineNo,
ROW_NUMBER() OVER (PARTITION BY orderNo ORDER BY orderlineNo) AS Ranking
FROM
packages) p2 ON p.orderNo = p2.orderNo AND p.orderlineNo= p2.orderlineNo
答案 2 :(得分:0)
WITH cteA AS (
SELECT
packageNo,
row_number() over (partition by orderNo order by orderNo, orderlineNo) rn
FROM packages
)
UPDATE cteA
SET packageNo = rn - 1;
您还应该在orderNo,orderlineNo。
上创建聚簇索引(我希望您使用的是sql2005或更新版本)
答案 3 :(得分:-1)
如果您确实需要使用游标,请使用某些属性定义光标,如下所示:
DECLARE _cursor CURSOR LOCAL FAST_FORWARD FOR
....