如何使用SSIS将大型平面文件加载到数据库表中?

时间:2011-05-19 15:28:19

标签: sql-server-2008 ssis

我不确定它是如何工作的所以我正在寻找合适的解决方案。我认为SSIS是正确的选择,但我之前从未使用过它

情境:

每天早上,我都会获得一个带有800K记录的制表符分隔文件。我需要将它加载到我的数据库中:

  1. 从ftp或本地
  2. 获取文件
  3. 首先,我需要从数据库中删除新文件中不存在的那个;
    • 如何比较tsql中的数据
    • 我应该从制表符分隔文件中加载数据,以便将其与文件进行比较?我应该使用临时表吗? ItemID是表格中的唯一列。
  4. 其次,我只需要将新记录插入数据库。
  5. 当然,它应该是自动化的。
  6. 应该是没有过热SQL数据库的有效方法
  7. 不要忘记该文件包含800K记录。

    示例平面文件数据:

    ID  ItemID  ItemName  ItemType
    --  ------  --------  --------
     1  2345    Apple     Fruit
     2  4578    Banana    Fruit
    

    我该如何解决这个问题?

5 个答案:

答案 0 :(得分:19)

答案 1 :(得分:2)

假设您正在使用SQL Agent(或类似的调度程序)

要求1/4)我将有一个前驱步骤处理FTP和/或文件复制步骤。如果可以避免,我不喜欢用文件操作来混乱我的包。

Reqs 2/3)在控制流级别,包设计看起来像连接到连接到另一个执行SQL任务的数据流的执行SQL任务。正如@AllenG指出的那样,通过数据流任务加载到临时表中可以获得最佳服务。第一个执行SQL任务将清除登台表中的所有行(TRUNCATE TABLE dbo.DAILY_STAGE)

近似表格设计如下所示。 MICHAEL_BORN表是您现有的表,DAILY_STAGE是您的数据流将落地的位置。

CREATE TABLE DBO.MICHAEL_BORN
(
    ID int identity(1,1) NOT NULL PRIMARY KEY CLUSTERED
,   ItemID int NOT NULL
,   ItemName varchar(20) NOT NULL
,   ItemType varchar(20) NOT NULL
)
CREATE TABLE dbo.DAILY_STAGE
(
    ItemID int NOT NULL PRIMARY KEY CLUSTERED
,   ItemName varchar(20) NOT NULL
,   ItemType varchar(20) NOT NULL
)

出于演示目的,我将通过TSQL

加载带有示例数据的上表
-- Original data
INSERT INTO
    dbo.MICHAEL_BORN
VALUES
    (2345,'Apple','Fruit')
,   (4578, 'Bannana','Fruit')


-- Daily load runs
-- Adds a new fruit (pear), corrects misspelling of banana, eliminates apple
INSERT INTO
    dbo.DAILY_STAGE
VALUES
    (7721,'Pear','Fruit')
,   (4578, 'Banana','Fruit')

执行SQL任务将利用2008+版SQL Server中提供的MERGE语句。请注意,尾部分号是MERGE声明的一部分。如果不包括它将导致“MERGE语句必须以分号(;)终止”的错误。

-- MERGE statement
-- http://technet.microsoft.com/en-us/library/bb510625.aspx
-- Given the above scenario, this script will
-- 1)  Update the matched (4578 bannana/banana) row
-- 2)  Add the new (pear) row
-- 3)  Remove the unmatched (apple) row

MERGE
    dbo.[MICHAEL_BORN] AS T
USING
(
    SELECT
        ItemID
    ,   ItemName
    ,   ItemType
    FROM
        dbo.DAILY_STAGE

) AS S
ON T.ItemID = S.ItemID
WHEN
    MATCHED THEN
    UPDATE
    SET
        T.ItemName = S.ItemName
    ,   T.ItemType = S.ItemType
WHEN
    NOT MATCHED THEN
    INSERT
    (
        ItemID
    ,   ItemName
    ,   ItemType
    )
    VALUES
    (
        ItemID
    ,   ItemName
    ,   ItemType
    )
