Sql server 2008 使用SSI以高性能执行操作
我正在尝试根据我的CDR表中的呼叫详细记录创建用户网络 为了让事情变得简单,让我们假设我有CDR表:Sql server 2008 使用SSI以高性能执行操作,sql-server-2008,ssis,Sql Server 2008,Ssis,我正在尝试根据我的CDR表中的呼叫详细记录创建用户网络 为了让事情变得简单,让我们假设我有CDR表: CDRid UserAId UserBId 有超过1亿条记录,所以这个表相当大 我创建了user2user表: UserAId UserBId NumberOfConnections 然后使用curos遍历表中的每一行,然后生成select语句: 如果在user2user表中有一个记录,其中包含来自CDR记录的UserAId=UserAId和来自CDR记录的UserBId=UserBId,则
CDRid
UserAId
UserBId
有超过1亿条记录,所以这个表相当大
我创建了user2user表:
UserAId
UserBId
NumberOfConnections
然后使用curos遍历表中的每一行,然后生成select语句:
如果在user2user表中有一个记录,其中包含来自CDR记录的UserAId=UserAId和来自CDR记录的UserBId=UserBId,则增加NumberOfConnections
否则,插入NumebrOfConnections=1的行
这项任务非常简单,正如我所说的那样,使用游标工作,但性能非常差(在我的计算机上估计的时间约为60小时)
我听说SQLServerIntegrationServices在我们谈论如此大的表时有更好的性能
问题是我不知道如何定制SSIS包来创建这样的任务
如果有人知道如何帮助我,有什么好的资源等,我会非常感激
也许还有其他更好的解决方案可以让它更快地工作。我使用了索引和变量表等,性能仍然很好
谢谢你的帮助
附言
这是我写的脚本,执行需要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,所以我需要检查这是哪一个用户(我只有来自的用户)
--网络,因此每次我找不到该用户时,我都会添加一个位于外部网络的用户)
这是你需要的吗
select
UserAId, UserBId, count(CDRid) as count_connections
from cdr
group by UserAId, UserBId
这是你需要的吗
select
UserAId, UserBId, count(CDRid) as count_connections
from cdr
group by UserAId, UserBId
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
(注意:我没有时间测试这段代码,你必须自己调试)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
(注意:我没有时间测试这段代码,你必须自己调试)你能把条件更新/插入分解成两个单独的语句并去掉游标吗
对所有空行执行INSERT,对所有非空行执行UPDATE。能否将条件UPDATE/INSERT分解为两个单独的语句,并去掉光标
对所有空行执行INSERT操作,对所有非空行执行更新操作。为什么要考虑对这样大小的表进行逐行处理?您知道可以使用合并语句和INSERT或UPDATE,速度会更快。或者,您可以编写更新操作,将所有需要更新的行插入到一个基于集合的语句和insert可在基于集合的语句中不存在行时插入所有行 停止使用values子句,改为使用带连接的insert。更新也是如此。如果您需要额外的复杂性,case stamenet可能会满足您的所有需要 通常情况下,不要考虑逐行处理。如果可以为光标编写select,则可以编写基于集合的语句来完成99.9%的工作
您可能仍然需要一个表如此大的游标,但它可以处理成批数据(例如,一次处理1000条记录)没有一个可以按行运行ro。为什么您甚至考虑在这样大小的表上逐行处理?您知道可以使用合并语句和插入或更新,这样会更快。或者您可以编写更新,将需要更新的所有行插入到一个基于集合的语句中,并在不存在行时插入所有行在一个基于集合的语句中 停止使用values子句,改为使用带连接的insert。更新也是如此。如果您需要额外的复杂性,case stamenet可能会满足您的所有需要 通常情况下,不要考虑逐行处理。如果可以为光标编写select,则可以编写基于集合的语句来完成99.9%的工作
您可能仍然需要一个表如此大的游标,但它可以处理成批数据(例如,一次处理1000条记录)不是一个逐行运行ro的方法。是的,但实际操作要复杂得多,我想知道如何使用ssis对每一行执行迭代并将结果插入表中。这只是一个简单的示例,但无论如何,谢谢您可以将迭代和插入保留在存储过程中,然后从ssis执行。您是否考虑使用itera使用SSI遍历行您的性能会提高吗?是的,但实际操作相当复杂,我想知道如何使用SSI遍历每行并将结果插入表中。这只是一个简单的示例,但无论如何,谢谢您可以将迭代和插入保留在存储过程中,然后从SSI执行。我们您是否认为如果使用SSI遍历行,您的性能会有所提高?问题是我只有一个AuserId成员可以调用