更改存储过程中选择的顺序会影响SSIS挂起问题

时间:2010-07-21 15:17:22

标签: sql sql-server ssis

我正在使用OLEDB源来调用存储过程来获取一组行,每行都标记为I UD,方法是在三个SELECT语句之间执行UNION存储过程。

A是一个填充了每晚从旧系统带来的数据的表。 B是我们希望用遗留系统数据更新的系统数据。

SET NOCOUNT ON;

-- entries in A that dont exist in B need to be inserted into B
SELECT 
    A.ID,
    B.ID,
    A.data1,
    A.data2,
    A.data3,
    A.data4,
    F1.ID as Fkey1,
    F2.ID as Fkey2,
    'I' as InsertUpdateDeactivateFlag
FROM A
LEFT JOIN B ON A.val = B.val
LEFT JOIN F1 ON A.f1val = F1.val
LEFT JOIN F2 ON A.f2val = F2.val
WHERE B.ID is null

UNION ALL

-- entries in A that do exist in B that have different field values
SELECT
    A.ID,
    B.ID,
    A.data1,
    A.data2,
    A.data3,
    A.data4,
    F1.ID as Fkey1,
    F2.ID as Fkey2,
    'U' as InsertUpdateDeactivateFlag
FROM A
INNER JOIN B ON A.val = B.val
LEFT JOIN F1 ON A.f1val = F1.val
LEFT JOIN F2 ON A.f2val = F2.val
WHERE
    A.data1 <> B.data1 OR
    A.data2 <> B.data2 OR
    A.data3 <> B.data3 OR
    A.data4 <> B.data4 OR
    F1.ID <> B.Fkey1 OR
    F2.ID <> B.Fkey2

UNION ALL

-- entries in B that dont exist in A should have Active set to 0
SELECT
    A.ID,
    B.ID,
    B.data1,
    B.data2,
    null as data3, -- dont need this value for deactivates
    null as data4, -- dont need this value for deactivates
    B.Fkey1,
    B.Fkey2,
    'D' as InsertUpdateDeactivateFlag
FROM A
RIGHT JOIN B ON A.val = B.val
WHERE A.ID is null

然后我正在使用该标志进行条件分割,以将行定向到三个OLEDB命令之一,该命令执行每行的存储过程(插入,更新或停用)。这三个程序写入表B.

如果只有几十行通过我的SSIS包,它可以正常工作。但是,当我们消灭表B并重新填充(几十万个插入)时,程序包会挂起。它只是挂起,没有错误信息,没有失败。 OLEDB源读取除了最后几行(每次大约700次,每次都是相同的数字)以外的所有行,通过流的其余部分提供行,然后挂起。我的同事说它实际上在75分钟后完成了。

存储过程在SSMS中完美运行,并且每次都会在几秒钟内返回整个结果集。除了在SSIS之外从未有任何问题。

现在奇怪的是,如果我将第三个SELECT语句(去激活)从最后一个结果集移动到union再到union的第一个结果集,那么一切正常并且包在大约3分钟内执行!咦?!

另外,如果我没有在停用时进行连接,只返回其中一个表中的所有行,它也可以正常工作。为什么SSIS会关心这次加入,或者它怎么会知道呢?我也尝试将UNION包装在外部SELECT中无济于事。

我们已经检查了SQL Server Profiler,查询正在执行,没有锁等等。据我所知,SSIS在开始将行放入管道之前已经从OLEDB源获取了所有数据。因此,写入我在SQL Server上选择的同一个表所引起的并发问题应该不是问题,因为在程序包开始处理之前已经完成了读取(如果这是错误的,请纠正我)。

当UNION处于特定顺序时,就好像SSIS正在分析存储过程。是这样的吗?有没有人遇到类似的情况?或者有人可以对这个过程有所了解,看看我应该在哪里寻找这个问题?

在实际存储过程中,SELECT项中有CASE语句,WHERE子句项上有ISNULL(),WHERE子句项和SELECT项中有其他UDF调用,以防万一。

感谢。

5 个答案:

答案 0 :(得分:1)

我遇到的几个问题是,存储过程在SSMS中正常运行并且在外部执行非常严重是由parameter sniffing引起的。

答案 1 :(得分:1)

我会尝试两件事:

(1)在制作此SQL语句的OLE DB组件的属性窗口中,将ValidateExternalMetadata设置为False(远射但尝试)。

(2)制作3个OLEDB组件源并使用SSIS Union组件。我认为SSIS希望你这样做,坦率地说,我通常使用组件而不是试图让UNION在一个OLEDB组件源中工作。

答案 2 :(得分:0)

听起来你看过我推荐的大部分内容。在这种情况下,我通常会责怪grelmins,建立一个解决方案(例如你将第三个查询作为第一个),并继续前进。

您在75分钟内检查了系统中存在哪些锁?这可能表明当SSIS试图在后续任务中“跳过”时数据是否仍在被拉动。

根据键和基数,将第三个查询更改为“不存在”形式可能更有效 - 尽管这并不能解释当前行为。 (太,右外连接让我感到紧张 - 你可以像其他人一样尝试左外连接。)

-- entries in B that dont exist in A should have Active set to 0 
SELECT 
    A.ID, 
    B.ID, 
    B.data1, 
    B.data2, 
    null as data3, -- dont need this value for deactivates 
    null as data4, -- dont need this value for deactivates 
    B.Fkey1, 
    B.Fkey2, 
    'D' as InsertUpdateDeactivateFlag 
FROM B
WHERE NOT EXISTS (SELECT 1 FROM A WHERE val = B.val)

答案 3 :(得分:0)

由于SSIS可能会在收到行时开始处理,我的猜测是无法处理其中一个停用行,因为联合中的其他一个语句已经抓取该行(或创建它)。 / p>

您是否尝试过订购UNION中的行?请记住,如果没有ORDER BY,更改语句的顺序可能会改变接收和处理行的顺序。

答案 4 :(得分:0)

你在SSIS做重要的工作吗?

难道你不能将数据并行输入SSIS中的UNION吗?我知道你有UNION ALL,但是SQL Server执行它并不是特别的。另外,为什么UNION如果再次分裂呢?

好像你可以制作三个独立的表值UDF,只需:

INSERT INTO B
SELECT *
FROM udf_INSERTS()

UPDATE B
SET whatever
FROM B
INNER JOIN udf_UPDATES() AS u
    ON u.key = B.key

DELETE
FROM B
WHERE B.key IN (SELECT key FROM udf_DELETES())

全部直接SQL。

在SSIS中调用SP进行单独插入/更新的速度不是很快。通常,我喜欢流式传输到表,然后使用SQL语句来执行set操作。

在你的情况下,SSIS正在做很多擅长的工作(枢轴,排序,聚合,查找,异构数据,脚本,验证)并不是那么清楚(你在SSIS之外工作,然后在SSIS中分裂)并且为结果行调用单个SP),所以我只是把它扔出去了。