SSIS 包不想获取临时表的元数据

Posted

技术标签:

【中文标题】SSIS 包不想获取临时表的元数据【英文标题】:SSIS Package not wanting to fetch metadata of temporary table 【发布时间】:2013-08-23 04:17:56 【问题描述】:

我有一个 SSIS 包,其中包含多个流。

每个流负责创建一个“临时”表,该表在创建后被填满。 这些表是全局临时表。

我为另一个表添加了 1 个额外的流程(我没有制作包),它完全按照上面的说明进行。但是,由于某种原因,包在此流程中间歇性地失败,而除了一些表名之外,它与其他包完全相同。

不断弹出的错误:

更新 - 插入数据流:错误:SSIS 错误代码 DTS_E_OLEDBERROR。一个 发生 OLE DB 错误。错误代码:0x80004005。 OLE DB 记录是 可用的。来源:“Microsoft SQL Server Native Client 11.0” Hresult:0x80004005 描述:“未指定的错误”。一个 OLE 数据库 记录可用。资料来源:“Microsoft SQL Server Native Client 11.0" Hresult: 0x80004005 描述: "元数据无法确定,因为语句'select * from '##TmpMcsConfigurationDeviceHistory86B34BFD041A430E84CCACE78DA336A1'' 使用临时表。”。

创作表达:

"CREATE TABLE " + @[User::TmpMcsConfigurationDeviceHistory]  + " ([RecId] [bigint] NULL,[DataAreaID] [nvarchar](4) COLLATE database_default NULL,[Asset] [bigint] NULL,[Code] [nvarchar](255) COLLATE database_default NULL,[Configuration] [bigint],[StartdateTime] [datetime] NULL,[EndDateTime] [datetime] NULL)

"

已解析的表达式(=已评估):

CREATE TABLE ##TmpMcsConfigurationDeviceHistory764E56F088DC475C9CC747CC82B9E388 ([RecId] [bigint] NULL,[DataAreaID] [nvarchar](4) COLLATE database_default NULL,[Asset] [bigint] NULL,[Code] [nvarchar](255) COLLATE database_default NULL,[Configuration] [bigint],[StartdateTime] [datetime] NULL,[EndDateTime] [datetime] NULL)

【问题讨论】:

【参考方案1】:

如果您使用的是 SSIS 2012,那么它使用系统存储过程 sp_describe_first_result_set 来获取表的元数据,并且它不支持临时表。但是您可以选择其他选项,例如可以正常工作的表变量和 CTE。 https://connect.microsoft.com/SQLServer/feedback/details/629077/denali-engine-metadata-discovery-shuns-temp-tables

【讨论】:

我在我的数据流中使用表变量(这是我使用 SSIS 的第一天,所以我希望我是正确的),它们只包含用于创建临时表的 DDL,就像所有其他数据流一样(而它适用于其他数据流)。 正如我在您的错误描述中看到的那样,选择查询正在针对临时表运行,该临时表又会要求元数据。 select * from '##TmpMcsConfigurationDeviceHistory86B34BFD041A430E84CCACE78DA336A1' 请通过此数据流并确认上述查询是否正在运行。 仅供参考:对于表变量,Soram 是指 SQL 表变量 (@tables) 而不是包含 DDL 的 SSIS 变量。 表变量对于小型结果集将“正常”工作。一旦有几百行,性能就会很糟糕。【参考方案2】:

另一个选项(有点像 hack,但它可以工作,并且不需要您更改对全局临时表的使用)是在您的实际查询前使用 SET FMTONLY ON 命令来发送虚假的“第一个结果”设置”为具有正确列结构的 SSIS。所以你可以做类似的事情

SET FMTONLY ON
select 0 as a, 1 as b, 'test' as C, GETDATE() as D
SET FMTONLY OFF

select a, b, c, d from ##TempTable

当 SSIS 运行 sp_describe_first_result_set 时,它将返回 FMTONLY 命令的元数据和列名,并且不会抱怨无法确定临时表的元数据,因为它甚至不会尝试。

【讨论】:

谢谢,我在一个使用临时表的触发器的地方,我无法触摸触发器(不要问)......这就是我需要的 一年半后仍然有用。谢谢凯尔。 成功了。我必须采取更多步骤才能使其正常工作。我的查询有 40 多个字段,其中一些是 bigint,一些是小数(19,4)。在 FMTONLY 内的假选择中,我不得不多次写 CAST(NULL AS DECIMAL(19,4)) 作为 MyDecimalField。 仅供参考:SET FMTONLY 自 SQL Server 2012 以来已被弃用。msdn.microsoft.com/en-us/library/ms143729(v=sql.110).aspx【参考方案3】:

