0

我们在 SQL Server 2008R2-SP1 中运行导入存储过程,一次将数千行加载到多个表中。我们在尺寸tempDBtransaction log尺寸方面存在问题。

像这样的东西:

CREATE PROCEDURE spReallyHugeImportDataProcedure
    @id int
AS
BEGIN
    CREATE TABLE #temp(...)

    INSERT INTO #temp
    SELECT *
    FROM AlotOfJoins

    INSERT INTO FinalTable
    SELECT * FROM AlotOfJoins

    DROP #tempTable

    INSERT INTO #temp
    SELECT *
    FROM AlotOfJoins

    INSERT INTO FinalTable
    SELECT * FROM AlotOfJoins

    DROP #tempTable

    INSERT INTO #temp
    SELECT *
    FROM AlotOfJoins

    INSERT INTO FinalTable
    SELECT * FROM AlotOfJoins

    DROP #tempTable

    -- And so on....

END

我们正在尝试拆分整个过程并针对一小组数据运行多次。

像这样:

CREATE PROCEDURE spReallyHugeImportDataProcedure
   @id int
AS
BEGIN

    DECLARE @SomeSortOfCounter int = 100
    WHILE(@SomeSortOfCounter <> 0)
    BEGIN
        -- TRY TO START A NEW TRANSACTION
        BEGIN TRAN

        CREATE TABLE #temp(...)

        INSERT INTO #temp
        SELECT *
        FROM AlotOfJoins
        WHERE SomeFileterWorkinWithTheCounter = @SomeSortOfCounter

        INSERT INTO FinalTable
        SELECT * FROM AlotOfJoins

        DROP #tempTable

        INSERT INTO #temp
        SELECT *
        FROM AlotOfJoins
        WHERE SomeFileterWorkinWithTheCounter = @SomeSortOfCounter

        INSERT INTO FinalTable
        SELECT * FROM AlotOfJoins

        DROP #tempTable

        INSERT INTO #temp
        SELECT *
        FROM AlotOfJoins
        WHERE SomeFileterWorkinWithTheCounter = @SomeSortOfCounter

        INSERT INTO FinalTable
        SELECT * FROM AlotOfJoins

        DROP #tempTable

        -- And so on....

        -- TRY TO RELASE TEMP OBJECTS, 
        -- OR GIVE TO THE SERVER THE OPORTUNITY TO DO IT
        COMMIT

        SET @SomeSortOfCounter = @SomeSortOfCounter - 1
    END
END

SQL Server 引擎是否可以在这些内部事务之间工作?

4

2 回答 2

1

选项 1:使用用户数据库中的表

如果您确实需要将数据存储在临时表中,请在用户数据库(例如 ImportTemp 或目标 DB)中构建该表,然后使用它而不是 tempdb。在这种情况下,SQL Server 不应在 TempDB 中使用太多空间,并且您的数据将被永久存储 -> 您可以重复使用它,并且可以将加载程序查询拆分为多个批次。

或者,您可以将此表移动到不同的文件组,以防止并发写入并降低干扰其他进程的机会。

在这种情况下,步骤是:

  1. 如果存在,则删除“临时”
  2. 创建“临时”(在用户数据库中)
  3. 用必要的数据填充“临时”表
  4. 从持久的“临时”表中加载目标表
  5. 删除“临时”表以释放数据文件中的空间
  6. 可选择收缩与“临时”表相关的数据和日志文件

如果您相对频繁地使用此导入表,则只能在使用前后截断它,而不是删除并重新创建它。

选项 2:使用 ETL 工具

使用可以批量/缓冲区处理数据的 ETL 工具。如果您使用的是 SQL Server Standard 或更高版本,则可以选择使用SSIS (SQL Server Integration Services)

DBCC 收缩文件

DBCC SHRINKFILE您可以使用以下命令从数据和日志文件中释放未使用的空间 :

USE [YourDatabase]

DBCC SHRINKFILE 
(
    { file_name | file_id } 
    { [ , EMPTYFILE ] 
    | [ [ , target_size ] [ , { NOTRUNCATE | TRUNCATEONLY } ] ]
    }
)
[ WITH NO_INFOMSGS ]

例子

USE [tempdb]
DBCC SHRINKFILE (tempdb_data, TRUNCATEONLY)

可选

您可以通过将其他数据文件添加到 TempDB 来跨驱动器传播 TempDB 文件:

ALTER DATABASE tempdb
    ADD FILE (NAME = tempdev2, FILENAME = 'W:\tempdb2.mdf', SIZE = 256);

一个相关问题:如何将 tempdb 分布在多个文件上?

于 2014-11-07T11:47:14.513 回答
0

简单的答案是肯定的,只要存储过程之外没有外部事务。此外,没有理由添加显式事务。简单地创建一个循环并且只处理每个语句的一大块记录将使您的 tlog 空间得到重用,并且您不会一次将所有记录强制到临时表中。

于 2014-11-08T05:17:13.457 回答