更好的大数据集导入性能

时间:2011-08-25 16:02:45

标签: sql sql-server sql-server-2008

我有一些从文本文件中插入大数据集的作业。数据通过.NET的SqlBulkCopy加载。

目前,我将所有数据加载到临时表中,然后将其插入到生产表中。这比直接进口到生产中有所改进。 T-SQL插入结果查询速度要快得多。数据仅通过此方法加载,没有其他插入或删除。

然而,由于工作正在执行时的锁定,我又回到了超时状态。该工作包括以下步骤:

  1. 将数据加载到临时表
  2. 启动交易
  3. 删除当前和未来的日期行
  4. 从临时表中插入
  5. 提交
  6. 这种情况每小时发生一次。这部分需要70秒。我需要尽可能少的数量。

    生产表有大约2000万条记录,每条导入大约70K行。该表不在晚上访问,因此我利用这段时间进行所有必需的维护(重建统计数据,索引等)。在70K中,补充说,每天保持~4K - 也就是说,桌子每天增加4k。

    我在考虑一个2部分解决方案:

    该作业将变为复制/重命名作业。我将所有当前数据插入临时表,创建统计数据&索引,重命名表,删除旧表。

    创建历史记录表以分解旧数据。 “当前”表格将有6个月的滚动数据,大约990K记录。这将使删除/插入表更小,并且[希望]更高效。我宁愿不这样做;桌子设计精良,索引完美;查询很快。但最终可能需要它。

    编辑:使用Windows 2003,SQL Server 2008

    思考?其他建议?

6 个答案:

答案 0 :(得分:0)

答案应该是从这个表中读取的查询应该是READ UNCOMMITTED,因为您的数据加载是唯一更改数据的地方。使用READ UNCOMMITTED,SELECT查询将不会获得锁定。

http://msdn.microsoft.com/en-us/library/ms173763.aspx

答案 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)

你的解决方案对我来说似乎很合理。尝试的另一种方法是在临时表中创建最终数据,所有数据都在事务之外,然后在事务内部截断目标表,然后从临时表中加载...沿着这些行的某些东西也可能值得尝试。