簡體   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