繁体   English   中英

将表传递给存储过程

[英]Passing a table to a stored procedure

我有一个有200亿行的表。 该表没有任何索引,因为它是为进行批量插入操作而动态创建的。 该表正在存储过程中使用,该存储过程执行以下操作

Delete A
from master a 
inner join (Select distinct Col from TableB ) b
on A.Col = B.Col

Insert into master 
Select *
from tableB
group by col1,col2,col3

TableB是具有200亿行的表。 我不想直接执行SP,因为完成执行可能需要几天的时间。 Master也是一个巨大的表,并且在Col上具有聚集索引

  1. 我可以将几行行传递给存储过程并执行操作吗?这可能会减少日志文件的增长。 如果可以,我该怎么做
  2. 我是否应该在表上创建聚簇索引并执行SP,这可能会快一点,但我又想在一个巨大的表上创建CI可能需要10个小时才能完成。

还是有什么方法可以快速执行此操作

我使用了与方法类似的方法。 如果可以的话,建议您将数据库置于批量记录恢复模式,而不是完全恢复模式。

下面复制了博客条目,以供将来证明。

下面是一种用于将大量记录从一个表转移到另一个表的技术。 由于几个原因,这可以很好地扩展。 首先,这不会在提交事务之前填满整个日志。 相反,它将以10,000条记录的块填充表。 其次,通常要快得多。 您将不得不处理批量大小。 有时,根据系统的不同,效率更高,为10,000,有时为500,000。

如果您不需要插入现有表中而只需要该表的副本,则最好执行SELECT INTO 但是,对于本示例,我们将插入现有表中。

您应该做的另一个技巧是将数据库的恢复模型更改为简单。 这样,将减少事务日志中的日志记录。

下面的WITH (TABLOCK)仅在SQL 2008中有效。

 DECLARE @BatchSize INT = 10000 WHILE 1 = 1 BEGIN INSERT INTO [dbo].[Destination] --WITH (TABLOCK) -- Uncomment for 2008 ( FirstName ,LastName ,EmailAddress ,PhoneNumber ) SELECT TOP(@BatchSize) s.FirstName ,s.LastName ,s.EmailAddress ,s.PhoneNumber FROM [dbo].[SOURCE] s WHERE NOT EXISTS ( SELECT 1 FROM dbo.Destination WHERE PersonID = s.PersonID ) IF @@ROWCOUNT < @BatchSize BREAK END 

对于上面的示例,在两个表中的PersonID上至少具有非聚集索引很重要。

传输记录的另一种方法是使用多个线程。 指定这样的记录范围:

 INSERT INTO [dbo].[Destination] ( FirstName ,LastName ,EmailAddress ,PhoneNumber ) SELECT TOP(@BatchSize) s.FirstName ,s.LastName ,s.EmailAddress ,s.PhoneNumber FROM [dbo].[SOURCE] s WHERE PersonID BETWEEN 1 AND 5000 GO INSERT INTO [dbo].[Destination] ( FirstName ,LastName ,EmailAddress ,PhoneNumber ) SELECT TOP(@BatchSize) s.FirstName ,s.LastName ,s.EmailAddress ,s.PhoneNumber FROM [dbo].[SOURCE] s WHERE PersonID BETWEEN 5001 AND 10000 

为了获得超快的性能,我建议使用SSIS。 尤其是在SQL Server 2008中。我们最近在5分钟内传输了1700万条记录,并且在同一台服务器上执行的SSIS包与在其之间传输的两个数据库一起执行。

SQL Server 2008 SQL Server 2008在插入记录时对其日志记录机制进行了更改。 以前,要进行最少记录的插入,必须执行SELECT.. INTO 现在,如果您可以锁定要插入的表,则可以执行最少记录的插入。 下面的示例显示了一个示例。 此规则的例外情况是,如果表上有聚集索引并且表不为空。 如果表为空,并且您获得了表锁,并且具有聚集索引,那么它将被最小化记录。 但是,如果表中有数据,则将记录插入。 现在,如果堆上具有非聚集索引并且获得了表锁,则将仅记录非聚集索引。 最好在插入记录之前删除索引。

要确定日志记录的数量,可以使用以下语句

  SELECT * FROM ::fn_dblog(NULL, NULL) 

以上内容归功于SQL Server Planet的Derek Dieter。

如果在将表传递到存储过程时一无所获,则可以在SQL Server 2008中将表值参数传递给存储过程 建议使用其他一些方法(例如分区)可能会更好。 在具有200亿行的表上选择“不重复”可能是问题的一部分。 我想知道一些非常基本的调整是否也无济于事:

Delete A
from master a 
where exists (select 1 from TableB b where b.Col = a.Col)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM