我的C#客户端将批量数据插入SQL Server 2005数据库时遇到了一些性能瓶颈,我正在寻找加快这一过程的方法.
我已经在使用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行的块中插入数据,其中ContainerId和BinId在每个块中是常量,并且Sequence值是0-n,并且值是基于主键预排序的.
%Disk时间性能计数器花费大量时间在100%,因此很明显磁盘IO是主要问题,但我得到的速度比原始文件副本低几个数量级.
如果我:它有帮助吗?
我在插入时删除主键,稍后重新创建它
插入具有相同模式的临时表并定期将它们传输到主表中,以保持表插入发生的大小
还要别的吗?
- 根据我得到的答复,让我澄清一下:
Portman:我正在使用聚簇索引,因为当数据全部导入时,我需要按顺序依次访问数据.导入数据时,我并不特别需要索引.在执行插入时是否有任何优势来使用非聚簇PK索引而不是完全删除约束以进行导入?
Chopeen:数据是在许多其他机器上远程生成的(我的SQL服务器目前只能处理大约10个,但我希望能够添加更多).在本地计算机上运行整个过程是不切实际的,因为它必须处理50倍的输入数据才能生成输出.
Jason:我在导入过程中没有对表进行任何并发查询,我会尝试删除主键,看看是否有帮助.
以下是在SQL Server中禁用/启用索引的方法:
--Disable Index ALTER INDEX [IX_Users_UserID] SalesDB.Users DISABLE GO --Enable Index ALTER INDEX [IX_Users_UserID] SalesDB.Users REBUILD
以下是一些可帮助您找到解决方案的资源:
一些批量加载速度比较
使用SqlBulkCopy快速将数据从客户端加载到SQL Server
优化批量复制性能
绝对看看NOCHECK和TABLOCK选项:
表提示(Transact-SQL)
INSERT(Transact-SQL)
你已经在使用SqlBulkCopy,这是一个好的开始.
但是,仅使用SqlBulkCopy类并不一定意味着SQL将执行批量复制.特别是,SQL Server必须满足一些要求才能执行有效的批量插入.
进一步阅读:
批量导入中最小日志记录的先决条件
优化批量导入性能
出于好奇,为什么你的指数设置如此?好像数据筒/ BinId /序列是很多更适合成为一个非聚集索引.您是否希望将此索引集群化?
我的猜测是,如果将该索引更改为非聚集,您将看到显着的改进.这有两个选择:
将索引更改为非聚簇,并将其保留为堆表,而不包含聚簇索引
将索引更改为非聚簇,但随后添加代理键(如"id")并使其成为标识,主键和聚簇索引
任何一个都可以加快插入速度而不会明显减慢读取速度.
以这种方式考虑 - 现在,你告诉SQL做一个批量插入,但是你要求SQL在你添加任何东西的每个表中重新排序整个表.使用非聚簇索引,您将按照它们进入的顺序添加记录,然后构建一个指示其所需顺序的单独索引.