2008-08-23 93 views
52

我遇到了一些性能瓶颈,我的C#客户端将批量数据插入到SQL Server 2005数据库中,我正在寻找方法加快这一进程。在SQL Server中批量插入大量数据的最快方法是什么(C#客户端)

我已经在使用SqlClient.SqlBulkCopy(基于TDS)来加速跨线的数据传输,这有助于很多,但我仍然在寻找更多。

我有一个简单的表看起来像这样:

CREATE TABLE [BulkData](
[ContainerId] [int] NOT NULL, 
[BinId] [smallint] NOT NULL, 
[Sequence] [smallint] NOT NULL, 
[ItemId] [int] NOT NULL, 
[Left] [smallint] NOT NULL, 
[Top] [smallint] NOT NULL, 
[Right] [smallint] NOT NULL, 
[Bottom] [smallint] NOT NULL, 
CONSTRAINT [PKBulkData] PRIMARY KEY CLUSTERED 
(
    [ContainerIdId] ASC, 
    [BinId] ASC, 
    [Sequence] ASC 
)) 

我在平均约为300行,其中数据筒和BinId是在每个块和序列值恒定块插入数据0-n的并根据主键对值进行预先排序。

%磁盘时间性能计数器花了很多时间在100%,所以很明显磁盘IO是主要问题,但我得到的速度比原始文件副本低几个数量级。

它是否帮助任何如果我:

  1. 删除主键,而我做的插入,并重新创建后
  2. 执行插入到一个临时表具有相同的架构,并定期将其转移到主表保持插入正在发生的表的大小小
  3. 还有其他吗?

- 根据我得到的答复,让我澄清一点:

波特曼:我使用了一个聚集索引,因为当数据被所有进口我需要访问数据按顺序依次进行。在导入数据时,我并不特别需要索引。在执行插入操作时使用非聚集PK索引有什么好处,而不是完全放弃导入的约束? Chopeen:数据正在许多其他机器上远程生成(我的SQL服务器目前只能处理大约10个数据,但我希望能够添加更多数据)。在本地机器上运行整个过程是不实际的,因为它将不得不处理50倍的输入数据来生成输出。

Jason:我没有在导入过程中对表进行任何并发查询,我会尝试删除主键,看看是否有帮助。

+0

http://msdn.microsoft.com/en-us/library/ms174335.aspx – JohnB 2010-05-24 18:59:09

回答

0

是的,你的想法会有所帮助。
如果在加载时没有发生读取,则依靠选项1。
如果在处理过程中正在查询目标表,则依靠选项2。

@Andrew
问题。你以300的块插入。你插入的总量是多少? SQL服务器应该能够快速处理300个普通旧插入。

0

如果可能,增加分配给服务器的内存或服务器使用的缓冲区大小如何?

4

您是否尝试过使用事务?

从你所描述的情况来看,让服务器将100%的时间提交给磁盘,看起来你是在一个原子SQL语句中发送每行数据,从而迫使服务器向每一行提交(写入磁盘)。

如果您使用的是交易,服务器将只在交易结束时提交一次

如需进一步的帮助:您使用什么方法将数据插入服务器?使用DataAdapter更新DataTable,还是使用字符串执行每个句子?

+0

很慢半拍,但大家有没有发现现在,这是一件好事。我正在使用来自客户端应用程序的通用DbCommand代码编写插入过程,因此我无法使用SqlClient特定的东西或SQL Server批量工具 - 这个简单的提示已将我的运行时间从一分半钟减少到了5秒钟。 – Whelkaholism 2013-04-25 09:28:25

18

您已经在使用SqlBulkCopy,这是一个好的开始。

但是,仅使用SqlBulkCopy类并不一定意味着SQL将执行批量复制。特别是,SQL Server执行高效批量插入时必须满足一些要求。

延伸阅读:

出于好奇,为什么你的指标集这样呢?看起来像ContainerId/BinId/Sequence是很多更适合作为非聚集索引。是否有特定原因希望将此索引聚类?

1

我认为这听起来像这样可以使用SSIS packages完成。它们与SQL 2000的DTS包类似。我已经使用它们成功转换了纯文本CSV文件,现有SQL表格甚至是跨越多个工作表的6位行的XLS文件。您可以使用C#将数据转换为可导入的格式(CSV,XLS等),然后让SQL服务器运行预定的SSIS作业来导入数据。

创建SSIS包相当简单,内置SQL Server企业管理器工具向导(标记为“导入数据”,我认为),在向导结尾处可以选择将其保存为一个SSIS包。还有一些更多信息on Technet

3

BCP - 这是一个痛苦的设置,但它已经存在,因为数据库的曙光,它非常快。

