SQL 2016 SQL Server声明:文件:<pageref.cpp>,行= 951失败声明


8

我目前正在将数据仓库从SQL 2012升级到SQL2016。新旧DW并行运行。

我的ETL流程(由第三方在SSIS中开发的框架)在2012年成功运行了两年多,但在2016年失败了。到目前为止,数据库和ETL流程是相同的。

这两个服务器都是在VMWare上运行的虚拟机。旧服务器是Win 2008,具有24Gb RAM。SQL 2012标准 最大内存设置为16Gb。新服务器是Win 2012,具有64Gb RAM。SQL 2016开发 最大内存设置为50Gb。新的DW正在运行v13.0.1601.5 RTM Developer Edition(64位)。

在运行我的ETL进程时,将SQL合并到维或事实表中的加载步骤失败,并出现以下错误。

全文:

描述:SQL Server声明:文件:,line = 951失败声明='IS_OFF(BUF_MINLOGGED,m_buf-> bstat)|| pageModifyType!= PageModifyType_Contents || GetPagePtr()-> IsTextPage()'。此错误可能与时序有关。如果重新运行该语句后错误仍然存​​在,请使用DBCC CHECKDB检查数据库的结构完整性,或者重新启动服务器以确保内存中的数据结构没有损坏。

按照建议,我已经运行DBCC,没有发现错误。我还重新启动了SQL。然后,我重新启动了ETL流程,并得到了相同的错误。

我对此错误的搜索显示,这是SQL 2008、2012和2014年的已知错误并已在后续的修补程序和累积更新中修复。因此,我很惊讶看到它在2016年重新出现。

我发现的链接说,如果数据库处于“简单”或“大容量日志记录”恢复模型中,则在尝试执行插入操作时会影响SSIS。(我正在以简单恢复模式运行)

建议的解决方法是将Db恢复模型更改为FULL。我已经尝试过了,并且可以正常工作,但这并不是数据仓库的解决方案。

其他人在2016年遇到过这个吗?

谁能建议替代解决方法?

更新:

2016年7月26日:我应用了重要更新KB3164398(v13.0.1708.0),问题仍然存在。

2016年7月27日:我已应用累积更新CU1 KB3164674(v13.0.2149.0)。

2016/3/8:在我们最小的立方体上,错误在一夜之间发生。CU1无法解决问题。今天,我报告了MS Connect上的错误,并且还与Microsoft记录了支持电话。

2016年12月8日:MS-Support最初做出了回应,但回应是“我们没有针对此问题的解决方案”。支持人员将与他的同事讨论该问题,并尽快与我联系。8天后,我没有收到他的消息。

尽管我没有“解决方案”,但我们确实找到了适合我们的解决方法。查看我发布的答案。

29/9/2016。我上周应用了CU2。在Thursay上,我们意外地运行了旧版本的合并,但由于相同的错误再次失败。所以.. CU2也没有修复它。

23/1/2017:我应用了2016 SP1 CU1,我相信这已经解决了问题。特别是KB3205964

Answers:


2

查看KB,您有几个选择/解决方法:

  1. 切换到完整恢复模型。您说“对于仓库而言,这不是很多选择”,但实际上仅是定期设置事务日志备份(例如15分钟),然后处置它们的问题。SSIS /维护计划具有执行此任务的库存任务。您将丢失批量记录的事务,但是我从未发现它们对运行时产生了巨大的影响,只是日志大小。您甚至可以将日志备份到nul,在这里我将不做介绍。如果您不确定该怎么做,请咨询本地DBA。磁盘空间和事务日志备份保留比致命错误更容易解决。该问题最终解决后,您可以切换回去。
  2. 该知识库提到“在单个分布式事务中有多个BULK INSERT语句”。从您的问题尚不清楚如何设置大容量插入物。您是否正在使用SSIS运行“执行SQL”任务,这些任务使用MERGE命令?“多个批量插入”在这里是什么意思?有没有一种方法可以将您的方法转换为单个大容量插入,例如一次转换一次?例如,在SSIS中,您可以将“ MaxConcurrentExecutables”暂时设置为1,看看是否有帮助。将其绑定到配置变量中,以便稍后再将其更改。显然,它会使速度变慢,但是您希望ETL完成而不是快速失败。并行执行操作是一种很好的模式,也是SSIS的真正优势,但是您只能以最慢的速度运行。假设您有10个维度需要一分钟,而一个事实则需要一个小时,那么您的ETL在一个小时内并行运行或1小时10分钟连续运行即可完成。
  3. MERGE很好,但确实有一些问题。您可以考虑转换回INSERT/ UPDATE。你也应该根据这里使用HOLDLOCKwith 。您是否使用该提示?如果这样做,对这个问题有什么影响吗?我们在早期的SQL 2014构建中遇到了一个问题,其中在列存储中使用可组合DML(子句)导致了这种断言-我让他们从未添加维度的列存储索引中删除了这些索引,而他们却没有告诉我。MERGEMERGEOUTPUT
  4. 您正在执行哪种交易处理?有时使用ETL,只需重新运行即可重复定位。有时您需要它失败并回滚。您是如何实现的?可以更改,因此不是“单一分布式事务”?

