我尝试根据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;
答案 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条记录),而不是逐行运行。