我有一些从文本文件中插入大数据集的作业。数据通过.NET的SqlBulkCopy加载。
目前,我将所有数据加载到临时表中,然后将其插入到生产表中。这比直接进口到生产中有所改进。 T-SQL插入结果查询速度要快得多。数据仅通过此方法加载,没有其他插入或删除。
然而,由于工作正在执行时的锁定,我又回到了超时状态。该工作包括以下步骤:
这种情况每小时发生一次。这部分需要70秒。我需要尽可能少的数量。
生产表有大约2000万条记录,每条导入大约70K行。该表不在晚上访问,因此我利用这段时间进行所有必需的维护(重建统计数据,索引等)。在70K中,补充说,每天保持~4K - 也就是说,桌子每天增加4k。
我在考虑一个2部分解决方案:
该作业将变为复制/重命名作业。我将所有当前数据插入临时表,创建统计数据&索引,重命名表,删除旧表。
创建历史记录表以分解旧数据。 “当前”表格将有6个月的滚动数据,大约990K记录。这将使删除/插入表更小,并且[希望]更高效。我宁愿不这样做;桌子设计精良,索引完美;查询很快。但最终可能需要它。
编辑:使用Windows 2003,SQL Server 2008
思考?其他建议?
答案 0 :(得分:0)
答案应该是从这个表中读取的查询应该是READ UNCOMMITTED,因为您的数据加载是唯一更改数据的地方。使用READ UNCOMMITTED,SELECT查询将不会获得锁定。
答案 1 :(得分:0)
一个非常偷偷摸摸的方法是将当前表重命名为TableA,并设置第二个表,其结构与TableB相同,并且数据相同。然后在TableA中设置一个具有相同名称和确切字段的视图。现在,您现有的所有代码都将使用视图而不是当前表。该视图从TableA开始。
在加载过程中,加载到TableB。刷新视图定义更改它以查看TableB。您的用户停机时间不到一秒钟。然后将相同的数据加载到TableA并存储应该从数据库表中的某个位置开始的表。下次首先加载到TableA,然后将视图更改为指向TableA,然后重新加载TableB。
答案 2 :(得分:0)
您应该考虑使用分区表。基本思想是您可以将所有新数据加载到新表中,然后将该表作为新分区加入原始表中。这比插入当前现有表格快几个数量级。
稍后,您可以将多个分区合并为一个更大的分区。
此处提供更多信息:http://msdn.microsoft.com/en-us/library/ms191160.aspx
答案 3 :(得分:0)
您可以使用的另一个技巧是为更新提供增量表。你有2个表可以查看它们以合并它们。一个表TableBig将保存旧数据,第二个表TableDelta将保存您添加到tableBig中的行的增量。
您可以在其上创建一个添加它们的视图。一个简单的例子:
例如,TableBig中的旧数据(20M行,批次的索引等)
ID Col1 Col2
123 5 10
124 6 20
并且您想要更新1行并添加一行,以便之后表格如下所示:
ID Col1 Col2
123 5 10 -- unchanged
124 8 30 -- this row is updated
125 9 60 -- this one added
然后在TableDelta中插入这两行:
ID Col1 Col2
124 2 10 -- these will be added to give the right number
125 9 60 -- this row is new
并且视图是
select ID,
sum(col1) col1, -- the old value and delta added to give the correct value
sum(col2) col2
from (
select id, col1, col2 from TableBig
union all
select id, col1, col2 from TableDelta
)
group by ID
晚上你可以将TableDelta合并到TableBig和索引等中。
通过这种方式,您可以在白天完全独自放置大表,而TableDelta将没有很多行,因此整体查询性能非常好。从BigTable中获取数据可以从不受欢迎中获益,从DeltaTable获取行是没有问题的,因为它很小,与在磁盘上查找数据相比,总结起来很便宜。将数据泵入TableDelta非常便宜,因为您可以在最后插入。
关心Gert-Jan
更新文字列:
你可以尝试使用两个表来进行相似的操作,但不要添加,而是替换。就像这样:
Select isnull(b.ID, o.ID) Id,
isnull(b.Col1, o.Col1) Col1
isnull(b.Col2, o.Col2) col2
From TableBig b
full join TableOverWrite o on b.ID = o.ID
基本思路是一样的:一个带索引的大表和一个不需要它们的更新小表。
答案 4 :(得分:0)
获得更好的硬件。使用3个线程,35.000个项目批次,我使用这种方法每秒导入大约90.000个项目。
抱歉,但是硬件决定插入速度。重要:日志的SSD,镜像;)
答案 5 :(得分:0)
你的解决方案对我来说似乎很合理。尝试的另一种方法是在临时表中创建最终数据,所有数据都在事务之外,然后在事务内部截断目标表,然后从临时表中加载...沿着这些行的某些东西也可能值得尝试。