为什么SQL Server上的varbinary(max)上的更新语句如此缓慢?
我有一个只有500行的表为什么SQL Server上的varbinary(max)上的更新语句如此缓慢?,sql,sql-server,filestream,Sql,Sql Server,Filestream,我有一个只有500行的表S,还有一个有120000行的表F。两者都使用GUID主键,而tableF将外键保存到tableS。表F包含一个varbinary(max)列F.Data,每行约100KB(数据库总大小约为10GB)。文件流已打开。我正在使用SQL Server 2014 Express 当我执行以下UPDATE语句(在SQLServerManagementStudio中)时,它会影响大约100000行 UPDATE F SET F.Data = 0 FROM F INNER JOIN
S
,还有一个有120000行的表F
。两者都使用GUID主键,而tableF
将外键保存到tableS
。表F
包含一个varbinary(max)
列F.Data
,每行约100KB(数据库总大小约为10GB)。文件流已打开。我正在使用SQL Server 2014 Express
当我执行以下UPDATE语句(在SQLServerManagementStudio中)时,它会影响大约100000行
UPDATE F
SET F.Data = 0
FROM F
INNER JOIN S
ON S.SID = F.SID
WHERE S.BITFIELD = 1 AND S.Date < DATEADD(DAY,-90,GETDATE())
更新F
设置F.数据=0
来自F
内连接
在S.SID=F.SID上
其中S.BITFIELD=1,S.Date
查询大约需要30分钟。这是不可接受的,但我对SQL的了解还不够,不知道为什么或者如何使这个查询更有效。有谁能帮忙
仅供参考,等效SELECT语句只需几秒钟。我在Stackoverflow和其他地方搜索过,没有发现任何特别有用的东西(考虑到我对SQL的知识有限)。我在这里看到了三件事:
DECLARE @MyDate as DATETIME = DATEADD(DAY,-90,GETDATE());
UPDATE F
SET F.Data = 0
FROM F
INNER JOIN S
ON S.SID = F.SID
WHERE S.BITFIELD = 1 AND S.Date < @MyDate
将@MyDate声明为DATETIME=DATEADD(DAY,-90,GETDATE());
更新F
设置F.数据=0
来自F
内连接
在S.SID=F.SID上
其中S.BITFIELD=1,S.Date<@MyDate
注释:作为PK的GUID对此处的性能没有帮助。如果有许多非聚集索引,则GUID问题会加剧 您是否尝试过创建一个只有一个字段(S.SID)和所有与S.Date
CREATE TABLE [#TEMPTBL1]([SID] uniqueidentifier);
CREATE CLUSTERED INDEX IDX_TEMPTBL1_SID ON [#TEMPTBL1]([SID]);
INSERT INTO [#TEMPTBL1]([SID])
SELECT ([SID]) FROM S
WHERE S.BITFIELD = 1
AND S.Date < DATEADD(DAY,-90,GETDATE());
UPDATE F
SET F.Data = 0
FROM F
INNER JOIN #TEMPTBL1 TMP ON F.SID = TMP.SID
DROP TABLE #TEMPTBL1;
创建表[#testbl1]([SID]唯一标识符);
在[#TENTBL1]([SID])上创建聚集索引IDX_TENTBL1_SID;
插入到[#bl1]([SID])
从中选择([SID])
其中S.位字段=1
和S.Date
----------使用计数器更新代码--------
DECLARE@updtCounter int=0;
创建表[#TENTBL1]([SID]唯一标识符);
在[#TENTBL1]([SID])上创建聚集索引IDX_TENTBL1_SID;
插入到[#bl1]([SID])
从中选择([SID])
其中S.位字段=1
和S.Date
还有一些建议:
1.这可能是一种罕见的情况,在这种情况下,游标可以通过将更新分成更小的块来提高性能。您提到表S有500行,表F有120K行,所以如果它们大致均匀分布,那么S中每行F中有240行
Declare @SID uniqueidentifier;
Declare c cursor forward_only for
SELECT ([SID]) FROM S
WHERE S.BITFIELD = 1
AND S.Date < DATEADD(DAY,-90,GETDATE());
Fetch next from c into @SID
While @@fetch_status = 0
Begin
UPDATE F
SET F.Data = 0
FROM F
WHERE F.SID = @SID
Fetch next from c into @SID
End
Deallocate c
Declare@SID uniqueidentifier;
声明c游标向前\u仅用于
从中选择([SID])
其中S.位字段=1
和S.Date
Update
周围使用begintrans
和Commit
可以获得更好的性能触发器中
选择S.BitField=1时的大小写,然后选择0,否则F.数据作为数据结束
来自F
内连接
在S.SID=F.SID上
select语句旨在使S中的位字段设置为1时,F.Data似乎包含0。您可以将Select放入视图中,然后在其他查询中访问F时使用视图而不是表。即使F.Data字段仍然包含100KB的值,但无论何时从视图中选择,它都会根据S.BitField将F.Data显示为0或实际值。如果需要减少正在使用的磁盘空间,您仍然需要执行更新,但您可以将其安排在系统未使用的时间。100000(每行5个字节)将转换为500 GB的更新信息。那是日志。所有这些都需要被记录。我想你已经回答了你自己的问题,你有一个大的表,你正在更新它…它被记录,并且它也必须在表中结束。建议将你的更新分成小块。最终,你只是移动了太多的数据,速度会很慢。@Matt,我的错误。我更新了问题。每行大约为100KB,数据库总大小约为10GB。@GordonLinoff,我的错误。我更新了问题。每行约为100KB,数据库总大小约为10GB.1。添加变量f
Declare @SID uniqueidentifier;
Declare c cursor forward_only for
SELECT ([SID]) FROM S
WHERE S.BITFIELD = 1
AND S.Date < DATEADD(DAY,-90,GETDATE());
Fetch next from c into @SID
While @@fetch_status = 0
Begin
UPDATE F
SET F.Data = 0
FROM F
WHERE F.SID = @SID
Fetch next from c into @SID
End
Deallocate c