我发现问题在于 GUID 重复问题,我复制了元素(例如用于创建临时表的元素),并且它们在复制时都收到了相同的 guid。我使用了一个工具来重置我的包中的所有这些 guid,这解决了我的问题。

谢谢!

【讨论】:

【参考方案4】:

遇到了与我们使用临时表进行暂存相同的问题。花了一些时间后,找到了解决方法。

在数据流任务的 OLE DB/ADO 目标中指定临时表的名称。

将 AccessMode 属性更改为 SQL 命令而不是 OpenRowSet,并将 SQL 命令属性指定为“select * from #temp”。

万岁,它按预期工作。

这里的问题是,当您指定 SQL 命令以外的访问模式时,SSIS 期望它是一个表/视图,并且它更改了 SSIS 以调用 sp_describe_first_result_set 来获取元数据。但是当你指定 SQL 命令时,它会期待一个查询或 SP 命令等,所以幸运的是它仍然使用旧的方式来获取元数据。

http://social.msdn.microsoft.com/Forums/sqlserver/en-US/cfe1c7c1-910a-4f52-9718-c3406263b177/usage-of-temp-tables-in-ssis-2012?forum=sqlintegrationservices#cfe1c7c1-910a-4f52-9718-c3406263b177

【讨论】:

【参考方案5】:

Using WITH RESULT SETS to explicitly define the metadata 将允许 SSIS 跳过 sp_describe_first_result_set 步骤并使用您定义的元数据。好处是您可以使用它来让 SSIS 执行包含临时表的 SQL(对我来说,这种性能帮助很大);缺点是,如果有任何变化,您必须手动维护和更新它。

查询样本(存储过程:)

    EXEC ('dbo.MyStoredProcedure')
    WITH RESULT SETS
      (
        (
            MyIntegerColumn INT NOT NULL,
            MyTextColumn VARCHAR(50) NULL,
            MyOtherColumn BIT NULL
        )
      )

查询示例(简单 SQL:)

EXEC ('
    CREATE TABLE #a 
      (
        MyIntegerColumn INT NOT NULL,
        MyTextColumn VARCHAR(50) NULL,
        MyOtherColumn BIT NULL
      ) 
    INSERT INTO #a 
      (
        MyIntegerColumn,
        MyTextColumn,
        MyOtherColumn
      )
    SELECT 
        1 AS MyIntegerColumn,
        ''x'' AS MyTextColumn,
        0 AS MyOtherColumn

    SELECT MyIntegerColumn, MyTextColumn, MyOtherColumn
    FROM #a')

WITH RESULT SETS
    (
        (
            MyIntegerColumn INT NOT NULL
           ,MyTextColumn VARCHAR(50) NULL
           ,MyOtherColumn BIT NULL
        )
    )

【讨论】:

这是对我有用的答案。上面使用 FMTONLY 命令的答案最终在实际 ETL 期间向输出发送了 0 行。 谢谢 - 这是我刚刚偶然发现的一个非常有用的解决方案。 有效!我在 Visual Studio 2017 上。我正在使用一组小型、成熟的存储过程,因此这种方法对于不需要经常更改的过程来说非常棒。谢谢,希金斯。 很棒的解决方案,它适用于我需要使用多个#TempTables 来优化查询性能的地方。今晚我可以睡个好觉了,所以谢谢你分享这个金块 AHiggins 和 MrEdmundo【参考方案6】:

当 SSSI 包从 2008 年迁移到 2016 年时,我遇到了类似的问题。最新版本使用 sp_describe_first_result_set 获取元数据,它不适用于临时表。作为一种解决方法,我在 OLEDB 源代码编辑器中使用了以下查询。我没有更改 SQL 存储过程,它仍然使用临时表。请务必使用 Parse Query and Preview 选项以确保其正常工作。见下图。

查询:

EXEC [dbo].[spGetNames]
WITH RESULT SETS((
        FirstName varchar(50), 
        LastName varchar(50)
));

【讨论】:

以上是关于SSIS 包不想获取临时表的元数据的主要内容,如果未能解决你的问题,请参考以下文章

部署 SSIS 包时 Visual Studio 2012 崩溃

SSIS包瓶颈插入记录

Java自学-JDBC 获取自增长id以及表的元数据

SSIS:无法创建OLE DB访问器。验证列元数据是否有效

如果一个表是自动增量的,你怎么能从一个 sqlite 表的元数据中得到?

获取多个日期表的 BQ 元数据