除非您按照该顺序插入数据,否则3部分索引会真的放慢速度。稍后再应用它也会让事情变得缓慢,但这将是第二步。

Sql中的复合键总是很慢,键越慢越慢。

8

我的猜测是,如果您将该索引更改为非集群,您会看到显着的改进。这使你有两个选择:

  1. 更改索引非聚集,并把它作为一个堆表,没有聚集索引
  2. 更改索引非聚集,但然后添加一个代理键(如“ID “),并使其成为一种身份,主键,和聚簇索引

两者将加快您插入没有明显放慢您的读取。

想想这样 - 现在,你告诉SQL做一个批量插入,但是你要求SQL为每个添加任何东西的表重新排序整个表。使用非聚集索引,您将按照它们进入的顺序添加记录,然后构建一个单独的索引,指示其所需的顺序。

3

我不是一个聪明人,我没有很多SqlClient.SqlBulkCopy方法的经验,但这里是我的2美分,它是值得的。我希望它能帮助你和其他人(或者至少让人们唤起我的无知;)。

除非数据库数据文件(mdf)与事务日志文件(ldf)位于单独的物理磁盘上,否则永远不会匹配原始文件的复制速度。此外,任何聚簇索引还需要位于单独的物理磁盘上以进行更公平的比较。

您的原始副本不记录或维护用于索引目的的选择字段(列)的排序顺序。

我同意波特曼创建非集群身份种子并将现有非集群索引更改为聚集索引。至于你在客户端上使用什么构造......(数据适配器,数据集,数据表等)。如果服务器上的磁盘IO为100%,我认为您最好花时间分析客户端构造,因为它们看起来比服务器当前处理的速度快。

如果按照波特曼关于最小记录的联系,我也不会觉得周围的交易批量复制将有很大的帮助,如果任何,但我已经在我的生活是错误的许多倍;)

此次荣获”现在不一定能帮到你,但如果你弄清楚你目前的问题,这下一个评论可能会帮助解决下一个瓶颈(网络吞吐量) - 尤其是当它通过互联网...

Chopeen问了一个有趣的问题。你是如何确定使用300个记录数块来插入的? SQL Server有一个默认的数据包大小(我相信它是4096字节),这对我来说是有意义的,可以导出记录的大小,并确保您有效地使用客户端和服务器之间的数据包传输。 (请注意,您可以更改您的客户端代码上的数据包大小,而不是服务器选项,这显然会改变它的所有服务器通信 - 可能不是一个好主意。)例如,如果您的记录大小导致300个记录批次需要4500字节,您将发送2个数据包,其中第二个数据包大部分被浪费。如果批量记录计数是任意分配的,那么做一些快速简单的数学可能是有意义的。我可以告诉(并记住数据类型大小),每个记录(如果int = 4字节和smallint = 2字节)恰好有20个字节。如果你正在使用300个记录计数批次,那么你试图发送300×20 = 6000个字节(加上我猜测连接的一些开销等)。以200个记录计数批次发送(200 x 20 = 4,000 +空间用于开销)= 1个数据包可能会更高效。然后再一次,你的瓶颈似乎仍然是服务器的磁盘io。

我知道你要比较相同的硬件/配置的原始数据传输到SqlBulkCopy的,但这里的地方我会去还,如果面临的挑战是我的:

这个职位可能不会帮你了,因为这是相当古老的,但我会问下你的磁盘的RAID配置是什么和你使用的磁盘的速度?尝试将日志文件放置在数据文件上使用RAID 10(理想情况下为1)的驱动器上。这可以帮助减少大量主轴移动到磁盘上的不同扇区,并导致更多的时间读取/写入,而不是非生产性的“移动”状态。如果您已经将数据和日志文件分开,是否将索引放在与数据文件不同的物理磁盘驱动器上(只能使用聚簇索引执行此操作)。这将不仅允许同时更新带有数据插入的日志信息,而且允许索引插入(以及任何昂贵的索引页操作)同时发生。

18

这里是你如何禁用/启用在SQL Server索引:

--Disable Index ALTER INDEX [IX_Users_UserID] SalesDB.Users DISABLE 
GO 
--Enable Index ALTER INDEX [IX_Users_UserID] SalesDB.Users REBUILD

这里有一些资源,帮助你找到一个解决方案:

Some bulk loading speed comparisons

Use SqlBulkCopy to Quickly Load Data from your Client to SQL Server

Optimizing Bulk Copy Performance

绝对看看NOCHECK和TABLOCK选项:

Table Hints (Transact-SQL)

INSERT (Transact-SQL)

+0

一些很好的信息,谢谢! – tbone 2010-12-14 15:57:31

相关问题