将表传递给存储过程

时间:2014-04-17 17:20:49

标签: sql sql-server

我有一张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个小时才能完成。
  3. 或者有没有办法快速执行此操作

2 个答案:

答案 0 :(得分:2)

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

博客条目转载如下以供将来证明。

  

以下是用于传输大量记录的技术   一张桌到另一张桌子。由于几个原因,这很好地扩展。   首先,这不会在提交之前填满整个日志   交易。相反,它将以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中。我们最近转移了1700万   在同一台服务器上执行SSIS包的5分钟内记录   作为它之间转移的两个数据库。

     

SQL Server 2008 SQL Server 2008已对其进行了更改   插入记录时的记录机制。以前,要做插入   记录最少,您必须执行SELECT.. INTO。   现在,如果可以锁定,则可以执行最少记录的插入   你插入的桌子。以下示例显示了一个示例   这个。此规则的例外情况是,如果您有聚簇索引   表和表不是空的。如果表是空的而你   获取一个表锁,你有一个聚集索引,它将是   记录最少。但是,如果表中有数据,则插入   将被记录。现在,如果堆上有非聚集索引,那么   你获得一个表锁,那么只有非聚集索引   登录。在插入之前删除索引总是更好   记录。

     

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

 SELECT * FROM ::fn_dblog(NULL, NULL)

上面的信用归功于SQL Server Planet的Derek Dieter。

答案 1 :(得分:1)

如果您在将表格传递到存储过程时设置为you can pass a table-valued parameter to a stored procedure in SQL Server 2008。你可能会对建议的其他一些方法有更好的运气,比如分区。在具有200亿行的表上选择distinct可能是问题的一部分。我想知道一些非常基本的调整是否也不会有所帮助:

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