使用ssis执行高性能操作

时间:2010-11-02 19:13:11

标签: sql-server-2008 ssis

我尝试根据CDR表中的呼叫详细记录创建用户网络。

为了简单起见,我可以说我有CDR表:

CDRid
UserAId
UserBId

有超过100万条记录,因此表格非常大。

我使用了user2user表:

UserAId
UserBId
NumberOfConnections

然后使用curos迭代遍历表中的每一行,然后我创建select语句:

如果在user2user表中有记录,其中CDR记录中的UserAId = UserAId,CDR记录中的UserBId = UserBId,则增加NumberOfConnections。

否则插入NumebrOfConnections = 1的行。

非常简单的任务,它就像我说使用光标一样,但性能非常糟糕(估计我的电脑时间约为60小时)。

我听说过Sql Server Integration Services,当我们谈论这样的大表时,它已经有了更好的性能。

问题是我不知道如何自定义SSIS包来创建这样的任务。

如果有人知道如何帮助我,任何好的资源等我都会非常感激。

也许有任何其他好的解决方案可以让它更快地运作。我使用索引和变量表等等,性能仍然是纯粹的。

感谢您的帮助,

P.S。

这是我编写的脚本,执行此操作需要40到50小时。

DECLARE CDR_cursor CURSOR FOR 
SELECT CDRId, SubscriberAId, BNumber 
FROM dbo.CDR

OPEN CDR_cursor;

FETCH NEXT FROM CDR_cursor 
INTO @CdrId, @SubscriberAId, @BNumber;

WHILE @@FETCH_STATUS = 0

BEGIN

- 在这里我检查是否有这个号码的用户(因为CDR我只有SubscriberAId - 和BNumber所以我需要检查哪个用户是这个(我只有来自的用户) - 网络,以便每次我找不到这个用户我添加一个是outide网络

SELECT @UserBId = (Select UserID from dbo.Number where Number = @BNumber)
    IF (@UserBId is NULL)
    BEGIN
        INSERT INTO dbo.[User] (ID, Marked, InNetwork)
        VALUES (@OutUserId, 0, 0);

        INSERT into dbo.[Number](Number, UserId) values (@BNumber, @OutUserId);
        INSERT INTO dbo.User2User

        VALUES (@SubscriberAId, @OutUserId, 1)
        SET @OutUserId = @OutUserId - 1;
    END

    else

    BEGIN
        UPDATE dbo.User2User
        SET NumberOfConnections = NumberOfConnections + 1
        WHERE User1ID = @SubscriberAId AND User2ID = @UserBId
        -- Insert the row if the UPDATE statement failed.   
        if(@@ROWCOUNT = 0)
        BEGIN
            INSERT INTO dbo.User2User
            VALUES (@SubscriberAId, @UserBId, 1)
        END 
    END

    SET @Counter = @Counter + 1;

    if((@Counter % 100000) = 0)
    BEGIN
        PRINT Cast (@Counter as NVarchar(12));
    END
    FETCH NEXT FROM CDR_cursor 
    INTO @CdrId, @SubscriberAId, @BNumber;
END

CLOSE CDR_cursor;
DEALLOCATE CDR_cursor;

4 个答案:

答案 0 :(得分:1)

这就是你需要的吗?

select 
UserAId, UserBId, count(CDRid) as count_connections
from cdr
group by UserAId, UserBId

答案 1 :(得分:1)

关于SSIS的事情是它可能不会比光标快得多。它几乎做同样的事情:按记录读取表记录,处理记录然后转移到下一个记录。 SSIS中有一些先进的技术,比如分割数据输入,如果你有重型硬件会有所帮助,但没有它会很慢。

更好的解决方案是编写一个INSERT和一个UPDATE语句,它将为您提供所需的内容。有了这个,您将能够更好地利用数据库中的索引。它们看起来像是:

WITH SummaryCDR AS (UserAId, UserBId, Conns) AS
(
SELECT UserAId, UserBId, COUNT(1) FROM CDR
GROUP BY UserAId, UserBId)    
UPDATE user2user
SET NumberOfConnections = NumberOfConnections + SummaryCDR.Conns
FROM SummaryCDR
WHERE SummaryCDR.UserAId = user2user.UserAId
AND SummaryCDR.UserBId = user2user.UserBId

INSERT INTO user2user (UserAId, UserBId, NumberOfConnections)
SELECT CDR.UserAId, CDR.UserBId, Count(1)
FROM CDR
LEFT OUTER JOIN user2user
ON user2user.UserAId = CDR.UserAId
AND user2user.UserBId = CDR.UserBId
WHERE user2user.UserAId IS NULL

GROUP BY CDR.UserAId, CDR.UserBId

(注意:我没有时间测试这段代码,你必须自己调试)

答案 2 :(得分:1)

你能否将条件更新/插入分成两个单独的语句并摆脱游标?

对所有NULL行执行INSERT,对所有NOT NULL行执行UPDATE。

答案 3 :(得分:1)

为什么你甚至考虑在一个大小的表上进行逐行处理?您知道可以使用合并语句并插入或更新,它会更快。或者,您可以编写更新以在一个基于集合的语句中插入需要更新的所有行,并在一个基于集合的语句中不存在行时插入插入alll行。

停止使用values子句并使用带有连接的插入。更新也是如此。如果您需要额外的复杂性,案例stamenet可能会为您提供所需的一切。

一般来说,不要再考虑逐行处理了。如果你可以为光标编写一个select,你可以编写一个基于集合的语句,以便在99.9%的时间内完成工作。

您可能仍然希望光标的表格大而一个用于处理批量数据(例如,一次处理1000条记录),而不是逐行运行。