祝好运。


嗨@wBob谢谢您的回复。回答您的问题。1.我们正在谈论一步提取20-30Gb表。移动超过100Gb的数据。我担心要烧毁TX日志以及存储。也许每次提取后我都可以将日志备份放在ETL中的一步?2.是,SSIS调用SQL任务来执行合并。每个步骤都按顺序执行。在合并运行时,它是唯一执行的任务。3.我们的ETL工具是供应商提供的框架。这就是它的工作方式。不确定提示。会检查。4.没有TX处理。直接SQL。
Swears-a-Slot爵士'16

因此,如果成功运行无法继续进行,请在每次移动表后尝试使用100GB的t-log和日志备份,这应该对它进行排序。显然,您必须进行测试。我们还应该了解目标上的其他功能吗?列存储,分区,过度索引?
wBob

目前,2012 std上现有DW尚不具备的功能。新的DW / Datamarts是原始文档的精确副本,没有列存储或分区。最小(但有效)的索引。我们目前正在专注于平台之类的应用,最终我们的新产品DW将是2016 Enterprise。但是,直到基本功能正常运行,我们才添加企业级功能。
Swears-a-Slot爵士'16

@wBob,您好。我们通过将插入从合并中断开来实现了您的建议。但是考虑到我提出问题的方式,我不确定什么才是正确答案。但我认为您已经引导我采取了有效且可行的解决方法。
Swears-a-lot爵士,



1

我相信我们已经找到了另一个解决方法。我发布我的答案,因为我认为这可能有用,并且与wBob的建议足够不同。

我们更改了merge语句的insert部分,以便它插入到临时表中,而不是原始目标中。

一旦执行merge语句,我们便从#table插入目标。

这不是理想的方法,但是至少合并仍然可以通过标记已退出/已过期的行来处理“向上插入”的复杂性。

与将合并完全重写为单独的插入和更新相比,我们发现这是一个可以接受的折衷方案。

CREATE TABLE #Activity(
[ETL_ActivitySurrogateKey] [int] IDENTITY(1,1) NOT NULL,
[Field1] [varchar](255) NULL,
)

-- Insert statements for procedure here
INSERT INTO #Activity ( [Field1],2,3,etc )

SELECT [Field1],2,3,etc
FROM 
(
    MERGE [DDS_OZ_CC].[dimActivity] AS target 
    USING (
      SELECT [Field1],2,3,etc
      FROM [STAGE_OZ_CC].[Transform_Activity]
      ) as source
    ON
    (
      target.RowIsCurrent = source.RowIsCurrent
         AND target.[Field1] = source.[Field1]
    )
    WHEN MATCHED 
        AND (        
        EXISTS (SELECT target.Level5Id EXCEPT SELECT source.Level5Id)
    )
    THEN
      UPDATE SET 
        ETL_ValidToDateTime = source.ETL_ValidFromDateTime 
       ,ETL_RowIsCurrent = 0 
       ,ETL_LastTouchedBy = source.ETL_LastTouchedBy 
       ,ETL_RowChangeReason = 'SCD2 Retired' 

    WHEN NOT MATCHED THEN 
    INSERT 
    (    
     [Field1],2,3,etc
    )
    VALUES (      
      source.[Field1],2,3,etc
    )
       WHEN NOT MATCHED BY SOURCE AND target.ETL_RowIsCurrent = 1
       THEN UPDATE SET
       ETL_RowIsCurrent = 0 
       ,ETL_RowChangeReason = 'Fact Removed' 
       ,ETL_LastTouchedBy = 'Unknown'

  OUTPUT
    $action      
      ,source.[Field1],2,3,etc    

  ) AS MergeOutput
  (
    action  
    ,[Field1],2,3,etc   
  ) 

  WHERE ACTION = 'UPDATE' AND ETL_RowIsCurrent = 1

    INSERT INTO [DDS_OZ_CC].[dimActivity]
    ( [Field1],2,3,etc  )
    SELECT [Field1],2,3,etc
    FROM #Activity

    END

好的,谢谢彼得。只是出于兴趣,您是否尝试了HOLDLOCK提示?
wBob

不,我没有。阅读有关Aaron Bertrands的文章后,我的理解是这实际上是有关多个用户的并发问题。在我们的例子中,只有ETL流程执行。
Swears-a-lot爵士,

我认为值得一试,看看您是否有其他行为,再加上这可能是最佳实践,只是说您现在不并发并不意味着您将来可能不会。无论如何,在找到解决方案和解决下一个问题方面
做得很好:)

我本来想,但可惜我们受时间限制。一旦找到可行的解决方案,老板就会打电话继续前进。
瑟斯爵士乐团
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.