Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么SQL Server上的varbinary(max)上的更新语句如此缓慢?_Sql_Sql Server_Filestream - Fatal编程技术网

为什么SQL Server上的varbinary(max)上的更新语句如此缓慢?

为什么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

我有一个只有500行的表
S
,还有一个有120000行的表
F
。两者都使用GUID主键,而table
F
将外键保存到table
S
。表
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的知识有限)。

我在这里看到了三件事:

  • 您没有提到等价的select语句返回所需的秒数,但是如果这需要几秒(如中所示,而不是10秒以下),您可能希望为日期使用变量,而不是运行DATEADD函数100k次。其语法如下:

    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
    
  • 你可以选择成批更新,比如说10k行;这将不会锁定太多,并可能更快地返回

  • 我要检查的另一件事是表F上的索引数量。当您选择时,优化器将决定使用哪个索引,然后您将执行该操作,而在更新中,包含受影响字段的所有索引也需要更新
    注释:作为PK的GUID对此处的性能没有帮助。如果有许多非聚集索引,则GUID问题会加剧

    您是否尝试过创建一个只有一个字段(S.SID)和所有与S.Date 此外,GUID上的索引可能不如在INT上使用索引好。请阅读此 祝你好运

    大概是这样的:

    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中的记录将位字段设置为1的频率,如果不太频繁,可以将更新放入
    触发器中

  • 另一种方法是,仅当S中的位字段未设置时,才从F中选择数据:

  • 选择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