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

Mic*_*orn 11 ssis sql-server-2008

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

场景:

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

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

不要忘记该文件包含800K记录.

样本平面文件数据:

ID  ItemID  ItemName  ItemType
--  ------  --------  --------
 1  2345    Apple     Fruit
 2  4578    Banana    Fruit
Run Code Online (Sandbox Code Playgroud)

我该如何处理这个问题?

小智 20

是的,SSIS可以执行您在问题中指定的要求.以下示例应该让您了解如何完成它.示例使用SQL Server作为后端.下面提供了在包上执行的一些基本测试场景.很抱歉这个冗长的答案.

分步过程:

  1. 在SQL Server数据库,即创建两个表dbo.ItemInfodbo.Staging." 脚本"部分下提供了创建表查询.这些表的结构显示在屏幕截图#1中.ItemInfo将保存实际数据,Staging表将保存登台数据以比较和更新实际记录.Id这两个表中的列都是自动生成的唯一标识列.IsProcessed表ItemInfo中的列将用于标识和删除不再有效的记录.

  2. 创建一个SSIS包并创建5个变量,如屏幕截图#2所示.我使用.txt扩展名为制表符分隔文件,因此*.txt使用变量FileExtension中的值.FilePath变量将在运行时分配值.FolderLocation变量表示文件的位置.SQLPostLoadSQLPreLoad变量表示在预加载和后加载操作期间使用的存储过程.这些存储过程的脚本在" 脚本"部分下提供.

  3. 创建指向SQL Server数据库的OLE DB连接.创建一个平面文件连接,如屏幕截图#3和#4所示."平面文件连接列"部分包含列级信息.屏幕截图#5显示了列数据预览.

  4. 配置控制流任务,如屏幕截图#6所示.配置任务Pre Load,Post LoadLoop Files如图截图#7 - #10.IsProcessed对于ItemInfo表中的所有行,Pre Load将截断staging表并将flag 设置为false.Post Load将更新更改,并将删除数据库中未在文件中找到的行.请参阅这些任务中使用的存储过程,以了解在这些Execute SQL任务中执行的操作.

  5. 双击Load Items数据流任务并按照屏幕截图#11所示进行配置.Read File是一个配置为使用平面文件连接的平面文件源.Row Count是派生列转换,其配置显示在screenshto#12中.Check Exist是查找转换,其配置显示在屏幕截图#13 - #15中.查找无匹配输出重定向到Destination Split左侧.查找匹配输出重定向到Staging Split左侧.Destination SplitStaging Split具有与屏幕截图#16中所示完全相同的配置.目标和登台表的9个不同目标的原因是为了提高程序包的性能.

  6. 所有目标任务0 - 8都配置为将数据插入表中dbo.ItemInfo,如屏幕截图#17所示.所有登台任务0 - 8都配置为插入数据dbo.Staging,如屏幕截图#18所示.

  7. 在Flat File连接管理器上,将ConnectionString属性设置为使用变量FilePath,如屏幕截图#19所示.这将使包在循环遍历文件夹中的每个文件时使用变量中设置的值.

测试场景:

Test results may vary from machine to machine. 
In this scenario, file was located locally on the machine. 
Files on network might perform slower. 
This is provided just to give you an idea. 
So, please take these results with grain of salt.
Run Code Online (Sandbox Code Playgroud)
  1. 软件包是在64位计算机上运行的,具有Xeon单核CPU 2.5GHz和3.00 GB RAM.

  2. 加载一个平面文件1 million rows.包裹执行约2分47秒.参考截图#20和#21.

  3. 使用" 测试查询"部分下提供的查询来修改数据,以模拟在第二次运行包期间更新,删除和创建新记录.

  4. 1 million rows在数据库中执行以下查询后,加载包含该文件的同一文件.包裹在约1分35秒内执行.参考屏幕截图#22和#23.请注意屏幕截图#22中重定向到目标和登台表的行数.

希望有所帮助.

测试查询: .

--These records will be deleted during next run 
--because item ids won't match with file data.
--(111111 row(s) affected)
UPDATE dbo.ItemInfo SET ItemId = 'DEL_' + ItemId WHERE Id % 9 IN (3)

--These records will be modified to their original item type of 'General'
--because that is the data present in the file.
--(222222 row(s) affected)
UPDATE dbo.ItemInfo SET ItemType = 'Testing' + ItemId WHERE Id % 9 IN (2,6)

--These records will be reloaded into the table from the file.
--(111111 row(s) affected)
DELETE FROM dbo.ItemInfo WHERE Id % 9 IN (5,9)
Run Code Online (Sandbox Code Playgroud)

平面文件连接列 .

Name        InputColumnWidth     DataType          OutputColumnWidth
----------  ----------------     ---------------   -----------------
Id          8                    string [DT_STR]   8
ItemId      11                   string [DT_STR]   11
ItemName    21                   string [DT_STR]   21
ItemType    9                    string [DT_STR]   9
Run Code Online (Sandbox Code Playgroud)

脚本:( 创建表和存储过程) .

CREATE TABLE [dbo].[ItemInfo](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ItemId] [varchar](255) NOT NULL,
    [ItemName] [varchar](255) NOT NULL,
    [ItemType] [varchar](255) NOT NULL,
    [IsProcessed] [bit] NULL,
    CONSTRAINT [PK_ItemInfo] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [UK_ItemInfo_ItemId] UNIQUE NONCLUSTERED ([ItemId] ASC)) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Staging](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ItemId] [varchar](255) NOT NULL,
    [ItemName] [varchar](255) NOT NULL,
    [ItemType] [varchar](255) NOT NULL,
 CONSTRAINT [PK_Staging] PRIMARY KEY CLUSTERED ([Id] ASC)) ON [PRIMARY]
GO

CREATE PROCEDURE [dbo].[PostLoad]
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE      ITM
    SET         ITM.ItemName    = STG.ItemName
            ,   ITM.ItemType    = STG.ItemType 
            ,   ITM.IsProcessed = 1
    FROM        dbo.ItemInfo    ITM
    INNER JOIN  dbo.Staging     STG
    ON          ITM.ItemId      = STG.ItemId;

    DELETE FROM dbo.ItemInfo
    WHERE       IsProcessed = 0;
END
GO

CREATE PROCEDURE [dbo].[PreLoad]
AS
BEGIN
    SET NOCOUNT ON;

    TRUNCATE TABLE dbo.Staging;     

    UPDATE  dbo.ItemInfo 
    SET     IsProcessed = 0;
END
GO
Run Code Online (Sandbox Code Playgroud)

截图#1:

1

截图#2:

2

截图#3:

3

截图#4:

4

截图#5:

五

截图#6:

6

截图#7:

7

截图#8:

8

截图#9:

9

截图#10:

10

截图#11:

11

截图#12:

12

截图#13:

13

截图#14:

14

截图#15:

15

截图#16:

16

截图#17:

17

截图#18:

18

截图#19:

19

截图#20:

20

屏幕截图#21:

21

截图#22:

22

屏幕截图#23:

23

  • 这个答案几乎说明了我看到的所有其他SSIS答案的耻辱.做得好. (2认同)

All*_*enG 0

SSIS 听起来是个不错的选择。我之前看到处理您的问题类型的方式是使用暂存表。新文档加载到暂存表中 - 然后比较暂存和生产 - 过时的记录从生产中存档(不仅仅是删除),更新具有某些更改的现有行(同样,原始数据存档在某处),并插入新行。

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

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