T-SQL的威力之一就是大批量操作數據。不過某些場景下需要限制t-sql影響的行數。比如以前藝龍遇到的場景是:對一個發布的表,一次更改太多的行,可能造成發布的崩潰。這次我遇到的場景是服務器性能不是很好,內存不夠大,不限制影響行數的話,內存中可能已經容納不下執行sql過程中產生的數據集,執行起來非常慢。
我們單位的DBA針對這種情況,寫過一個存儲過程來應對,核心的代碼如下:
set rowcount 10000
delete
from temp
WHERE OperateTime > @CurrentDate
while @@rowcount>1
delete
from temp
WHERE OperateTime > @CurrentDate
set rowcount 0
其中用到了兩個關鍵的參數,一個是RowCount,可以設置受影響行數。設為0表示不限。如果上面設了rowcount=10000,下面忘了設rowcount=0,再執行一個select,最多也就返回10000行。另外一個是@@RowCount,表示上一條sql影響的行數。
在SQL Server 2008 r2的bookonline中,說下一個版本將廢除RowCount,建議改用其他方法,比如使用top參數。
我在最近的這個項目中,對這段代碼做了兩處改動:一是在刪除過程中把被刪除的數據插入到一個存檔表,另外增加了一條日志:
set rowcount 10000
delete
from temp
OUTPUT deleted.*
INTO temp_deleted
WHERE OperateTime > @CurrentDate
exec PRSDBLOGAffectedRowCount @PackageType,1350,@@RowCount
while @@rowcount>1
delete
from temp
OUTPUT deleted.*
INTO temp_deleted
WHERE OperateTime > @CurrentDate
exec PRSDBLOGAffectedRowCount @PackageType,1350,@@RowCount
set rowcount 0
不過發現那個while循環語句沒有執行,因為@@RowCount返回的是上一句sql“exec PRSDBLOGAffectedRowCount @PackageType,1350,@@RowCount”影響的行數。在PRSDBLOGAffectedRowCount中設了SET NOCOUNT ON,返回的@@RowCount都是0,下面的while循環永遠不會執行。
最終修改如下:
declare @TempRowCount int = 0
set rowcount 10000
DELETE
FROM temp
OUTPUT deleted.*
into temp_deleted
WHERE DepartureDate < dateadd(day, 0 - @OldDataExpireDayCount, @CurrentDate)
set @TempRowCount = @@RowCount
exec PRSDBLOGAffectedRowCount @PackageType,100,@TempRowCount
while @TempRowCount>1
begin
DELETE
FROM temp
OUTPUT deleted.*
into temp_deleted
WHERE DepartureDate < dateadd(day, 0 - @OldDataExpireDayCount, @CurrentDate)
set @TempRowCount = @@RowCount
exec PRSDBLOGAffectedRowCount @PackageType,100,@TempRowCount
end
set rowcount 0