WHEN
    NOT MATCHED BY SOURCE THEN
    DELETE
    ;

要求5)效率完全取决于您的数据以及行数的宽度,但不应该太糟糕。

-- Performance testing
-- Assumes you have a similar fast row number generator function
-- http://billfellows.blogspot.com/2009/11/fast-number-generator.html

TRUNCATE TABLE dbo.MICHAEL_BORN
TRUNCATE TABLE dbo.DAILY_STAGE

-- load initial rows
-- 20ish seconds
INSERT INTO
    dbo.MICHAEL_BORN
SELECT
    N.number AS ItemID
,   'Spam & eggs ' + CAST(N.number AS varchar(10)) AS ItemName
,   'SPAM' AS ItemType
--, CASE N.number % 2 WHEN 0 THEN N.number + 1000000 ELSE N.number END AS UpTheEvens
FROM
    dbo.GenerateNumbers(1000000) N


-- Load staging table
-- Odds get item type switched out
-- Evens get delete and new ones created
-- 20ish seconds
INSERT INTO
    dbo.DAILY_STAGE
SELECT
    CASE N.number % 2 WHEN 0 THEN N.number + 1000000 ELSE N.number END AS ItemID
,   'Spam & eggs ' + CAST(N.number AS varchar(10)) AS ItemName
,   CASE N.number % 2 WHEN 0 THEN 'SPAM' ELSE 'Not much spam' END AS ItemType
FROM
    dbo.GenerateNumbers(1000000) N


-- Run MERGE statement, 32 seconds 1.5M rows upserted
-- Probably fast enough for you

答案 2 :(得分:1)

我只是想为下一个可能通过这个问题的人提出我的想法。因此,我将针对每个场景建议我的想法 1.来自FTP或本地的Getfile     我建议您使用Drop box,Google Drive或您选择的任何其他同步云服务文件,请参阅this链接了解详细信息。
2.我建议按照建议将所有平面文件数据加载到临时表中。然后通过在临时表和唯一列(ID)上的目标表之间使用MERGE,可以轻松地比较数据。您可以看到this链接,了解如何使用合并脚本。第二&如果您使用MERGE脚本,将解决第三种情况  对于最后两个场景,我建议您使用SQL JOB自动运行程序包并在非工作时间或服务器不忙的时间安排它。请查看链接以获取有关如何使用SQL运行程序包的详细信息服务器代理工作只需在您最喜欢的搜索引擎上输入它,您就会发现大量博客显示它是如何完成的。

答案 3 :(得分:0)

SSIS听起来像是要走的路。我之前看到的处理问题类型的方式是使用临时表。将新文档加载到临时表中 - 然后对分段和生产进行比较 - 从生产中归档(不是刚刚删除)过时的记录,更新现有的行并更新某些更改(再次,原始数据存档在某处),并插入新行。

注意:您对“过时”的定义需要非常非常精确。例如:是否应将某些内容归档,因为最近的文件中不存在匹配的行?如果它出现在后续文件中,它应该保留X个时间吗?应该考虑这些问题和其他问题。

几乎所有标准的SSIS教程都应该指出如何执行每个步骤的正确途径。

答案 4 :(得分:0)

我会给Merge一个机会。确保最终在两个表上都有ItemID的索引。

Merge [dbo].[ItemInfo] as target
using
(
    SELECT stg.ItemID, stg.ItemName, stg.ItemType
    FROM [dbo].[ItemInfo_Staging] stg
    LEFT OUTER JOIN [dbo].[ItemInfo] final
        on stg.ItemId = final.ItemId
) as SOURCE
ON SOURCE.ItemID = target.ItemID

WHEN MATCHED THEN
    Update SET
        target.ItemID = SOURCE.ItemID
        , target.ItemName = SOURCE.ItemName
        , target.ItemType = SOURCE.ItemType

WHEN NOT MATCHED BY TARGET THEN
    INSERT (ItemID, ItemName, ItemType )
        VALUES (SOURCE.ItemID, SOURCE.ItemName, SOURCE.ItemType ) 

WHEN NOT MATCHED BY SOURCE THEN
    DELETE
;