在写入SQL Server(顺便提一下,我用的是2008 Express版本)之前,我的代码很少进行处理。
通常,我使用SqlHelper类的ExecuteNonQuery方法,并传递存储过程名称和存储过程所需的参数列表。
这非常方便,但我需要更快的方法来完成这个任务。
谢谢。
使用INSERT语句或存储过程的ExecuteNonQuery方法可以让您在Express上实现每秒数千个插入。4000-5000 / 秒非常容易实现,我可以证明这一点。
通常会减慢单个更新的是日志刷新的等待时间,您需要考虑这一点。最简单的解决方案是批量提交。例如,每1000个插入或每秒提交一次。这将填充日志页面,并将日志刷新等待的成本分摊到事务中的所有插入操作中。
使用批处理提交,你可能会出现磁盘日志写入性能瓶颈,而无法做任何事情除了更换硬件(对日志进行raid 0条带化)。
如果您遇到早期的瓶颈(不太可能),那么您可以尝试批处理语句,即发送一个具有多个插入操作的单个T-SQL批处理。但这很少有回报。
当然,您需要将写入的大小减少到最小,也就是说,将表的宽度减少到最小所需列,消除非聚集索引,消除不必要的约束条件。如果可能,请使用堆而不是聚集索引,因为堆插入要比聚集索引快得多。
使用普通的INSERT语句和ExecuteNoQuery方法进行批处理提交,几乎不需要使用快速插入接口(例如SqlBulkCopy)。因为批处理提交会比部署批量插入更快地耗尽驱动器的顺序写入吞吐量。对于快速连接到SAN的机器,需要使用批量插入。您提到了Express,所以可能不需要这样做。人们普遍认为相反是正确的,但这只是因为他们没有意识到批量插入给他们带来了批量提交,而不是批量插入加速了操作。
与任何性能测试一样,请确保消除随机性,并预分配数据库和日志,您不希望在测试测量或生产期间出现数据库或日志增长事件,那太业余了。
以下是使用表变量插入大量记录的好方法...
但最好每次限制到1000条记录,因为表变量在内存中。
在这个例子中,我将向一个包含3个字段的表中插入2条记录 - CustID,Firstname,Lastname。
--first create an In-Memory table variable with same structure
--you could also use a temporary table, but it would be slower
declare @MyTblVar table (CustID int, FName nvarchar(50), LName nvarchar(50))
insert into @MyTblVar values (100,'Joe','Bloggs')
insert into @MyTblVar values (101,'Mary','Smith')
Insert into MyCustomerTable
Select * from @MyTblVar
通常情况下,这是通过BULK INSERT完成的。简单来说,您需要准备一个文件,然后发出BULK INSERT
语句,SQL Server会以最快的方式将文件中的所有数据复制到表中。
它确实有一些限制(例如,如果您可能存在要更新的行,则无法执行“更新或插入”类型的行为),但是如果您能够克服这些限制,那么您不太可能找到任何更快的方法。
SqlBulkCopy
。可能会影响插入速度的因素包括索引以及对同一表进行的读取或更新(锁定)。您可以通过避免这些因素,并将单独的事务插入到一个没有索引或其他活动的临时表中,从而加快类似情况的速度。然后稍微不那么频繁地将临时表批量导入到主表中。
它只能以您的SP运行速度为准确参考。确保表格被正确索引,如果您有一个聚集索引,请确保它具有窄、唯一、递增的键。确保其余索引和约束(如果有)没有太多的开销。
在ADO.NET层中不应该看到太多的开销(我不会使用任何其他.NET库来代替SQLCommand)。您可以尝试使用ADO.NET Async方法,以便在不阻塞应用程序中的单个线程的情况下排队执行多个对存储过程的调用(这可能比任何其他方法都能释放更多吞吐量,就像有多个机器插入数据库一样)。
除此之外,您确实需要告诉我们更多关于您的需求。