我不确定它是如何工作的所以我正在寻找合适的解决方案。我认为SSIS是正确的选择,但我之前从未使用过它
每天早上,我都会获得一个带有800K记录的制表符分隔文件。我需要将它加载到我的数据库中:
ItemID
是表格中的唯一列。不要忘记该文件包含800K记录。
ID ItemID ItemName ItemType
-- ------ -------- --------
1 2345 Apple Fruit
2 4578 Banana Fruit
我该如何解决这个问题?
答案 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
;